Repository: TBD54566975/ssi-service
Pull request #570 (2023-06-29 21:52:07)

Ability to provide public keys when creating an ION did
# Overview
Upon creation of an ion did, clients can now provide a public key to associate with the did, for which they own the private keys.

# Description
Some quality of life improvements were algo included in this PR. A follow up will change the API surface so that it's clear what `issuerKID` means and we avoid confusion. 

Separately, instead of constructing the did doc, we're taking the one returned from the ION node. 

# How Has This Been Tested?
Integration and unit


codecov-commenter: ## [Codecov](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) Report
> Merging [#570](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (b356770) into [main](https://app.codecov.io/gh/TBD54566975/ssi-service/commit/a8ec4a990c36e71fe83fb2076d54909f9af3d640?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (a8ec4a9) will **decrease** coverage by `0.13%`.
> The diff coverage is `30.00%`.

```diff
@@            Coverage Diff             @@
##             main     #570      +/-   ##
==========================================
- Coverage   23.95%   23.83%   -0.13%     
==========================================
  Files          46       46              
  Lines        5305     5286      -19     
==========================================
- Hits         1271     1260      -11     
+ Misses       3800     3794       -6     
+ Partials      234      232       -2     
```


| [Impacted Files](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) | Coverage Δ | |
|---|---|---|
| [pkg/server/router/credential.go](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvY3JlZGVudGlhbC5nbw==) | `2.91% <0.00%> (-0.02%)` | :arrow_down: |
| [pkg/server/router/manifest.go](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvbWFuaWZlc3QuZ28=) | `7.78% <0.00%> (-0.03%)` | :arrow_down: |
| [pkg/service/did/ion.go](https://app.codecov.io/gh/TBD54566975/ssi-service/pull/570?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZpY2UvZGlkL2lvbi5nbw==) | `62.98% <90.00%> (+1.10%)` | :arrow_up: |



Patch:
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..0484436
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,11 @@
+bin
+build
+log/*.log
+sips
+
+bolt.db
+coverage.out
+**/*.md
+**/*_test.go
+**/*.png
+
diff --git a/go.mod b/go.mod
index 7ee055e..e0be9ee 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.20
 
 require (
 	github.com/BurntSushi/toml v1.3.2
-	github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230623174120-9617360e9ee2
+	github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230629211408-d0031cf86600
 	github.com/alicebob/miniredis/v2 v2.30.3
 	github.com/ardanlabs/conf v1.5.0
 	github.com/benbjohnson/clock v1.3.5
diff --git a/go.sum b/go.sum
index 9ae8f25..e36c757 100644
--- a/go.sum
+++ b/go.sum
@@ -46,8 +46,13 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
-github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230623174120-9617360e9ee2 h1:cJLc4zt1GpOXxQ5hzP+Z0j7GXSx/xyq7DW0jjapzSbE=
-github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230623174120-9617360e9ee2/go.mod h1:yPkVO9MCC/kRu+lut3jllhnCV0gEqSubaaSVT7xLSOs=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230628200007-83e6a4e298b9 h1:4R5PytL9g0GrnuEQF/2ZhtdhJw2OtlGG9bsXYibJrUg=
+github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230628200007-83e6a4e298b9/go.mod h1:yPkVO9MCC/kRu+lut3jllhnCV0gEqSubaaSVT7xLSOs=
+github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230629211408-d0031cf86600 h1:POzVbjLxtQYQGVGaU95uQtUvhf3djJsAAWrADV6Ou4Y=
+github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230629211408-d0031cf86600/go.mod h1:yPkVO9MCC/kRu+lut3jllhnCV0gEqSubaaSVT7xLSOs=
 github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
 github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
 github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
@@ -58,6 +63,7 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h
 github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
 github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
 github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
 github.com/aws/aws-sdk-go v1.44.277 h1:YHmyzBPARTJ7LLYV1fxbfEbQOaUh3kh52hb7nBvX3BQ=
@@ -78,6 +84,7 @@ github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pY
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
 github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
 github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
 github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
 github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -119,6 +126,7 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
@@ -132,6 +140,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
+github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
 github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
@@ -185,6 +194,7 @@ github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QX
 github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
 github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
@@ -271,6 +281,7 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gowebpki/jcs v1.0.0 h1:0pZtOgGetfH/L7yXb4KWcJqIyZNA43WXFyMd7ftZACw=
 github.com/gowebpki/jcs v1.0.0/go.mod h1:CID1cNZ+sHp1CCpAR8mPf6QRtagFBgPJE0FCUQ6+BrI=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
@@ -299,6 +310,9 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
 github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
@@ -314,6 +328,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 h1:kMJlf8z8wUcpyI+FQJIdGjAhfTww1y0AbQEv86bpVQI=
 github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69/go.mod h1:tlkavyke+Ac7h8R3gZIjI5LKBcvMlSWnXNMgT3vZXo8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -349,6 +364,7 @@ github.com/lestrrat-go/jwx/v2 v2.0.11/go.mod h1:ZtPtMFlrfDrH2Y0iwfa3dRFn8VzwBrB+
 github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
 github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
+github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs=
 github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
 github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
@@ -358,14 +374,17 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg=
 github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ=
+github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
 github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
 github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -375,6 +394,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
 github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
 github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
 github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
@@ -392,6 +413,7 @@ github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOEL
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM=
 github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjGmesFh1D0rDy+q1Twx6FyU7VWHi8wZbI=
 github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4=
@@ -403,8 +425,10 @@ github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTs
 github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
 github.com/ory/ristretto v0.1.1-0.20211108053508-297c39e6640f h1:P3stZofIZ2D+tjaPCrwLAPd2FJa1wmmyMI7phSbZU98=
 github.com/ory/ristretto v0.1.1-0.20211108053508-297c39e6640f/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
+github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
 github.com/ory/x v0.0.558 h1:/UQssZxyuqlB+QgsujyPwO7hv5da7EhNCA3w2AcWk1Y=
 github.com/ory/x v0.0.558/go.mod h1:6w1jt+TaPX2uY8vBGMuo5GZhx8PqwI7GBA+MRzyYTYE=
+github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
 github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
 github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
@@ -437,8 +461,11 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 h1:uIkTLo0AGRc8l7h5l9r+GcYi9qfVP
 github.com/santhosh-tekuri/jsonschema/v5 v5.3.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
 github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
 github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
+github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
@@ -453,6 +480,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
 github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
+github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU=
 github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
 github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -486,6 +514,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6
 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
 github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
+github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
diff --git a/pkg/server/router/credential.go b/pkg/server/router/credential.go
index 68141b8..dd851a5 100644
--- a/pkg/server/router/credential.go
+++ b/pkg/server/router/credential.go
@@ -5,6 +5,7 @@ import (
 	"net/http"
 
 	credsdk "github.com/TBD54566975/ssi-sdk/credential"
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/gin-gonic/gin"
 	"github.com/pkg/errors"
 	credmodel "github.com/tbd54566975/ssi-service/internal/credential"
@@ -131,17 +132,18 @@ type CreateCredentialRequest struct {
 }
 
 func (c CreateCredentialRequest) toServiceRequest() credential.CreateCredentialRequest {
+	verificationMethodID := did.FullyQualifiedVerificationMethodID(c.Issuer, c.IssuerKID)
 	return credential.CreateCredentialRequest{
-		Issuer:      c.Issuer,
-		IssuerKID:   c.IssuerKID,
-		Subject:     c.Subject,
-		Context:     c.Context,
-		SchemaID:    c.SchemaID,
-		Data:        c.Data,
-		Expiry:      c.Expiry,
-		Revocable:   c.Revocable,
-		Suspendable: c.Suspendable,
-		Evidence:    c.Evidence,
+		Issuer:                             c.Issuer,
+		FullyQualifiedVerificationMethodID: verificationMethodID,
+		Subject:                            c.Subject,
+		Context:                            c.Context,
+		SchemaID:                           c.SchemaID,
+		Data:                               c.Data,
+		Expiry:                             c.Expiry,
+		Revocable:                          c.Revocable,
+		Suspendable:                        c.Suspendable,
+		Evidence:                           c.Evidence,
 	}
 }
 
diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go
index 92dc010..a34f382 100644
--- a/pkg/server/router/manifest.go
+++ b/pkg/server/router/manifest.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/gin-gonic/gin"
 	"github.com/goccy/go-json"
 	"github.com/tbd54566975/ssi-service/pkg/service/common"
@@ -79,15 +80,16 @@ type CreateManifestRequest struct {
 }
 
 func (c CreateManifestRequest) ToServiceRequest() model.CreateManifestRequest {
+	verificationMethodID := did.FullyQualifiedVerificationMethodID(c.IssuerDID, c.IssuerKID)
 	return model.CreateManifestRequest{
-		Name:                      c.Name,
-		Description:               c.Description,
-		IssuerDID:                 c.IssuerDID,
-		IssuerKID:                 c.IssuerKID,
-		IssuerName:                c.IssuerName,
-		OutputDescriptors:         c.OutputDescriptors,
-		ClaimFormat:               c.ClaimFormat,
-		PresentationDefinitionRef: c.PresentationDefinitionRef,
+		Name:                               c.Name,
+		Description:                        c.Description,
+		IssuerDID:                          c.IssuerDID,
+		FullyQualifiedVerificationMethodID: verificationMethodID,
+		IssuerName:                         c.IssuerName,
+		OutputDescriptors:                  c.OutputDescriptors,
+		ClaimFormat:                        c.ClaimFormat,
+		PresentationDefinitionRef:          c.PresentationDefinitionRef,
 	}
 }
 
diff --git a/pkg/service/common/request.go b/pkg/service/common/request.go
index 651733f..8d50c83 100644
--- a/pkg/service/common/request.go
+++ b/pkg/service/common/request.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"time"
 
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/google/uuid"
 	"github.com/lestrrat-go/jwx/v2/jwt"
 	"github.com/pkg/errors"
@@ -65,7 +66,9 @@ func CreateStoredRequest(ctx context.Context, keyStore *keystore.Service, claimN
 	if err != nil {
 		return nil, errors.Wrap(err, "building jwt")
 	}
-	signedToken, err := keyStore.Sign(ctx, request.IssuerKID, token)
+
+	keyStoreID := did.FullyQualifiedVerificationMethodID(request.IssuerDID, request.IssuerKID)
+	signedToken, err := keyStore.Sign(ctx, keyStoreID, token)
 	if err != nil {
 		return nil, errors.Wrapf(err, "signing payload with KID %q", request.IssuerKID)
 	}
diff --git a/pkg/service/credential/model.go b/pkg/service/credential/model.go
index f71c459..8e7b3e5 100644
--- a/pkg/service/credential/model.go
+++ b/pkg/service/credential/model.go
@@ -15,9 +15,11 @@ type BatchCreateCredentialsResponse struct {
 }
 
 type CreateCredentialRequest struct {
-	Issuer    string `json:"issuer" validate:"required"`
-	IssuerKID string `json:"issuerKid" validate:"required"`
-	Subject   string `json:"subject" validate:"required"`
+	Issuer string `json:"issuer" validate:"required"`
+	// Fully qualified verification method ID to determine the private key used for signing this credential. For example
+	// `did:ion:EiDpQBo_nEfuLVeppgmPVQNEhtrnZLWFsB9ziZUuaKCJ3Q#83526c36-136c-423b-a57a-f190b83ae531`.
+	FullyQualifiedVerificationMethodID string `json:"issuerVerificationMethodId" validate:"required"`
+	Subject                            string `json:"subject" validate:"required"`
 	// A context is optional. If not present, we'll apply default, required context values.
 	Context string `json:"context,omitempty"`
 	// A schema ID is optional. If present, we'll attempt to look it up and validate the data against it.
diff --git a/pkg/service/credential/service.go b/pkg/service/credential/service.go
index 33313eb..330ab01 100644
--- a/pkg/service/credential/service.go
+++ b/pkg/service/credential/service.go
@@ -8,12 +8,12 @@ import (
 	"github.com/TBD54566975/ssi-sdk/credential"
 	schemalib "github.com/TBD54566975/ssi-sdk/credential/schema"
 	statussdk "github.com/TBD54566975/ssi-sdk/credential/status"
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/TBD54566975/ssi-sdk/did/resolution"
 	sdkutil "github.com/TBD54566975/ssi-sdk/util"
 	"github.com/google/uuid"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
-
 	"github.com/tbd54566975/ssi-service/config"
 	credint "github.com/tbd54566975/ssi-service/internal/credential"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
@@ -232,14 +232,14 @@ func (s Service) createCredential(ctx context.Context, request CreateCredentialR
 	if err != nil {
 		return nil, sdkutil.LoggingErrorMsg(err, "could not copy credential")
 	}
-	credJWT, err := s.signCredentialJWT(ctx, request.IssuerKID, *credCopy)
+	credJWT, err := s.signCredentialJWT(ctx, request.FullyQualifiedVerificationMethodID, *credCopy)
 	if err != nil {
 		return nil, sdkutil.LoggingErrorMsg(err, "signing credential")
 	}
 
 	container := credint.Container{
 		ID:            credentialID,
-		IssuerKID:     request.IssuerKID,
+		IssuerKID:     request.FullyQualifiedVerificationMethodID,
 		Credential:    cred,
 		CredentialJWT: credJWT,
 		Revoked:       false,
@@ -258,7 +258,8 @@ func (s Service) createCredential(ctx context.Context, request CreateCredentialR
 
 // signCredentialJWT signs a credential and returns it as a vc-jwt
 func (s Service) signCredentialJWT(ctx context.Context, issuerKID string, cred credential.VerifiableCredential) (*keyaccess.JWT, error) {
-	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: issuerKID})
+	keyStoreID := did.FullyQualifiedVerificationMethodID(cred.IssuerID(), issuerKID)
+	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: keyStoreID})
 	if err != nil {
 		return nil, sdkutil.LoggingErrorMsgf(err, "getting key for signing credential<%s>", issuerKID)
 	}
diff --git a/pkg/service/credential/status.go b/pkg/service/credential/status.go
index 77a9cf0..d05722c 100644
--- a/pkg/service/credential/status.go
+++ b/pkg/service/credential/status.go
@@ -18,7 +18,7 @@ import (
 func (s Service) createStatusListEntryForCredential(ctx context.Context, credID string, request CreateCredentialRequest,
 	tx storage.Tx, statusMetadata StatusListCredentialMetadata) (*statussdk.StatusList2021Entry, error) {
 	issuerID := request.Issuer
-	issuerKID := request.IssuerKID
+	issuerKID := request.FullyQualifiedVerificationMethodID
 	schemaID := request.SchemaID
 
 	statusPurpose := statussdk.StatusRevocation
diff --git a/pkg/service/did/ion.go b/pkg/service/did/ion.go
index db7908a..766f3c8 100644
--- a/pkg/service/did/ion.go
+++ b/pkg/service/did/ion.go
@@ -9,6 +9,7 @@ import (
 	"github.com/TBD54566975/ssi-sdk/crypto/jwx"
 	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/TBD54566975/ssi-sdk/did/ion"
+	"github.com/TBD54566975/ssi-sdk/did/resolution"
 	"github.com/TBD54566975/ssi-sdk/util"
 	"github.com/google/uuid"
 	"github.com/mr-tron/base58"
@@ -51,12 +52,8 @@ type ionHandler struct {
 var _ MethodHandler = (*ionHandler)(nil)
 
 type CreateIONDIDOptions struct {
-	// TODO(gabe) for now we only allow adding service endpoints upon creation.
-	//  we do not allow adding external keys or other properties.
-	//  Related:
-	//  - https://github.com/TBD54566975/ssi-sdk/issues/336
-	//  - https://github.com/TBD54566975/ssi-sdk/issues/335
-	ServiceEndpoints []did.Service `json:"serviceEndpoints"`
+	ServiceEndpoints []did.Service   `json:"serviceEndpoints"`
+	PublicKeys       []ion.PublicKey `json:"publicKeys"`
 }
 
 func (c CreateIONDIDOptions) Method() did.Method {
@@ -120,6 +117,7 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 			Purposes: []ion.PublicKeyPurpose{ion.Authentication, ion.AssertionMethod},
 		},
 	}
+	pubKeys = append(pubKeys, opts.PublicKeys...)
 
 	// generate the did document's initial state
 	doc := ion.Document{PublicKeys: pubKeys, Services: opts.ServiceEndpoints}
@@ -129,42 +127,15 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 	}
 
 	// submit the create operation to the ION service
-	if err = h.resolver.Anchor(ctx, createOp); err != nil {
+	var resolutionResult *resolution.Result
+	if resolutionResult, err = h.resolver.Anchor(ctx, createOp); err != nil {
 		return nil, errors.Wrap(err, "anchoring create operation")
 	}
 
-	// construct first document state
-	ldKeyType, err := did.KeyTypeToMultikeyLDType(request.KeyType)
-	if err != nil {
-		return nil, errors.Wrap(err, "converting key type to LD key type")
-	}
-
-	// TODO(gabe): move this to the SDK
-	didDoc := did.Document{
-		ID: ionDID.ID(),
-		VerificationMethod: []did.VerificationMethod{
-			{
-				ID:           keyID,
-				Type:         ldKeyType,
-				Controller:   ionDID.ID(),
-				PublicKeyJWK: pubKeyJWK,
-			},
-		},
-		Authentication:  []did.VerificationMethodSet{map[string]any{"id": keyID}},
-		AssertionMethod: []did.VerificationMethodSet{map[string]any{"id": keyID}},
-	}
-	for _, s := range opts.ServiceEndpoints {
-		didDoc.Services = append(didDoc.Services, did.Service{
-			ID:              s.ID,
-			Type:            s.Type,
-			ServiceEndpoint: s.ServiceEndpoint,
-		})
-	}
-
 	// store the did document
 	storedDID := ionStoredDID{
-		ID:          ionDID.ID(),
-		DID:         didDoc,
+		ID:          resolutionResult.Document.ID,
+		DID:         resolutionResult.Document,
 		SoftDeleted: false,
 		LongFormDID: ionDID.LongForm(),
 		Operations:  ionDID.Operations(),
@@ -177,7 +148,7 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 	// 1. update key
 	// 2. recovery key
 	// 3. key(s) in the did docs
-	updateStoreRequest, err := keyToStoreRequest(ionDID.ID()+"#"+updateKeySuffix, ionDID.GetUpdatePrivateKey(), ionDID.ID())
+	updateStoreRequest, err := keyToStoreRequest(resolutionResult.Document.ID+"#"+updateKeySuffix, ionDID.GetUpdatePrivateKey(), resolutionResult.Document.ID)
 	if err != nil {
 		return nil, errors.Wrap(err, "converting update private key to store request")
 	}
@@ -185,7 +156,7 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 		return nil, errors.Wrap(err, "could not store did:ion update private key")
 	}
 
-	recoveryStoreRequest, err := keyToStoreRequest(ionDID.ID()+"#"+recoverKeySuffix, ionDID.GetRecoveryPrivateKey(), ionDID.ID())
+	recoveryStoreRequest, err := keyToStoreRequest(resolutionResult.Document.ID+"#"+recoverKeySuffix, ionDID.GetRecoveryPrivateKey(), resolutionResult.Document.ID)
 	if err != nil {
 		return nil, errors.Wrap(err, "converting recovery private key to store request")
 	}
@@ -193,7 +164,8 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 		return nil, errors.Wrap(err, "could not store did:ion recovery private key")
 	}
 
-	keyStoreRequest, err := keyToStoreRequest(keyID, *privKeyJWK, ionDID.ID())
+	keyStoreID := did.FullyQualifiedVerificationMethodID(resolutionResult.Document.ID, resolutionResult.Document.VerificationMethod[0].ID)
+	keyStoreRequest, err := keyToStoreRequest(keyStoreID, *privKeyJWK, resolutionResult.Document.ID)
 	if err != nil {
 		return nil, errors.Wrap(err, "converting private key to store request")
 	}
@@ -201,7 +173,7 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (*
 		return nil, errors.Wrap(err, "could not store did:ion private key")
 	}
 
-	return &CreateDIDResponse{DID: didDoc}, nil
+	return &CreateDIDResponse{DID: storedDID.DID}, nil
 }
 
 func keyToStoreRequest(kid string, privateKeyJWK jwx.PrivateKeyJWK, controller string) (*keystore.StoreKeyRequest, error) {
diff --git a/pkg/service/manifest/model/model.go b/pkg/service/manifest/model/model.go
index 1535ab7..0b143e4 100644
--- a/pkg/service/manifest/model/model.go
+++ b/pkg/service/manifest/model/model.go
@@ -15,14 +15,14 @@ import (
 // Manifest
 
 type CreateManifestRequest struct {
-	Name                      *string                        `json:"name,omitempty"`
-	Description               *string                        `json:"description,omitempty"`
-	IssuerDID                 string                         `json:"issuerDid" validate:"required"`
-	IssuerKID                 string                         `json:"issuerKid" validate:"required"`
-	IssuerName                *string                        `json:"issuerName,omitempty"`
-	OutputDescriptors         []manifestsdk.OutputDescriptor `json:"outputDescriptors" validate:"required,dive"`
-	ClaimFormat               *exchange.ClaimFormat          `json:"format" validate:"required,dive"`
-	PresentationDefinitionRef *PresentationDefinitionRef     `json:"presentationDefinitionRef,omitempty" validate:"omitempty,dive"`
+	Name                               *string                        `json:"name,omitempty"`
+	Description                        *string                        `json:"description,omitempty"`
+	IssuerDID                          string                         `json:"issuerDid" validate:"required"`
+	FullyQualifiedVerificationMethodID string                         `json:"fullyQualifiedVerificationMethodId" validate:"required"`
+	IssuerName                         *string                        `json:"issuerName,omitempty"`
+	OutputDescriptors                  []manifestsdk.OutputDescriptor `json:"outputDescriptors" validate:"required,dive"`
+	ClaimFormat                        *exchange.ClaimFormat          `json:"format" validate:"required,dive"`
+	PresentationDefinitionRef          *PresentationDefinitionRef     `json:"presentationDefinitionRef,omitempty" validate:"omitempty,dive"`
 }
 
 type CreateManifestResponse struct {
diff --git a/pkg/service/manifest/response.go b/pkg/service/manifest/response.go
index 4068332..c61253e 100644
--- a/pkg/service/manifest/response.go
+++ b/pkg/service/manifest/response.go
@@ -29,10 +29,10 @@ const (
 	DenialResponse errresp.Type = "DenialResponse"
 )
 
-func (s Service) signCredentialResponse(ctx context.Context, issuerKID string, r CredentialResponseContainer) (*keyaccess.JWT, error) {
-	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: issuerKID})
+func (s Service) signCredentialResponse(ctx context.Context, keyStoreID string, r CredentialResponseContainer) (*keyaccess.JWT, error) {
+	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: keyStoreID})
 	if err != nil {
-		return nil, sdkutil.LoggingErrorMsgf(err, "getting key for signing response with key<%s>", issuerKID)
+		return nil, sdkutil.LoggingErrorMsgf(err, "getting key for signing response with key<%s>", keyStoreID)
 	}
 	keyAccess, err := keyaccess.NewJWKKeyAccess(gotKey.Controller, gotKey.ID, gotKey.Key)
 	if err != nil {
@@ -101,10 +101,10 @@ func (s Service) fulfillmentCredentialResponse(ctx context.Context, responseBuil
 	creds := make([]cred.Container, 0, len(credManifest.OutputDescriptors))
 	for _, od := range credManifest.OutputDescriptors {
 		createCredentialRequest := credential.CreateCredentialRequest{
-			Issuer:    credManifest.Issuer.ID,
-			IssuerKID: issuerKID,
-			Subject:   applicantDID,
-			SchemaID:  od.Schema,
+			Issuer:                             credManifest.Issuer.ID,
+			FullyQualifiedVerificationMethodID: issuerKID,
+			Subject:                            applicantDID,
+			SchemaID:                           od.Schema,
 			// TODO(gabe) need to add in data here to match the request + schema
 			Data: make(map[string]any),
 		}
diff --git a/pkg/service/manifest/service.go b/pkg/service/manifest/service.go
index f51548a..59b4668 100644
--- a/pkg/service/manifest/service.go
+++ b/pkg/service/manifest/service.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/TBD54566975/ssi-sdk/did/resolution"
 	errresp "github.com/TBD54566975/ssi-sdk/error"
 	sdkutil "github.com/TBD54566975/ssi-sdk/util"
@@ -196,7 +197,7 @@ func (s Service) CreateManifest(ctx context.Context, request model.CreateManifes
 	storageRequest := manifeststg.StoredManifest{
 		ID:        m.ID,
 		IssuerDID: m.Issuer.ID,
-		IssuerKID: request.IssuerKID,
+		IssuerKID: request.FullyQualifiedVerificationMethodID,
 		Manifest:  *m,
 	}
 
@@ -372,7 +373,8 @@ func (s Service) attemptAutomaticIssuance(ctx context.Context, request model.Sub
 		return nil, err
 	}
 
-	responseJWT, err := s.signCredentialResponse(ctx, gotManifest.IssuerKID, CredentialResponseContainer{
+	keyStoreID := did.FullyQualifiedVerificationMethodID(gotManifest.IssuerDID, gotManifest.IssuerKID)
+	responseJWT, err := s.signCredentialResponse(ctx, keyStoreID, CredentialResponseContainer{
 		Response:    *credResp,
 		Credentials: credint.ContainersToInterface(creds),
 	})
@@ -441,7 +443,8 @@ func (s Service) ReviewApplication(ctx context.Context, request model.ReviewAppl
 	}
 
 	// sign the response before returning
-	responseJWT, err := s.signCredentialResponse(ctx, gotManifest.IssuerKID, responseContainer)
+	keyStoreID := did.FullyQualifiedVerificationMethodID(gotManifest.IssuerDID, gotManifest.IssuerKID)
+	responseJWT, err := s.signCredentialResponse(ctx, keyStoreID, responseContainer)
 	if err != nil {
 		return nil, sdkutil.LoggingErrorMsg(err, "could not sign credential response")
 	}
diff --git a/pkg/service/schema/service.go b/pkg/service/schema/service.go
index 161d2ab..23ffca1 100644
--- a/pkg/service/schema/service.go
+++ b/pkg/service/schema/service.go
@@ -9,6 +9,7 @@ import (
 	"github.com/TBD54566975/ssi-sdk/credential"
 	"github.com/TBD54566975/ssi-sdk/credential/parsing"
 	"github.com/TBD54566975/ssi-sdk/credential/schema"
+	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/TBD54566975/ssi-sdk/did/resolution"
 	schemalib "github.com/TBD54566975/ssi-sdk/schema"
 	sdkutil "github.com/TBD54566975/ssi-sdk/util"
@@ -180,7 +181,8 @@ func (s Service) createCredentialSchema(ctx context.Context, jsonSchema schema.J
 
 // signCredentialSchema signs a credential schema with the issuer's key and kid as a  VC JWT
 func (s Service) signCredentialSchema(ctx context.Context, cred credential.VerifiableCredential, issuer, issuerKID string) (*keyaccess.JWT, error) {
-	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: issuerKID})
+	keyStoreID := did.FullyQualifiedVerificationMethodID(cred.IssuerID(), issuerKID)
+	gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: keyStoreID})
 	if err != nil {
 		return nil, sdkutil.LoggingErrorMsgf(err, "getting key for signing credential schema<%s>", issuerKID)
 	}


Test patch:
diff --git a/integration/didion_integration_test.go b/integration/didion_integration_test.go
index 56567bd..39ab8ac 100644
--- a/integration/didion_integration_test.go
+++ b/integration/didion_integration_test.go
@@ -43,6 +43,27 @@ func TestCreateIssuerDIDIONIntegration(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NotEmpty(t, issuerKID)
 	SetValue(didIONContext, "issuerKID", issuerKID)
+
+	verificationMethod1ID, err := getJSONElement(didIONOutput, "$.did.verificationMethod[1].id")
+	assert.NoError(t, err)
+	assert.Equal(t, "#externalVerificationMethodId", verificationMethod1ID)
+
+	verificationMethod1KID, err := getJSONElement(didIONOutput, "$.did.verificationMethod[1].publicKeyJwk.kid")
+	assert.NoError(t, err)
+	assert.Equal(t, "myExternalPublicKID", verificationMethod1KID)
+
+	keyAgreementKID, err := getJSONElement(didIONOutput, "$.did.keyAgreement[0]")
+	assert.NoError(t, err)
+	assert.Equal(t, "#externalVerificationMethodId", keyAgreementKID)
+
+	capabilityInvocationKID, err := getJSONElement(didIONOutput, "$.did.capabilityInvocation[0]")
+	assert.NoError(t, err)
+	assert.Equal(t, "#externalVerificationMethodId", capabilityInvocationKID)
+
+	capabilityDelegationKID, err := getJSONElement(didIONOutput, "$.did.capabilityDelegation[0]")
+	assert.NoError(t, err)
+	assert.Equal(t, "#externalVerificationMethodId", capabilityDelegationKID)
+
 }
 
 func TestCreateAliceDIDKeyForDIDIONIntegration(t *testing.T) {
diff --git a/integration/testdata/did-ion-input.json b/integration/testdata/did-ion-input.json
index 9d7bf8e..52e9edd 100644
--- a/integration/testdata/did-ion-input.json
+++ b/integration/testdata/did-ion-input.json
@@ -1,3 +1,25 @@
 {
-  "keyType":"Ed25519"
+  "keyType":"Ed25519",
+  "options": {
+    "serviceEndpoints": [],
+    "publicKeys": [
+      {
+        "id": "externalVerificationMethodId",
+        "type": "JsonWebKey2020",
+        "publicKeyJwk": {
+          "kty": "OKP",
+          "crv": "Ed25519",
+          "x": "CV-aGlld3nVdgnhoZK0D36Wk-9aIMlZjZOK2XhPMnkQ",
+          "kid": "myExternalPublicKID"
+        },
+        "purposes": [
+          "authentication",
+          "assertionMethod",
+          "capabilityInvocation",
+          "capabilityDelegation",
+          "keyAgreement"
+        ]
+      }
+    ]
+  }
 }
\ No newline at end of file
diff --git a/pkg/server/router/credential_test.go b/pkg/server/router/credential_test.go
index e4aa9ab..0449426 100644
--- a/pkg/server/router/credential_test.go
+++ b/pkg/server/router/credential_test.go
@@ -68,9 +68,9 @@ func TestCredentialRouter(t *testing.T) {
 				issuer := issuerDID.DID.ID
 				subject := "did:test:345"
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
 					Data: map[string]any{
 						"firstName": "Satoshi",
 						"lastName":  "Nakamoto",
@@ -133,10 +133,10 @@ func TestCredentialRouter(t *testing.T) {
 
 				// create another cred with the same issuer, different subject, different schema that doesn't exist
 				_, err = credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   "did:abcd:efghi",
-					SchemaID:  "https://test-schema.com",
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            "did:abcd:efghi",
+					SchemaID:                           "https://test-schema.com",
 					Data: map[string]any{
 						"email": "satoshi@nakamoto.com",
 					},
@@ -152,10 +152,10 @@ func TestCredentialRouter(t *testing.T) {
 
 				// create another cred with the same issuer, different subject, different schema that does exist
 				createdCredWithSchema, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   "did:abcd:efghi",
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            "did:abcd:efghi",
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "satoshi@nakamoto.com",
 					},
@@ -220,7 +220,7 @@ func TestCredentialRouter(t *testing.T) {
 				didID := controllerDID.DID.ID
 
 				// Create a key controlled by the DID
-				keyID := "MyKeyId"
+				keyID := controllerDID.DID.VerificationMethod[0].ID
 				privateKey := "2dEPd7mA3aiuh2gky8tTPiCkyMwf8tBNUMZwRzeVxVJnJFGTbdLGUBcx51DCNyFWRjTG9bduvyLRStXSCDMFXULY"
 
 				err = keyStoreService.StoreKey(context.Background(), keystore.StoreKeyRequest{ID: keyID, Type: crypto.Ed25519, Controller: didID, PrivateKeyBase58: privateKey})
@@ -229,9 +229,9 @@ func TestCredentialRouter(t *testing.T) {
 				// Create a crendential
 				subject := "did:test:42"
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    didID,
-					IssuerKID: keyID,
-					Subject:   subject,
+					Issuer:                             didID,
+					FullyQualifiedVerificationMethodID: keyID,
+					Subject:                            subject,
 					Data: map[string]any{
 						"firstName": "Satoshi",
 						"lastName":  "Nakamoto",
@@ -249,9 +249,9 @@ func TestCredentialRouter(t *testing.T) {
 				// Create a crendential with the revoked key, it fails
 				subject = "did:test:43"
 				createdCred, err = credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    didID,
-					IssuerKID: keyID,
-					Subject:   subject,
+					Issuer:                             didID,
+					FullyQualifiedVerificationMethodID: keyID,
+					Subject:                            subject,
 					Data: map[string]any{
 						"firstName": "John",
 						"lastName":  "Doe",
@@ -293,10 +293,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCredResp, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -316,10 +316,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.NotEmpty(tt, credStatusMap["statusListIndex"])
 
 				createdCredRespTwo, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi2@Nakamoto2.btc",
 					},
@@ -346,10 +346,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.NotEmpty(tt, createdSchemaTwo)
 
 				createdCredRespThree, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchemaTwo.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchemaTwo.ID,
 					Data: map[string]any{
 						"email": "Satoshi2@Nakamoto2.btc",
 					},
@@ -398,9 +398,9 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCredResp, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -420,9 +420,9 @@ func TestCredentialRouter(t *testing.T) {
 				assert.NotEmpty(tt, credStatusMap["statusListIndex"])
 
 				createdCredRespTwo, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
 					Data: map[string]any{
 						"email": "Satoshi2@Nakamoto2.btc",
 					},
@@ -450,10 +450,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.NotEmpty(tt, createdSchema)
 
 				createdCredRespThree, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi2@Nakamoto2.btc",
 					},
@@ -505,10 +505,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				nonRevokableCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "cant@revoke.me",
 					},
@@ -520,10 +520,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.ErrorContains(tt, err, "has no credentialStatus field")
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -625,10 +625,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				nonSuspendableCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "cant@revoke.me",
 					},
@@ -640,10 +640,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.ErrorContains(tt, err, "has no credentialStatus field")
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -744,10 +744,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -758,10 +758,10 @@ func TestCredentialRouter(t *testing.T) {
 				assert.NotEmpty(tt, createdCred)
 
 				createdCredSuspendable, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: issuerDID.DID.VerificationMethod[0].ID,
-					Subject:   subject,
-					SchemaID:  createdSchema.ID,
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: issuerDID.DID.VerificationMethod[0].ID,
+					Subject:                            subject,
+					SchemaID:                           createdSchema.ID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -805,10 +805,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -861,10 +861,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -939,10 +939,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1022,10 +1022,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1044,10 +1044,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1069,10 +1069,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1094,10 +1094,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				_, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1122,10 +1122,10 @@ func TestCredentialRouter(t *testing.T) {
 				}
 
 				_, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
@@ -1141,10 +1141,10 @@ func TestCredentialRouter(t *testing.T) {
 				subject := "did:test:345"
 
 				createdCred, err := credService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuer,
-					IssuerKID: issuerKID,
-					Subject:   subject,
-					SchemaID:  schemaID,
+					Issuer:                             issuer,
+					FullyQualifiedVerificationMethodID: issuerKID,
+					Subject:                            subject,
+					SchemaID:                           schemaID,
 					Data: map[string]any{
 						"email": "Satoshi@Nakamoto.btc",
 					},
diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go
index 6cb4c8f..5a9b758 100644
--- a/pkg/server/router/manifest_test.go
+++ b/pkg/server/router/manifest_test.go
@@ -145,11 +145,11 @@ func TestManifestRouter(t *testing.T) {
 
 					// issue a credential against the schema to the subject, from the issuer
 					createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-						Issuer:    issuerDID.DID.ID,
-						IssuerKID: kid,
-						Subject:   applicantDID.ID,
-						SchemaID:  createdSchema.ID,
-						Data:      map[string]any{"licenseType": "WA-DL-CLASS-A"},
+						Issuer:                             issuerDID.DID.ID,
+						FullyQualifiedVerificationMethodID: kid,
+						Subject:                            applicantDID.ID,
+						SchemaID:                           createdSchema.ID,
+						Data:                               map[string]any{"licenseType": "WA-DL-CLASS-A"},
 					})
 					assert.NoError(ttt, err)
 					assert.NotEmpty(ttt, createdCred)
@@ -247,8 +247,8 @@ func getValidManifestRequestRequest(issuerDID *did.CreateDIDResponse, kid string
 // getValidManifestRequest returns a valid manifest request, expecting a single JWT-VC EdDSA credential
 func getValidManifestRequest(issuerDID, issuerKID, schemaID string) model.CreateManifestRequest {
 	createManifestRequest := model.CreateManifestRequest{
-		IssuerDID: issuerDID,
-		IssuerKID: issuerKID,
+		IssuerDID:                          issuerDID,
+		FullyQualifiedVerificationMethodID: issuerKID,
 		ClaimFormat: &exchange.ClaimFormat{
 			JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
 		},
diff --git a/pkg/server/server_did_test.go b/pkg/server/server_did_test.go
index eba4466..01f4c54 100644
--- a/pkg/server/server_did_test.go
+++ b/pkg/server/server_did_test.go
@@ -1,6 +1,7 @@
 package server
 
 import (
+	_ "embed"
 	"fmt"
 	"net/http"
 	"net/http/httptest"
@@ -21,6 +22,9 @@ import (
 	"github.com/tbd54566975/ssi-service/pkg/service/did"
 )
 
+//go:embed testdata/basic_did_resolution.json
+var BasicDIDResolution []byte
+
 func TestDIDAPI(t *testing.T) {
 
 	for _, test := range testutil.TestDatabases {
@@ -192,7 +196,8 @@ func TestDIDAPI(t *testing.T) {
 
 				gock.New(testIONResolverURL).
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				// with body, good key type, no options
@@ -232,7 +237,8 @@ func TestDIDAPI(t *testing.T) {
 
 				gock.New(testIONResolverURL).
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				c = newRequestContextWithParams(w, req, params)
diff --git a/pkg/server/server_issuance_test.go b/pkg/server/server_issuance_test.go
index f1c308b..91a2f72 100644
--- a/pkg/server/server_issuance_test.go
+++ b/pkg/server/server_issuance_test.go
@@ -436,9 +436,9 @@ func setupAllThings(t *testing.T, s storage.ServiceStorage) (*did.CreateDIDRespo
 
 	sillyName := "some silly name"
 	manifest, err := manifestSvc.CreateManifest(context.Background(), model.CreateManifestRequest{
-		Name:      &sillyName,
-		IssuerDID: issuerResp.DID.ID,
-		IssuerKID: issuerResp.DID.VerificationMethod[0].ID,
+		Name:                               &sillyName,
+		IssuerDID:                          issuerResp.DID.ID,
+		FullyQualifiedVerificationMethodID: issuerResp.DID.VerificationMethod[0].ID,
 		ClaimFormat: &exchange.ClaimFormat{
 			JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
 		},
diff --git a/pkg/server/server_manifest_test.go b/pkg/server/server_manifest_test.go
index b880da3..97481c7 100644
--- a/pkg/server/server_manifest_test.go
+++ b/pkg/server/server_manifest_test.go
@@ -383,10 +383,10 @@ func TestManifestAPI(t *testing.T) {
 				createdCred, err := credentialService.CreateCredential(
 					context.Background(),
 					credential.CreateCredentialRequest{
-						Issuer:    issuerDID.DID.ID,
-						IssuerKID: kid,
-						Subject:   applicantDID.ID,
-						SchemaID:  licenseApplicationSchema.ID,
+						Issuer:                             issuerDID.DID.ID,
+						FullyQualifiedVerificationMethodID: kid,
+						Subject:                            applicantDID.ID,
+						SchemaID:                           licenseApplicationSchema.ID,
 						Data: map[string]any{
 							"licenseType": "Class D",
 							"firstName":   "Tester",
@@ -543,11 +543,11 @@ func TestManifestAPI(t *testing.T) {
 
 				// issue a credential against the schema to the subject, from the issuer
 				createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: kid,
-					Subject:   applicantDID.ID,
-					SchemaID:  licenseApplicationSchema.ID,
-					Data:      map[string]any{"licenseType": "Class D"},
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: kid,
+					Subject:                            applicantDID.ID,
+					SchemaID:                           licenseApplicationSchema.ID,
+					Data:                               map[string]any{"licenseType": "Class D"},
 				})
 				assert.NoError(tt, err)
 				assert.NotEmpty(tt, createdCred)
@@ -703,11 +703,11 @@ func TestManifestAPI(t *testing.T) {
 
 				// issue a credential against the schema to the subject, from the issuer
 				createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: kid,
-					Subject:   applicantDID.ID,
-					SchemaID:  licenseApplicationSchema.ID,
-					Data:      map[string]any{"licenseType": "Class D"},
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: kid,
+					Subject:                            applicantDID.ID,
+					SchemaID:                           licenseApplicationSchema.ID,
+					Data:                               map[string]any{"licenseType": "Class D"},
 				})
 				assert.NoError(tt, err)
 				assert.NotEmpty(tt, createdCred)
@@ -854,11 +854,11 @@ func TestManifestAPI(t *testing.T) {
 				assert.NotEmpty(tt, licenseSchema)
 				// issue a credential against the schema to the subject, from the issuer
 				createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: kid,
-					Subject:   applicantDID.ID,
-					SchemaID:  licenseApplicationSchema.ID,
-					Data:      map[string]any{"licenseType": "Class D"},
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: kid,
+					Subject:                            applicantDID.ID,
+					SchemaID:                           licenseApplicationSchema.ID,
+					Data:                               map[string]any{"licenseType": "Class D"},
 				})
 				assert.NoError(tt, err)
 				assert.NotEmpty(tt, createdCred)
@@ -1026,11 +1026,11 @@ func TestManifestAPI(t *testing.T) {
 
 				// issue a credential against the schema to the subject, from the issuer
 				createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{
-					Issuer:    issuerDID.DID.ID,
-					IssuerKID: kid,
-					Subject:   applicantDID.ID,
-					SchemaID:  createdSchema.ID,
-					Data:      map[string]any{"licenseType": "WA-DL-CLASS-A"},
+					Issuer:                             issuerDID.DID.ID,
+					FullyQualifiedVerificationMethodID: kid,
+					Subject:                            applicantDID.ID,
+					SchemaID:                           createdSchema.ID,
+					Data:                               map[string]any{"licenseType": "WA-DL-CLASS-A"},
 				})
 				assert.NoError(tt, err)
 				assert.NotEmpty(tt, createdCred)
diff --git a/pkg/server/testdata/basic_did_resolution.json b/pkg/server/testdata/basic_did_resolution.json
new file mode 100644
index 0000000..ee5ec3b
--- /dev/null
+++ b/pkg/server/testdata/basic_did_resolution.json
@@ -0,0 +1,53 @@
+{
+  "didDocument": {
+    "@context": [
+      "https://www.w3.org/ns/did/v1",
+      {
+        "@base": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg"
+      }
+    ],
+    "assertionMethod": [
+      "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+      "#externalPublicKey1"
+    ],
+    "authentication": [
+      "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+      "#externalPublicKey1"
+    ],
+    "capabilityDelegation": [
+      "#externalPublicKey1"
+    ],
+    "capabilityInvocation": [
+      "#externalPublicKey1"
+    ],
+    "id": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+    "keyAgreement": [
+      "#externalPublicKey1"
+    ],
+    "verificationMethod": [
+      {
+        "controller": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+        "id": "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+        "publicKeyJwk": {
+          "alg": "EdDSA",
+          "crv": "Ed25519",
+          "kid": "1fb94235-376f-4a7e-a1e5-b5d036449764",
+          "kty": "OKP",
+          "x": "5jfCRhiHE2PNxDY8rzDylKdN9aO7dPE-QQBrNxYz1YU"
+        },
+        "type": "Ed25519"
+      },
+      {
+        "controller": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+        "id": "#externalPublicKey1",
+        "publicKeyJwk": {
+          "crv": "Ed25519",
+          "kid": "#myOwnKID",
+          "kty": "OKP",
+          "x": "CV-aGlld3nVdgnhoZK0D36Wk-9aIMlZjZOK2XhPMnkQ"
+        },
+        "type": "JsonWebKey2020"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/pkg/service/did/ion_test.go b/pkg/service/did/ion_test.go
index aa94942..f4a781e 100644
--- a/pkg/service/did/ion_test.go
+++ b/pkg/service/did/ion_test.go
@@ -2,11 +2,13 @@ package did
 
 import (
 	"context"
+	_ "embed"
 	"fmt"
 	"testing"
 
 	"github.com/TBD54566975/ssi-sdk/crypto"
 	"github.com/TBD54566975/ssi-sdk/did"
+	"github.com/goccy/go-json"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tbd54566975/ssi-service/config"
@@ -16,6 +18,9 @@ import (
 	"gopkg.in/h2non/gock.v1"
 )
 
+//go:embed testdata/basic_did_resolution.json
+var BasicDIDResolution []byte
+
 func TestIONHandler(t *testing.T) {
 	for _, test := range testutil.TestDatabases {
 		t.Run(test.Name, func(t *testing.T) {
@@ -63,7 +68,8 @@ func TestIONHandler(t *testing.T) {
 
 				gock.New("https://test-ion-resolver.com").
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				// create a did
@@ -78,7 +84,8 @@ func TestIONHandler(t *testing.T) {
 			t.Run("Test Create DID", func(tt *testing.T) {
 				gock.New("https://ion.tbddev.org").
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				// create a handler
@@ -119,7 +126,8 @@ func TestIONHandler(t *testing.T) {
 
 				gock.New("https://test-ion-resolver.com").
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				// create a did
@@ -157,7 +165,8 @@ func TestIONHandler(t *testing.T) {
 
 				gock.New("https://test-ion-resolver.com").
 					Post("/operations").
-					Reply(200)
+					Reply(200).
+					BodyString(string(BasicDIDResolution))
 				defer gock.Off()
 
 				// create a did
@@ -168,9 +177,12 @@ func TestIONHandler(t *testing.T) {
 				assert.NoError(tt, err)
 				assert.NotEmpty(tt, created)
 
+				createdDIDData, err := json.Marshal(created.DID)
+				assert.NoError(tt, err)
+
 				gock.New("https://test-ion-resolver.com").
 					Get("/identifiers/" + created.DID.ID).
-					Reply(200).BodyString(fmt.Sprintf(`{"didDocument": {"id": "%s"}}`, created.DID.ID))
+					Reply(200).BodyString(fmt.Sprintf(`{"didDocument": %s }`, createdDIDData))
 				defer gock.Off()
 
 				// get all DIDs
@@ -211,7 +223,8 @@ func TestIONHandler(t *testing.T) {
 
 				gock.New("https://test-ion-resolver.com").
 					Get("/identifiers/did:ion:test").
-					Reply(200).BodyString(`{"didDocument": {"id": "did:ion:test"}}`)
+					Reply(200).
+					BodyString(`{"didDocument": {"id": "did:ion:test"}}`)
 				defer gock.Off()
 
 				// get the did
diff --git a/pkg/service/did/testdata/basic_did_resolution.json b/pkg/service/did/testdata/basic_did_resolution.json
new file mode 100644
index 0000000..ee5ec3b
--- /dev/null
+++ b/pkg/service/did/testdata/basic_did_resolution.json
@@ -0,0 +1,53 @@
+{
+  "didDocument": {
+    "@context": [
+      "https://www.w3.org/ns/did/v1",
+      {
+        "@base": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg"
+      }
+    ],
+    "assertionMethod": [
+      "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+      "#externalPublicKey1"
+    ],
+    "authentication": [
+      "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+      "#externalPublicKey1"
+    ],
+    "capabilityDelegation": [
+      "#externalPublicKey1"
+    ],
+    "capabilityInvocation": [
+      "#externalPublicKey1"
+    ],
+    "id": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+    "keyAgreement": [
+      "#externalPublicKey1"
+    ],
+    "verificationMethod": [
+      {
+        "controller": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+        "id": "#b26f6e6b-8bd1-46ee-b02d-fd421db54714",
+        "publicKeyJwk": {
+          "alg": "EdDSA",
+          "crv": "Ed25519",
+          "kid": "1fb94235-376f-4a7e-a1e5-b5d036449764",
+          "kty": "OKP",
+          "x": "5jfCRhiHE2PNxDY8rzDylKdN9aO7dPE-QQBrNxYz1YU"
+        },
+        "type": "Ed25519"
+      },
+      {
+        "controller": "did:ion:EiCImroVD18aylCsdNn6y4CUHks8TwzqY08E-aSyTeZuqg",
+        "id": "#externalPublicKey1",
+        "publicKeyJwk": {
+          "crv": "Ed25519",
+          "kid": "#myOwnKID",
+          "kty": "OKP",
+          "x": "CV-aGlld3nVdgnhoZK0D36Wk-9aIMlZjZOK2XhPMnkQ"
+        },
+        "type": "JsonWebKey2020"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/pkg/testutil/well_known_generation_test.go b/pkg/testutil/well_known_generation_test.go
index bcc697c..08e3131 100644
--- a/pkg/testutil/well_known_generation_test.go
+++ b/pkg/testutil/well_known_generation_test.go
@@ -39,7 +39,7 @@ func TestWellKnownGenerationTest(t *testing.T) {
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, didKey)
 
-		gotKey, err := keyStoreService.GetKey(context.Background(), keystore.GetKeyRequest{ID: didKey.DID.ID})
+		gotKey, err := keyStoreService.GetKey(context.Background(), keystore.GetKeyRequest{ID: didKey.DID.VerificationMethod[0].ID})
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, gotKey)
 
@@ -50,12 +50,11 @@ func TestWellKnownGenerationTest(t *testing.T) {
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, didWeb)
 
-		gotDidWebKey, err := keyStoreService.GetKey(context.Background(), keystore.GetKeyRequest{ID: didWeb.DID.ID})
+		gotDidWebKey, err := keyStoreService.GetKey(context.Background(), keystore.GetKeyRequest{ID: didWeb.DID.VerificationMethod[0].ID})
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, gotDidWebKey)
 
 		createWellKnownDIDConfiguration(tt, didWeb, gotDidWebKey, origin)
-
 	})
 }