Repository: TBD54566975/ssi-service
Pull request #135 (2022-10-18 04:04:02)

Credential Application & Response Signing/Verification
- tests coming

codecov-commenter: # [Codecov](https://codecov.io/gh/TBD54566975/ssi-service/pull/135?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) Report
> Merging [#135](https://codecov.io/gh/TBD54566975/ssi-service/pull/135?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (7c6b131) into [main](https://codecov.io/gh/TBD54566975/ssi-service/commit/b13025ac1f3dad64760e508fa2755b2e3ec43282?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (b13025a) will **increase** coverage by `0.17%`.
> The diff coverage is `20.00%`.

```diff
@@            Coverage Diff             @@
##             main     #135      +/-   ##
==========================================
+ Coverage   27.80%   27.97%   +0.17%     
==========================================
  Files          20       20              
  Lines        1500     1555      +55     
==========================================
+ Hits          417      435      +18     
- Misses       1016     1047      +31     
- Partials       67       73       +6     
```


| [Impacted Files](https://codecov.io/gh/TBD54566975/ssi-service/pull/135?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) | Coverage Δ | |
|---|---|---|
| [internal/did/access.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-aW50ZXJuYWwvZGlkL2FjY2Vzcy5nbw==) | `0.00% <0.00%> (ø)` | |
| [internal/keyaccess/jwt.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-aW50ZXJuYWwva2V5YWNjZXNzL2p3dC5nbw==) | `48.21% <0.00%> (-6.34%)` | :arrow_down: |
| [pkg/server/router/did.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvZGlkLmdv) | `7.92% <0.00%> (-0.08%)` | :arrow_down: |
| [pkg/server/router/keystore.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIva2V5c3RvcmUuZ28=) | `12.69% <0.00%> (ø)` | |
| [pkg/service/keystore/service.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZpY2Uva2V5c3RvcmUvc2VydmljZS5nbw==) | `43.18% <25.00%> (ø)` | |
| [pkg/server/router/manifest.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/135/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvbWFuaWZlc3QuZ28=) | `11.69% <32.14%> (+7.93%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975)

decentralgabe: fixing the e2e in a follow-up

Patch:
diff --git a/README.md b/README.md
index b8a55b4..3352aa6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 [![godoc ssi-service](https://img.shields.io/badge/godoc-ssi--service-blue)](https://github.com/TBD54566975/ssi-service)
-[![go version 1.17.6](https://img.shields.io/badge/go_version-1.17.6-brightgreen)](https://go.dev/)
+[![go version 1.19.2](https://img.shields.io/badge/go_version-1.19.2-brightgreen)](https://go.dev/)
 [![license Apache 2](https://img.shields.io/badge/license-Apache%202-black)](https://github.com/TBD54566975/ssi-service/blob/main/LICENSE)
 [![issues](https://img.shields.io/github/issues/TBD54566975/ssi-service)](https://github.com/TBD54566975/ssi-service/issues)
 ![push](https://github.com/TBD54566975/ssi-service/workflows/ssi-service-ci/badge.svg?branch=main&event=push)
diff --git a/doc/swagger.yaml b/doc/swagger.yaml
index 4d08deb..fafd42f 100644
--- a/doc/swagger.yaml
+++ b/doc/swagger.yaml
@@ -297,6 +297,8 @@ definitions:
         $ref: '#/definitions/exchange.Filter'
       id:
         type: string
+      optional:
+        type: boolean
       path:
         items:
           type: string
@@ -322,9 +324,6 @@ definitions:
       exclusiveMinimum: {}
       format:
         type: string
-      formatMaximum: {}
-      formatMinimum:
-        description: TODO(gabe) these may not be valid https://github.com/decentralized-identity/presentation-exchange/issues/312
       maxLength:
         type: integer
       maximum: {}
@@ -512,15 +511,29 @@ definitions:
     properties:
       did:
         $ref: '#/definitions/did.DIDDocument'
+      keyType:
+        type: string
       privateKeyBase58:
         type: string
     type: object
   github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest:
     properties:
-      manifest:
-        $ref: '#/definitions/manifest.CredentialManifest'
+      format:
+        $ref: '#/definitions/exchange.ClaimFormat'
+      issuerDid:
+        type: string
+      issuerName:
+        type: string
+      outputDescriptors:
+        items:
+          $ref: '#/definitions/manifest.OutputDescriptor'
+        type: array
+      presentationDefinition:
+        $ref: '#/definitions/exchange.PresentationDefinition'
     required:
-    - manifest
+    - format
+    - issuerDid
+    - outputDescriptors
     type: object
   github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse:
     properties:
@@ -708,25 +721,18 @@ definitions:
     type: object
   github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest:
     properties:
-      applicantDid:
-        description: Once we have JWT signed wrapper that can get the did this can
-          be removed
+      applicationJwt:
         type: string
-      credential_application:
-        $ref: '#/definitions/manifest.CredentialApplication'
-      verifiableCredentials:
-        items: {}
-        type: array
     required:
-    - applicantDid
-    - credential_application
-    - verifiableCredentials
+    - applicationJwt
     type: object
   github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationResponse:
     properties:
       credential_response:
         $ref: '#/definitions/manifest.CredentialResponse'
-      verifiableCredential:
+      responseJwt:
+        type: string
+      verifiableCredentials:
         description: this is an interface type to union Data Integrity and JWT style
           VCs
         items: {}
@@ -913,15 +919,29 @@ definitions:
     properties:
       did:
         $ref: '#/definitions/did.DIDDocument'
+      keyType:
+        type: string
       privateKeyBase58:
         type: string
     type: object
   pkg_server_router.CreateManifestRequest:
     properties:
-      manifest:
-        $ref: '#/definitions/manifest.CredentialManifest'
+      format:
+        $ref: '#/definitions/exchange.ClaimFormat'
+      issuerDid:
+        type: string
+      issuerName:
+        type: string
+      outputDescriptors:
+        items:
+          $ref: '#/definitions/manifest.OutputDescriptor'
+        type: array
+      presentationDefinition:
+        $ref: '#/definitions/exchange.PresentationDefinition'
     required:
-    - manifest
+    - format
+    - issuerDid
+    - outputDescriptors
     type: object
   pkg_server_router.CreateManifestResponse:
     properties:
@@ -1109,25 +1129,18 @@ definitions:
     type: object
   pkg_server_router.SubmitApplicationRequest:
     properties:
-      applicantDid:
-        description: Once we have JWT signed wrapper that can get the did this can
-          be removed
+      applicationJwt:
         type: string
-      credential_application:
-        $ref: '#/definitions/manifest.CredentialApplication'
-      verifiableCredentials:
-        items: {}
-        type: array
     required:
-    - applicantDid
-    - credential_application
-    - verifiableCredentials
+    - applicationJwt
     type: object
   pkg_server_router.SubmitApplicationResponse:
     properties:
       credential_response:
         $ref: '#/definitions/manifest.CredentialResponse'
-      verifiableCredential:
+      responseJwt:
+        type: string
+      verifiableCredentials:
         description: this is an interface type to union Data Integrity and JWT style
           VCs
         items: {}
@@ -1473,7 +1486,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse'
+            $ref: '#/definitions/pkg_server_router.GetDIDMethodsResponse'
       summary: Get DID Methods
       tags:
       - DecentralizedIdentityAPI
@@ -1494,7 +1507,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDsByMethodResponse'
+            $ref: '#/definitions/pkg_server_router.GetDIDsByMethodResponse'
         "400":
           description: Bad request
           schema:
@@ -1512,7 +1525,7 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest'
+          $ref: '#/definitions/pkg_server_router.CreateDIDByMethodRequest'
       - description: Method
         in: path
         name: method
@@ -1524,7 +1537,7 @@ paths:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse'
+            $ref: '#/definitions/pkg_server_router.CreateDIDByMethodResponse'
         "400":
           description: Bad request
           schema:
@@ -1547,7 +1560,7 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest'
+          $ref: '#/definitions/pkg_server_router.CreateDIDByMethodRequest'
       - description: Method
         in: path
         name: method
@@ -1564,7 +1577,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse'
+            $ref: '#/definitions/pkg_server_router.GetDIDByMethodResponse'
         "400":
           description: Bad request
           schema:
@@ -1589,7 +1602,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse'
+            $ref: '#/definitions/pkg_server_router.ResolveDIDResponse'
         "400":
           description: Bad request
           schema:
@@ -1608,14 +1621,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.PublishManifestRequest'
+          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/pkg_server_router.PublishManifestResponse'
+            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestResponse'
         "400":
           description: Bad request
           schema:
@@ -1638,7 +1651,7 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.StoreKeyRequest'
+          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest'
       produces:
       - application/json
       responses:
@@ -1672,7 +1685,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetKeyDetailsResponse'
+            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse'
         "400":
           description: Bad request
           schema:
@@ -1826,7 +1839,8 @@ paths:
     put:
       consumes:
       - application/json
-      description: Submit application
+      description: Submit a credential application in response to a credential manifest.
+        The request body is expected to
       parameters:
       - description: request body
         in: body
diff --git a/go.mod b/go.mod
index 0eaca44..b1a05e0 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/BurntSushi/toml v1.2.0
-	github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221012163631-99a9a918234b
+	github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221019200812-2e73f0ac7722
 	github.com/ardanlabs/conf v1.5.0
 	github.com/dimfeld/httptreemux/v5 v5.4.0
 	github.com/go-playground/locales v0.14.0
@@ -29,8 +29,10 @@ require (
 )
 
 require (
+	github.com/buger/jsonparser v1.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
+	github.com/flowstack-com/jsonschema v0.1.2 // indirect
 	github.com/go-logr/logr v1.2.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-playground/validator/v10 v10.11.1 // indirect
@@ -42,7 +44,7 @@ require (
 	github.com/lestrrat-go/option v1.0.0 // indirect
 	github.com/multiformats/go-base32 v0.0.3 // indirect
 	github.com/multiformats/go-base36 v0.1.0 // indirect
-	github.com/multiformats/go-multicodec v0.6.0 // indirect
+	github.com/multiformats/go-multicodec v0.7.0 // indirect
 	github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indirect
 	github.com/piprate/json-gold v0.4.2 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -51,6 +53,7 @@ require (
 	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+	golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
 	golang.org/x/sys v0.0.0-20221006211917-84dc82d7e875 // indirect
 	golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect
 	golang.org/x/text v0.3.7 // indirect
diff --git a/go.sum b/go.sum
index 762f3e4..7bd6e56 100644
--- a/go.sum
+++ b/go.sum
@@ -1,9 +1,21 @@
 github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
 github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221012163631-99a9a918234b h1:7JhNPNNGDdIB7Q6kTaHd3cirG1xcDsmEX2ryK+a5iKM=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221012163631-99a9a918234b/go.mod h1:zmrYK0NCOKbD6lOOXzZBN51RN6Ai78HuZ3Jt0tqbkm0=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018194946-8583e4f4cc0c h1:BhL+EcNdgDeN0bfkKnBJLBXQJqJT4oZLlj/K+AgCKWI=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018194946-8583e4f4cc0c/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018201910-e1f529bd6a66 h1:3QwnubV4j2NQVnSt2YAT1hUHM26hrMS6xq3nPWofV1k=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018201910-e1f529bd6a66/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018210928-40550f92af68 h1:sH0LMADYtuTsvjBJPn1hwVIiM73HPHPaQN6xdf5msIY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018210928-40550f92af68/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018231409-c5db11472c38 h1:SvBK316+1tgBJmQOX0khxyRmyXOPtxqonPSQPPrLIuA=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221018231409-c5db11472c38/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221019161256-4b326c0c823a h1:YAdegwCMrbEr1N43FMKmqjObci8q+sc1NVf9qlyLoto=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221019161256-4b326c0c823a/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221019200812-2e73f0ac7722 h1:aDCoimfCRlAcFCYo3XUiYmavv39VXf45xX2eLrTgmtA=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20221019200812-2e73f0ac7722/go.mod h1:WBOPlvZkJ1qXW5HINQiNxgWTEm5THpkPy8iHXNkYnRY=
 github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
 github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -14,6 +26,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
 github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs=
 github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
+github.com/flowstack-com/jsonschema v0.1.2 h1:qO2Ed0OHxY88yqqfNwUGfWxF64rVQCdbJ68lmlHSIXs=
+github.com/flowstack-com/jsonschema v0.1.2/go.mod h1:Ce82M1ocyTfow5soqyAcHShvlSUqM8odW0UZVIIK4pQ=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
 github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -67,8 +81,8 @@ github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ8
 github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
 github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI=
 github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
-github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
-github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
+github.com/multiformats/go-multicodec v0.7.0 h1:rTUjGOwjlhGHbEMbPoSUJowG1spZTVsITRANCjKTUAQ=
+github.com/multiformats/go-multicodec v0.7.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
 github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
 github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjGmesFh1D0rDy+q1Twx6FyU7VWHi8wZbI=
@@ -120,6 +134,8 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
 golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/internal/credential/model.go b/internal/credential/model.go
index e3322aa..24f1459 100644
--- a/internal/credential/model.go
+++ b/internal/credential/model.go
@@ -25,6 +25,22 @@ func (c Container) JWTString() string {
 	return string(*c.CredentialJWT)
 }
 
+func (c Container) IsValid() bool {
+	return c.ID != "" && (c.HasDataIntegrityCredential() || c.HasJWTCredential())
+}
+
+func (c Container) HasSignedCredential() bool {
+	return c.HasDataIntegrityCredential() || c.HasJWTCredential()
+}
+
+func (c Container) HasDataIntegrityCredential() bool {
+	return c.Credential != nil && c.Credential.Proof != nil
+}
+
+func (c Container) HasJWTCredential() bool {
+	return c.CredentialJWT != nil
+}
+
 // NewCredentialContainerFromJWT attempts to parse a VC-JWT credential from a string into a Container
 func NewCredentialContainerFromJWT(credentialJWT string) (*Container, error) {
 	cred, err := signing.ParseVerifiableCredentialFromJWT(credentialJWT)
@@ -33,6 +49,7 @@ func NewCredentialContainerFromJWT(credentialJWT string) (*Container, error) {
 	}
 	return &Container{
 		ID:            cred.ID,
+		Credential:    cred,
 		CredentialJWT: keyaccess.JWTPtr(credentialJWT),
 	}, nil
 }
@@ -58,20 +75,16 @@ func NewCredentialContainerFromMap(credMap map[string]interface{}) (*Container,
 	return nil, errors.New("credential does not have a data integrity proof")
 }
 
-func (cc Container) IsValid() bool {
-	return cc.ID != "" && (cc.HasDataIntegrityCredential() || cc.HasJWTCredential())
-}
-
-func (cc Container) HasSignedCredential() bool {
-	return cc.HasDataIntegrityCredential() || cc.HasJWTCredential()
-}
-
-func (cc Container) HasDataIntegrityCredential() bool {
-	return cc.Credential != nil && cc.Credential.Proof != nil
-}
-
-func (cc Container) HasJWTCredential() bool {
-	return cc.CredentialJWT != nil
+func ContainersToInterface(cs []Container) []interface{} {
+	var credentials []interface{}
+	for _, container := range cs {
+		if container.HasDataIntegrityCredential() {
+			credentials = append(credentials, *container.Credential)
+		} else if container.HasJWTCredential() {
+			credentials = append(credentials, *container.CredentialJWT)
+		}
+	}
+	return credentials
 }
 
 // NewCredentialContainerFromArray attempts to parse arrays of credentials of any type (either data integrity or JWT)
@@ -95,7 +108,7 @@ func NewCredentialContainerFromArray(creds []interface{}) ([]Container, error) {
 			}
 			containers = append(containers, *container)
 		default:
-			return nil, fmt.Errorf("invalid credential type: %s", reflect.TypeOf(c).Name())
+			return nil, fmt.Errorf("invalid credential type: %s", reflect.TypeOf(c).Kind().String())
 		}
 	}
 	return containers, nil
diff --git a/internal/credential/verification.go b/internal/credential/verification.go
index ca3d29b..43a85f7 100644
--- a/internal/credential/verification.go
+++ b/internal/credential/verification.go
@@ -2,6 +2,7 @@ package credential
 
 import (
 	"crypto"
+	"fmt"
 
 	credsdk "github.com/TBD54566975/ssi-sdk/credential"
 	"github.com/TBD54566975/ssi-sdk/credential/signing"
@@ -10,6 +11,7 @@ import (
 	"github.com/goccy/go-json"
 	"github.com/pkg/errors"
 
+	didint "github.com/tbd54566975/ssi-service/internal/did"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
 	"github.com/tbd54566975/ssi-service/internal/schema"
 	"github.com/tbd54566975/ssi-service/internal/util"
@@ -55,7 +57,7 @@ func (v Verifier) VerifyJWTCredential(token keyaccess.JWT) error {
 	}
 
 	// resolve the issuer's key material
-	kid, pubKey, err := v.resolveIssuerKey(*cred)
+	kid, pubKey, err := v.resolveCredentialIssuerKey(*cred)
 	if err != nil {
 		return util.LoggingError(err)
 	}
@@ -78,7 +80,7 @@ func (v Verifier) VerifyJWTCredential(token keyaccess.JWT) error {
 // a set of static verification checks on the credential as per the credential service's configuration.
 func (v Verifier) VerifyDataIntegrityCredential(credential credsdk.VerifiableCredential) error {
 	// resolve the issuer's key material
-	kid, pubKey, err := v.resolveIssuerKey(credential)
+	kid, pubKey, err := v.resolveCredentialIssuerKey(credential)
 	if err != nil {
 		return util.LoggingError(err)
 	}
@@ -86,7 +88,8 @@ func (v Verifier) VerifyDataIntegrityCredential(credential credsdk.VerifiableCre
 	// construct a signature verifier from the verification information
 	verifier, err := keyaccess.NewDataIntegrityKeyAccess(kid, pubKey)
 	if err != nil {
-		return util.LoggingErrorMsg(err, "could not create verifier")
+		errMsg := fmt.Sprintf("could not create verifier for kid %s", kid)
+		return util.LoggingErrorMsg(err, errMsg)
 	}
 
 	// verify the signature on the credential
@@ -97,24 +100,35 @@ func (v Verifier) VerifyDataIntegrityCredential(credential credsdk.VerifiableCre
 	return v.staticVerificationChecks(credential)
 }
 
-// resolveIssuerKey resolves the issuer's public key from the credential's issuer DID.
-// TODO(gabe): perhaps this should be a verification method referenced on the proof object, not the issuer
-// TODO(gabe): support issuers that are not strings, but objects
-func (v Verifier) resolveIssuerKey(credential credsdk.VerifiableCredential) (kid string, pubKey crypto.PublicKey, err error) {
-	issuerDID := credential.Issuer.(string)
-	resolved, err := v.didResolver.Resolve(issuerDID, nil)
+func (v Verifier) VerifyJWT(did string, token keyaccess.JWT) error {
+	// resolve the did's key material
+	kid, pubKey, err := didint.ResolveKeyForDID(v.didResolver, did)
 	if err != nil {
-		err = errors.Wrapf(err, "failed to resolve did: %s", issuerDID)
-		return
+		return util.LoggingError(err)
 	}
 
-	// next, get the verification information (key) from the did document of the issuer
-	kid, pubKey, err = keyaccess.GetVerificationInformation(resolved.DIDDocument, "")
+	// construct a signature verifier from the verification information
+	verifier, err := keyaccess.NewJWKKeyAccessVerifier(kid, pubKey)
 	if err != nil {
-		err = errors.Wrapf(err, "failed to get verification information from the issuer's did document: %s", issuerDID)
-		return
+		errMsg := fmt.Sprintf("could not create verifier for kid %s", kid)
+		return util.LoggingErrorMsg(err, errMsg)
 	}
-	return
+
+	// verify the signature on the credential
+	if err = verifier.Verify(token); err != nil {
+		return util.LoggingErrorMsg(err, "could not verify the JWT signature")
+	}
+
+	return nil
+}
+
+// resolveCredentialIssuerKey resolves the issuer's public key from the credential's issuer DID.
+// TODO(gabe): perhaps this should be a verification method referenced on the proof object, not the issuer
+// TODO(gabe): support issuers that are not strings, but objects
+func (v Verifier) resolveCredentialIssuerKey(credential credsdk.VerifiableCredential) (kid string, pubKey crypto.PublicKey, err error) {
+	issuerDID := credential.Issuer.(string)
+	return didint.ResolveKeyForDID(v.didResolver, issuerDID)
+
 }
 
 // staticVerificationChecks runs a set of static verification checks on the credential as per the credential
diff --git a/internal/keyaccess/verification.go b/internal/did/access.go
similarity index 84%
rename from internal/keyaccess/verification.go
rename to internal/did/access.go
index dd38e5f..e6158a9 100644
--- a/internal/keyaccess/verification.go
+++ b/internal/did/access.go
@@ -1,4 +1,4 @@
-package keyaccess
+package did
 
 import (
 	"crypto"
@@ -29,7 +29,7 @@ func GetVerificationInformation(did didsdk.DIDDocument, maybeKID string) (kid st
 
 	// handle the case where a kid is provided && there are multiple verification methods
 	if len(verificationMethods) > 1 {
-		if kid == "" {
+		if maybeKID == "" {
 			return "", nil, errors.Errorf("kid is required for did: %s, which has multiple verification methods", did.ID)
 		}
 		for _, method := range verificationMethods {
@@ -106,3 +106,20 @@ func multibaseToPubKeyBytes(mb string) ([]byte, error) {
 	pubKeyBytes := decoded[n:]
 	return pubKeyBytes, nil
 }
+
+// ResolveKeyForDID resolves a public key from a DID.
+func ResolveKeyForDID(resolver *didsdk.Resolver, did string) (kid string, pubKey crypto.PublicKey, err error) {
+	resolved, err := resolver.Resolve(did, nil)
+	if err != nil {
+		err = errors.Wrapf(err, "failed to resolve did: %s", did)
+		return
+	}
+
+	// next, get the verification information (key) from the did document
+	kid, pubKey, err = GetVerificationInformation(resolved.DIDDocument, "")
+	if err != nil {
+		err = errors.Wrapf(err, "failed to get verification information from the did document: %s", did)
+		return
+	}
+	return
+}
diff --git a/internal/keyaccess/jwt.go b/internal/keyaccess/jwt.go
index 4089b8d..c7fde1d 100644
--- a/internal/keyaccess/jwt.go
+++ b/internal/keyaccess/jwt.go
@@ -6,6 +6,7 @@ import (
 	"github.com/TBD54566975/ssi-sdk/credential"
 	"github.com/TBD54566975/ssi-sdk/credential/signing"
 	"github.com/TBD54566975/ssi-sdk/crypto"
+	"github.com/goccy/go-json"
 	"github.com/lestrrat-go/jwx/jwk"
 	"github.com/pkg/errors"
 )
@@ -78,6 +79,22 @@ func JWTPtr(j string) *JWT {
 	return &jwt
 }
 
+// SignJSON takes an object that is either itself json or json-serializable and signs it.
+func (ka JWKKeyAccess) SignJSON(data interface{}) (*JWT, error) {
+	if ka.JWTSigner == nil {
+		return nil, errors.New("cannot sign with nil signer")
+	}
+	jsonBytes, err := json.Marshal(data)
+	if err != nil {
+		return nil, err
+	}
+	payload := make(map[string]interface{})
+	if err = json.Unmarshal(jsonBytes, &payload); err != nil {
+		return nil, err
+	}
+	return ka.Sign(payload)
+}
+
 func (ka JWKKeyAccess) Sign(payload map[string]interface{}) (*JWT, error) {
 	if ka.JWTSigner == nil {
 		return nil, errors.New("cannot sign with nil signer")
diff --git a/magefile.go b/magefile.go
index 7270931..94f9356 100644
--- a/magefile.go
+++ b/magefile.go
@@ -154,7 +154,8 @@ func ColorizeTestOutput(w io.Writer) io.Writer {
 }
 
 func ColorizeTestStdout() io.Writer {
-	if terminal.IsTerminal(syscall.Stdout) {
+	stdout := int(syscall.Stdout)
+	if terminal.IsTerminal(stdout) {
 		return ColorizeTestOutput(os.Stdout)
 	}
 	return os.Stdout
diff --git a/pkg/server/router/did.go b/pkg/server/router/did.go
index dafbf09..c223b08 100644
--- a/pkg/server/router/did.go
+++ b/pkg/server/router/did.go
@@ -62,8 +62,9 @@ type CreateDIDByMethodRequest struct {
 }
 
 type CreateDIDByMethodResponse struct {
-	DID        didsdk.DIDDocument `json:"did,omitempty"`
-	PrivateKey string             `json:"privateKeyBase58,omitempty"`
+	DID              didsdk.DIDDocument `json:"did,omitempty"`
+	PrivateKeyBase58 string             `json:"privateKeyBase58,omitempty"`
+	KeyType          crypto.KeyType     `json:"keyType,omitempty"`
 }
 
 // CreateDIDByMethod godoc
@@ -110,8 +111,9 @@ func (dr DIDRouter) CreateDIDByMethod(ctx context.Context, w http.ResponseWriter
 	}
 
 	resp := CreateDIDByMethodResponse{
-		DID:        createDIDResponse.DID,
-		PrivateKey: createDIDResponse.PrivateKey,
+		DID:              createDIDResponse.DID,
+		PrivateKeyBase58: createDIDResponse.PrivateKeyBase58,
+		KeyType:          createDIDResponse.KeyType,
 	}
 	return framework.Respond(ctx, w, resp, http.StatusCreated)
 }
diff --git a/pkg/server/router/keystore.go b/pkg/server/router/keystore.go
index d5c6214..f22b040 100644
--- a/pkg/server/router/keystore.go
+++ b/pkg/server/router/keystore.go
@@ -34,23 +34,23 @@ type StoreKeyRequest struct {
 	ID               string         `json:"id" validate:"required"`
 	Type             crypto.KeyType `json:"type,omitempty" validate:"required"`
 	Controller       string         `json:"controller,omitempty" validate:"required"`
-	Base58PrivateKey string         `json:"base58PrivateKey,omitempty" validate:"required"`
+	PrivateKeyBase58 string         `json:"base58PrivateKey,omitempty" validate:"required"`
 }
 
 func (sk StoreKeyRequest) ToServiceRequest() (*keystore.StoreKeyRequest, error) {
-	privateKeyBytes, err := base58.Decode(sk.Base58PrivateKey)
+	// make sure we can decode and re-encode the key before storing it
+	privateKeyBytes, err := base58.Decode(sk.PrivateKeyBase58)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not decode base58 private key")
 	}
-	privKey, err := crypto.BytesToPrivKey(privateKeyBytes, sk.Type)
-	if err != nil {
+	if _, err = crypto.BytesToPrivKey(privateKeyBytes, sk.Type); err != nil {
 		return nil, errors.Wrap(err, "could not convert bytes to private key")
 	}
 	return &keystore.StoreKeyRequest{
-		ID:         sk.ID,
-		Type:       sk.Type,
-		Controller: sk.Controller,
-		Key:        privKey,
+		ID:               sk.ID,
+		Type:             sk.Type,
+		Controller:       sk.Controller,
+		PrivateKeyBase58: sk.PrivateKeyBase58,
 	}, nil
 }
 
diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go
index 24d63fe..464044d 100644
--- a/pkg/server/router/manifest.go
+++ b/pkg/server/router/manifest.go
@@ -5,7 +5,11 @@ import (
 	"fmt"
 	"net/http"
 
+	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
+	"github.com/goccy/go-json"
+	"github.com/lestrrat-go/jwx/jwk"
+	"github.com/lestrrat-go/jwx/jwt"
 
 	"github.com/tbd54566975/ssi-service/internal/credential"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
@@ -35,15 +39,23 @@ func NewManifestRouter(s svcframework.Service) (*ManifestRouter, error) {
 	}, nil
 }
 
-// CreateManifestRequest
-// TODO(gabe) consider simplifying this to accept just output descriptors, format, presentation definition
+// CreateManifestRequest is the request body for creating a manifest, which populates all remaining fields
+// and builds a well-formed manifest object.
 type CreateManifestRequest struct {
-	Manifest manifestsdk.CredentialManifest `json:"manifest" validate:"required"`
+	IssuerDID              string                           `json:"issuerDid" validate:"required"`
+	IssuerName             *string                          `json:"issuerName,omitempty"`
+	ClaimFormat            *exchange.ClaimFormat            `json:"format" validate:"required,dive"`
+	OutputDescriptors      []manifestsdk.OutputDescriptor   `json:"outputDescriptors" validate:"required,dive"`
+	PresentationDefinition *exchange.PresentationDefinition `json:"presentationDefinition,omitempty" validate:"omitempty,dive"`
 }
 
 func (c CreateManifestRequest) ToServiceRequest() manifest.CreateManifestRequest {
 	return manifest.CreateManifestRequest{
-		Manifest: c.Manifest,
+		IssuerDID:              c.IssuerDID,
+		IssuerName:             c.IssuerName,
+		OutputDescriptors:      c.OutputDescriptors,
+		ClaimFormat:            c.ClaimFormat,
+		PresentationDefinition: c.PresentationDefinition,
 	}
 }
 
@@ -105,7 +117,7 @@ type GetManifestResponse struct {
 // @Success      200  {object}  GetManifestResponse
 // @Failure      400  {string}  string  "Bad request"
 // @Router       /v1/manifests/{id} [get]
-func (mr ManifestRouter) GetManifest(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetManifest(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot get manifest without ID parameter"
@@ -145,7 +157,7 @@ type GetManifestsResponse struct {
 // @Failure      400      {string}  string  "Bad request"
 // @Failure      500      {string}  string  "Internal server error"
 // @Router       /v1/manifests [get]
-func (mr ManifestRouter) GetManifests(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetManifests(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	gotManifests, err := mr.service.GetManifests()
 
 	if err != nil {
@@ -178,7 +190,7 @@ func (mr ManifestRouter) GetManifests(ctx context.Context, w http.ResponseWriter
 // @Failure      400  {string}  string  "Bad request"
 // @Failure      500  {string}  string  "Internal server error"
 // @Router       /v1/manifests/{id} [delete]
-func (mr ManifestRouter) DeleteManifest(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) DeleteManifest(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot delete manifest without ID parameter"
@@ -196,33 +208,83 @@ func (mr ManifestRouter) DeleteManifest(ctx context.Context, w http.ResponseWrit
 }
 
 type SubmitApplicationRequest struct {
-	// Once we have JWT signed wrapper that can get the did this can be removed
-	ApplicantDID string                            `json:"applicantDid" validate:"required"`
-	Application  manifestsdk.CredentialApplication `json:"credential_application" validate:"required"`
-	Credentials  []interface{}                     `json:"verifiableCredentials" validate:"required"`
+	ApplicationJWT keyaccess.JWT `json:"applicationJwt" validate:"required"`
+	// Contains the following properties:
+	// Application  manifestsdk.CredentialApplication `json:"credential_application" validate:"required"`
+	// Credentials  []interface{}                     `json:"vcs" validate:"required"`
 }
 
+const (
+	vcsJSONProperty                   = "vcs"
+	verifiableCredentialsJSONProperty = "verifiableCredentials"
+)
+
 func (sar SubmitApplicationRequest) ToServiceRequest() (*manifest.SubmitApplicationRequest, error) {
-	credContainer, err := credential.NewCredentialContainerFromArray(sar.Credentials)
+	parsed, err := jwt.Parse([]byte(sar.ApplicationJWT))
+	if err != nil {
+		return nil, errors.Wrap(err, "could not parse Credential Application token")
+	}
+
+	// make sure the known properties are present (Application and Credentials)
+	kid, ok := parsed.Get(jwk.KeyIDKey)
+	if !ok || kid == "" {
+		return nil, errors.New("Credential Application token missing kid")
+	}
+	var creds []interface{}
+	credentials, ok := parsed.Get(vcsJSONProperty)
+	if !ok {
+		logrus.Warn("could not find vc in Credential Application token, looking for `verifiableCredentials`")
+		if credentials, ok = parsed.Get(verifiableCredentialsJSONProperty); !ok {
+			return nil, errors.New("could not find vc or verifiableCredentials in Credential Application token")
+		}
+	}
+	creds, ok = credentials.([]interface{})
+	if !ok {
+		errMsg := fmt.Sprintf("could not parse Credential Application token, %s is not an array", vcsJSONProperty)
+		logrus.Errorf("%s: %s", errMsg, credentials)
+		return nil, errors.New(errMsg)
+	}
+
+	// marshal known properties into their respective types
+	credAppJSON, ok := parsed.Get(manifestsdk.CredentialApplicationJSONProperty)
+	if !ok {
+		return nil, errors.New("could not find credential_application in Credential Application token")
+	}
+	applicationTokenBytes, err := json.Marshal(credAppJSON)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not marshal Credential Application credAppJSON")
+	}
+	var application manifestsdk.CredentialApplication
+	if err = json.Unmarshal(applicationTokenBytes, &application); err != nil {
+		errMsg := "could not reconstruct Credential Application"
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrap(err, errMsg)
+	}
+
+	credContainer, err := credential.NewCredentialContainerFromArray(creds)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not parse submitted credentials")
 	}
 	return &manifest.SubmitApplicationRequest{
-		ApplicantDID: sar.ApplicantDID,
-		Application:  sar.Application,
-		Credentials:  credContainer,
+		ApplicantDID:    kid.(string),
+		Application:     application,
+		Credentials:     credContainer,
+		ApplicationJWT:  sar.ApplicationJWT,
+		ApplicationJSON: parsed.PrivateClaims(),
 	}, nil
 }
 
 type SubmitApplicationResponse struct {
 	Response manifestsdk.CredentialResponse `json:"credential_response"`
 	// this is an interface type to union Data Integrity and JWT style VCs
-	Credentials []interface{} `json:"verifiableCredential"`
+	Credentials []interface{} `json:"verifiableCredentials,omitempty"`
+	ResponseJWT keyaccess.JWT `json:"responseJwt,omitempty"`
 }
 
 // SubmitApplication godoc
 // @Summary      Submit application
-// @Description  Submit application
+// @Description  Submit a credential application in response to a credential manifest. The request body is expected to
+// be a valid JWT signed by the applicant's DID, containing two top level properties: credential_application and vcs.
 // @Tags         ApplicationAPI
 // @Accept       json
 // @Produce      json
@@ -253,15 +315,11 @@ func (mr ManifestRouter) SubmitApplication(ctx context.Context, w http.ResponseW
 		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
 	}
 
-	var credentials []interface{}
-	for _, container := range submitApplicationResponse.Credentials {
-		if container.HasDataIntegrityCredential() {
-			credentials = append(credentials, *container.Credential)
-		} else if container.HasJWTCredential() {
-			credentials = append(credentials, *container.CredentialJWT)
-		}
+	resp := SubmitApplicationResponse{
+		Response:    submitApplicationResponse.Response,
+		Credentials: submitApplicationResponse.Credentials,
+		ResponseJWT: submitApplicationResponse.ResponseJWT,
 	}
-	resp := SubmitApplicationResponse{Response: submitApplicationResponse.Response, Credentials: credentials}
 
 	return framework.Respond(ctx, w, resp, http.StatusCreated)
 }
@@ -281,7 +339,7 @@ type GetApplicationResponse struct {
 // @Success      200  {object}  GetApplicationResponse
 // @Failure      400  {string}  string  "Bad request"
 // @Router       /v1/manifests/applications/{id} [get]
-func (mr ManifestRouter) GetApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetApplication(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot get application without ID parameter"
@@ -317,7 +375,7 @@ type GetApplicationsResponse struct {
 // @Failure      400      {string}  string  "Bad request"
 // @Failure      500      {string}  string  "Internal server error"
 // @Router       /v1/manifests/applications [get]
-func (mr ManifestRouter) GetApplications(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetApplications(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	gotApplications, err := mr.service.GetApplications()
 
 	if err != nil {
@@ -344,7 +402,7 @@ func (mr ManifestRouter) GetApplications(ctx context.Context, w http.ResponseWri
 // @Failure      400  {string}  string  "Bad request"
 // @Failure      500  {string}  string  "Internal server error"
 // @Router       /v1/manifests/applications/{id} [delete]
-func (mr ManifestRouter) DeleteApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) DeleteApplication(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot delete application without ID parameter"
@@ -376,7 +434,7 @@ type GetResponseResponse struct {
 // @Success      200  {object}  GetResponseResponse
 // @Failure      400  {string}  string  "Bad request"
 // @Router       /v1/manifests/responses/{id} [get]
-func (mr ManifestRouter) GetResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetResponse(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot get response without ID parameter"
@@ -412,7 +470,7 @@ type GetResponsesResponse struct {
 // @Failure      400      {string}  string  "Bad request"
 // @Failure      500      {string}  string  "Internal server error"
 // @Router       /v1/manifests/responses [get]
-func (mr ManifestRouter) GetResponses(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) GetResponses(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	gotResponses, err := mr.service.GetResponses()
 
 	if err != nil {
@@ -439,7 +497,7 @@ func (mr ManifestRouter) GetResponses(ctx context.Context, w http.ResponseWriter
 // @Failure      400  {string}  string  "Bad request"
 // @Failure      500  {string}  string  "Internal server error"
 // @Router       /v1/manifests/responses/{id} [delete]
-func (mr ManifestRouter) DeleteResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+func (mr ManifestRouter) DeleteResponse(ctx context.Context, w http.ResponseWriter, _ *http.Request) error {
 	id := framework.GetParam(ctx, IDParam)
 	if id == nil {
 		errMsg := "cannot delete response without ID parameter"
diff --git a/pkg/service/credential/credential.go b/pkg/service/credential/service.go
similarity index 96%
rename from pkg/service/credential/credential.go
rename to pkg/service/credential/service.go
index dc88acb..9119533 100644
--- a/pkg/service/credential/credential.go
+++ b/pkg/service/credential/service.go
@@ -121,7 +121,7 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede
 	}
 
 	// if a schema value exists, verify we can access it, validate the data against it, then set it
-	var credSchema *schemalib.VCJSONSchema
+	var knownSchema *schemalib.VCJSONSchema
 	if request.JSONSchema != "" {
 		// resolve schema and save it for validation later
 		gotSchema, err := s.schema.GetSchema(schema.GetSchemaRequest{ID: request.JSONSchema})
@@ -129,7 +129,7 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede
 			errMsg := fmt.Sprintf("failed to create credential; could not get schema: %s", request.JSONSchema)
 			return nil, util.LoggingErrorMsg(err, errMsg)
 		}
-		credSchema = &gotSchema.Schema
+		knownSchema = &gotSchema.Schema
 
 		credSchema := credential.CredentialSchema{
 			ID:   request.JSONSchema,
@@ -161,8 +161,8 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede
 	}
 
 	// verify the built schema complies with the schema we've set
-	if credSchema != nil {
-		if err = schemalib.IsCredentialValidForVCJSONSchema(*cred, *credSchema); err != nil {
+	if knownSchema != nil {
+		if err = schemalib.IsCredentialValidForVCJSONSchema(*cred, *knownSchema); err != nil {
 			errMsg := fmt.Sprintf("credential data does not comply with the provided schema: %s", request.JSONSchema)
 			return nil, util.LoggingErrorMsg(err, errMsg)
 		}
@@ -184,7 +184,7 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede
 	storageRequest := credstorage.StoreCredentialRequest{
 		Container: container,
 	}
-	if err := s.storage.StoreCredential(storageRequest); err != nil {
+	if err = s.storage.StoreCredential(storageRequest); err != nil {
 		errMsg := "could not store credential"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
@@ -219,12 +219,13 @@ type VerifyCredentialRequest struct {
 	CredentialJWT           *keyaccess.JWT                   `json:"credentialJwt,omitempty"`
 }
 
-// IsValid checks if the request is valid, meaning there is at least one data integrity OR jwt credential, but not both
+// IsValid checks if the request is valid, meaning there is at least one data integrity (with proof)
+// OR jwt credential, but not both
 func (vcr VerifyCredentialRequest) IsValid() error {
 	if vcr.DataIntegrityCredential == nil && vcr.CredentialJWT == nil {
 		return errors.New("either a credential or a credential JWT must be provided")
 	}
-	if vcr.DataIntegrityCredential != nil && vcr.CredentialJWT != nil {
+	if (vcr.DataIntegrityCredential != nil && vcr.DataIntegrityCredential.Proof != nil) && vcr.CredentialJWT != nil {
 		return errors.New("only one of credential or credential JWT can be provided")
 	}
 	return nil
diff --git a/pkg/service/did/key.go b/pkg/service/did/key.go
index bd9c72c..8885a97 100644
--- a/pkg/service/did/key.go
+++ b/pkg/service/did/key.go
@@ -3,6 +3,7 @@ package did
 import (
 	"fmt"
 
+	"github.com/TBD54566975/ssi-sdk/crypto"
 	"github.com/TBD54566975/ssi-sdk/did"
 	"github.com/goccy/go-json"
 	"github.com/mr-tron/base58"
@@ -44,31 +45,33 @@ func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse,
 		ID:  id,
 		DID: *expanded,
 	}
-	if err := h.storage.StoreDID(storedDID); err != nil {
+	if err = h.storage.StoreDID(storedDID); err != nil {
 		return nil, errors.Wrap(err, "could not store did:key value")
 	}
 
 	// convert to a serialized format for return to the client
-	privKeyBase58, err := privateKeyToBase58(privKey)
+	privKeyBytes, err := crypto.PrivKeyToBytes(privKey)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not encode private key as base58")
 	}
+	privKeyBase58 := base58.Encode(privKeyBytes)
 
 	// store private key in key storage
 	keyStoreRequest := keystore.StoreKeyRequest{
-		ID:         id,
-		Type:       request.KeyType,
-		Controller: id,
-		Key:        privKey,
+		ID:               id,
+		Type:             request.KeyType,
+		Controller:       id,
+		PrivateKeyBase58: privKeyBase58,
 	}
 
-	if err := h.keyStore.StoreKey(keyStoreRequest); err != nil {
+	if err = h.keyStore.StoreKey(keyStoreRequest); err != nil {
 		return nil, errors.Wrap(err, "could not store did:key private key")
 	}
 
 	return &CreateDIDResponse{
-		DID:        storedDID.DID,
-		PrivateKey: privKeyBase58,
+		DID:              storedDID.DID,
+		PrivateKeyBase58: privKeyBase58,
+		KeyType:          request.KeyType,
 	}, nil
 }
 
diff --git a/pkg/service/did/model.go b/pkg/service/did/model.go
index 1bbbda2..6eb0635 100644
--- a/pkg/service/did/model.go
+++ b/pkg/service/did/model.go
@@ -27,9 +27,9 @@ type CreateDIDRequest struct {
 
 // CreateDIDResponse is the JSON-serializable response for creating a DID
 type CreateDIDResponse struct {
-	DID didsdk.DIDDocument `json:"did"`
-	// TODO(gabe) this is temporary, and should never be exposed like this!
-	PrivateKey string `json:"base58PrivateKey"`
+	DID              didsdk.DIDDocument `json:"did"`
+	PrivateKeyBase58 string             `json:"base58PrivateKey"`
+	KeyType          crypto.KeyType     `json:"keyType"`
 }
 
 type GetDIDRequest struct {
diff --git a/pkg/service/did/did.go b/pkg/service/did/service.go
similarity index 100%
rename from pkg/service/did/did.go
rename to pkg/service/did/service.go
diff --git a/pkg/service/dwn/dwn.go b/pkg/service/dwn/service.go
similarity index 100%
rename from pkg/service/dwn/dwn.go
rename to pkg/service/dwn/service.go
diff --git a/pkg/service/keystore/model.go b/pkg/service/keystore/model.go
index 25c47ff..3d85654 100644
--- a/pkg/service/keystore/model.go
+++ b/pkg/service/keystore/model.go
@@ -7,10 +7,10 @@ import (
 )
 
 type StoreKeyRequest struct {
-	ID         string
-	Type       crypto.KeyType
-	Controller string
-	Key        gocrypto.PrivateKey
+	ID               string
+	Type             crypto.KeyType
+	Controller       string
+	PrivateKeyBase58 string
 }
 
 type GetKeyRequest struct {
diff --git a/pkg/service/keystore/keystore.go b/pkg/service/keystore/service.go
similarity index 87%
rename from pkg/service/keystore/keystore.go
rename to pkg/service/keystore/service.go
index d635de2..a4357d1 100644
--- a/pkg/service/keystore/keystore.go
+++ b/pkg/service/keystore/service.go
@@ -80,22 +80,15 @@ func (s Service) StoreKey(request StoreKeyRequest) error {
 		return util.LoggingNewError(errMsg)
 	}
 
-	// serialize the key before storage
-	keyBytes, err := crypto.PrivKeyToBytes(request.Key)
-	if err != nil {
-		return errors.Wrap(err, "could not serialize key before storage")
-	}
-	privKeyBase58 := base58.Encode(keyBytes)
-
 	key := keystorestorage.StoredKey{
 		ID:         request.ID,
 		Controller: request.Controller,
 		KeyType:    request.Type,
-		Base58Key:  privKeyBase58,
+		Base58Key:  request.PrivateKeyBase58,
 		CreatedAt:  time.Now().Format(time.RFC3339),
 	}
 	if err := s.storage.StoreKey(key); err != nil {
-		err := errors.Wrapf(err, "could not store key: %s", request.ID)
+		err = errors.Wrapf(err, "could not store key: %s", request.ID)
 		return util.LoggingError(err)
 	}
 	return nil
@@ -108,11 +101,11 @@ func (s Service) GetKey(request GetKeyRequest) (*GetKeyResponse, error) {
 	id := request.ID
 	gotKey, err := s.storage.GetKey(id)
 	if err != nil {
-		err := errors.Wrapf(err, "could not get key for key: %s", id)
+		err = errors.Wrapf(err, "could not get key for key: %s", id)
 		return nil, util.LoggingError(err)
 	}
 	if gotKey == nil {
-		err := errors.Wrapf(err, "key with id<%s> could not be found", id)
+		err = errors.Wrapf(err, "key with id<%s> could not be found", id)
 		return nil, util.LoggingError(err)
 	}
 
@@ -142,11 +135,11 @@ func (s Service) GetKeyDetails(request GetKeyDetailsRequest) (*GetKeyDetailsResp
 	id := request.ID
 	gotKeyDetails, err := s.storage.GetKeyDetails(id)
 	if err != nil {
-		err := errors.Wrapf(err, "could not get key details for key: %s", id)
+		err = errors.Wrapf(err, "could not get key details for key: %s", id)
 		return nil, util.LoggingError(err)
 	}
 	if gotKeyDetails == nil {
-		err := errors.Wrapf(err, "key with id<%s> could not be found", id)
+		err = errors.Wrapf(err, "key with id<%s> could not be found", id)
 		return nil, util.LoggingError(err)
 	}
 	return &GetKeyDetailsResponse{
@@ -162,13 +155,13 @@ func (s Service) GetKeyDetails(request GetKeyDetailsRequest) (*GetKeyDetailsResp
 func GenerateServiceKey(skPassword string) (key, salt string, err error) {
 	saltBytes, err := util.GenerateSalt(util.Argon2SaltSize)
 	if err != nil {
-		err := errors.Wrap(err, "could not generate salt for service key")
+		err = errors.Wrap(err, "could not generate salt for service key")
 		return "", "", util.LoggingError(err)
 	}
 
 	keyBytes, err := util.Argon2KeyGen(skPassword, saltBytes, chacha20poly1305.KeySize)
 	if err != nil {
-		err := errors.Wrap(err, "could not generate key for service key")
+		err = errors.Wrap(err, "could not generate key for service key")
 		return "", "", util.LoggingError(err)
 	}
 
diff --git a/pkg/service/manifest/application.go b/pkg/service/manifest/application.go
new file mode 100644
index 0000000..7914616
--- /dev/null
+++ b/pkg/service/manifest/application.go
@@ -0,0 +1,68 @@
+package manifest
+
+import (
+	"fmt"
+
+	"github.com/TBD54566975/ssi-sdk/credential/manifest"
+	"github.com/pkg/errors"
+
+	didint "github.com/tbd54566975/ssi-service/internal/did"
+	"github.com/tbd54566975/ssi-service/internal/keyaccess"
+	"github.com/tbd54566975/ssi-service/internal/util"
+	"github.com/tbd54566975/ssi-service/pkg/service/credential"
+)
+
+func (s Service) verifyApplicationJWT(did string, token keyaccess.JWT) error {
+	kid, pubKey, err := didint.ResolveKeyForDID(s.didResolver, did)
+	if err != nil {
+		return errors.Wrapf(err, "failed to resolve applicant's did: %s", did)
+	}
+	verifier, err := keyaccess.NewJWKKeyAccessVerifier(kid, pubKey)
+	if err != nil {
+		return util.LoggingErrorMsg(err, "could not create application verifier")
+	}
+	if err := verifier.Verify(token); err != nil {
+		return util.LoggingErrorMsg(err, "could not verify the application's signature")
+	}
+	return nil
+}
+
+// validateCredentialApplication validates the credential application's signature(s) in addition to making sure it
+// is a valid credential application, and complies with its corresponding manifest
+// TODO: this should also (optionally) return the failed input descriptor(s)
+func (s Service) validateCredentialApplication(credManifest manifest.CredentialManifest, request SubmitApplicationRequest) error {
+	// validate the payload's signature
+	if err := s.verifyApplicationJWT(request.ApplicantDID, request.ApplicationJWT); err != nil {
+		errMsg := fmt.Sprintf("could not verify application<%s>'s signature", request.Application.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	// validate the application
+	credApp := request.Application
+	if err := credApp.IsValid(); err != nil {
+		return util.LoggingErrorMsg(err, "application is not valid")
+	}
+
+	// next, validate that the credential(s) provided in the application are valid
+	if err := manifest.IsValidCredentialApplicationForManifest(credManifest, request.ApplicationJSON); err != nil {
+		errMsg := fmt.Sprintf("could not validate application: %s", credApp.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	// signature and validity checks for each credential submitted with the application
+	for _, credentialContainer := range request.Credentials {
+		verificationResult, err := s.credential.VerifyCredential(credential.VerifyCredentialRequest{
+			DataIntegrityCredential: credentialContainer.Credential,
+			CredentialJWT:           credentialContainer.CredentialJWT,
+		})
+		if err != nil {
+			errMsg := fmt.Sprintf("could not verify credential: %s", credentialContainer.Credential.ID)
+			return util.LoggingNewError(errMsg)
+		}
+		if !verificationResult.Verified {
+			errMsg := fmt.Sprintf("submitted credential<%s> is not valid: %s", credentialContainer.Credential.ID, verificationResult.Reason)
+			return util.LoggingNewError(errMsg)
+		}
+	}
+	return nil
+}
diff --git a/pkg/service/manifest/manifest.go b/pkg/service/manifest/manifest.go
index 8db0233..719033d 100644
--- a/pkg/service/manifest/manifest.go
+++ b/pkg/service/manifest/manifest.go
@@ -3,115 +3,18 @@ package manifest
 import (
 	"fmt"
 
-	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
-	didsdk "github.com/TBD54566975/ssi-sdk/did"
-	sdkutil "github.com/TBD54566975/ssi-sdk/util"
 	"github.com/goccy/go-json"
 	"github.com/lestrrat-go/jwx/jwt"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 
-	"github.com/tbd54566975/ssi-service/config"
-	cred "github.com/tbd54566975/ssi-service/internal/credential"
+	didint "github.com/tbd54566975/ssi-service/internal/did"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
 	"github.com/tbd54566975/ssi-service/internal/util"
-	"github.com/tbd54566975/ssi-service/pkg/service/credential"
-	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
-	manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
-	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
 
-type Service struct {
-	storage manifeststorage.Storage
-	config  config.ManifestServiceConfig
-
-	// external dependencies
-	keyStore   *keystore.Service
-	resolver   *didsdk.Resolver
-	credential *credential.Service
-}
-
-func (s Service) Type() framework.Type {
-	return framework.Manifest
-}
-
-func (s Service) Status() framework.Status {
-	ae := sdkutil.NewAppendError()
-	if s.storage == nil {
-		ae.AppendString("no storage configured")
-	}
-	if s.keyStore == nil {
-		ae.AppendString("no keystore service configured")
-	}
-	if s.resolver == nil {
-		ae.AppendString("no did resolver configured")
-	}
-	if s.credential == nil {
-		ae.AppendString("no credential service configured")
-	}
-	if !ae.IsEmpty() {
-		return framework.Status{
-			Status:  framework.StatusNotReady,
-			Message: fmt.Sprintf("manifest service is not ready: %s", ae.Error().Error()),
-		}
-	}
-	return framework.Status{Status: framework.StatusReady}
-}
-
-func (s Service) Config() config.ManifestServiceConfig {
-	return s.config
-}
-
-func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, didResolver *didsdk.Resolver, credential *credential.Service) (*Service, error) {
-	manifestStorage, err := manifeststorage.NewManifestStorage(s)
-	if err != nil {
-		errMsg := "could not instantiate storage for the manifest service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-	return &Service{
-		storage:    manifestStorage,
-		config:     config,
-		keyStore:   keyStore,
-		resolver:   didResolver,
-		credential: credential,
-	}, nil
-}
-
-func (s Service) CreateManifest(request CreateManifestRequest) (*CreateManifestResponse, error) {
-
-	logrus.Debugf("creating manifest: %+v", request)
-
-	// validate the request
-	m := request.Manifest
-	if err := m.IsValid(); err != nil {
-		return nil, util.LoggingErrorMsg(err, "manifest is not valid")
-	}
-
-	// sign the manifest
-	manifestJWT, err := s.signManifestJWT(m)
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not sign manifest")
-	}
-
-	// store the manifest
-	storageRequest := manifeststorage.StoredManifest{
-		ID:          m.ID,
-		Issuer:      m.Issuer.ID,
-		Manifest:    m,
-		ManifestJWT: *manifestJWT,
-	}
-
-	if err = s.storage.StoreManifest(storageRequest); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not store manifest")
-	}
-
-	// return the result
-	response := CreateManifestResponse{Manifest: m, ManifestJWT: *manifestJWT}
-	return &response, nil
-}
-
 func (s Service) signManifestJWT(m manifest.CredentialManifest) (*keyaccess.JWT, error) {
 	issuerID := m.Issuer.ID
 	gotKey, err := s.keyStore.GetKey(keystore.GetKeyRequest{ID: issuerID})
@@ -125,19 +28,8 @@ func (s Service) signManifestJWT(m manifest.CredentialManifest) (*keyaccess.JWT,
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	// marshal the manifest before signing it as a JWT
-	manifestBytes, err := json.Marshal(m)
-	if err != nil {
-		errMsg := fmt.Sprintf("could not marshal manifest<%s>", m.ID)
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-	var manifestJSON map[string]interface{}
-	if err := json.Unmarshal(manifestBytes, &manifestJSON); err != nil {
-		errMsg := fmt.Sprintf("could not unmarshal manifest<%s>", m.ID)
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-
-	manifestToken, err := keyAccess.Sign(manifestJSON)
+	// signing the manifest as a JWT
+	manifestToken, err := keyAccess.SignJSON(m)
 	if err != nil {
 		errMsg := fmt.Sprintf("could not sign manifest with key<%s>", gotKey.ID)
 		return nil, util.LoggingErrorMsg(err, errMsg)
@@ -145,20 +37,6 @@ func (s Service) signManifestJWT(m manifest.CredentialManifest) (*keyaccess.JWT,
 	return manifestToken, nil
 }
 
-// VerifyManifest verifies a manifest's signature and makes sure the manifest is compliant with the specification
-func (s Service) VerifyManifest(request VerifyManifestRequest) (*VerifyManifestResponse, error) {
-	m, err := s.verifyManifestJWT(request.ManifestJWT)
-	if err != nil {
-		return &VerifyManifestResponse{Verified: false, Reason: "could not verify manifest's signature: " + err.Error()}, nil
-	}
-
-	// check the manifest is valid against its specification
-	if err := m.IsValid(); err != nil {
-		return &VerifyManifestResponse{Verified: false, Reason: "manifest is not valid: " + err.Error()}, nil
-	}
-	return &VerifyManifestResponse{Verified: true}, nil
-}
-
 func (s Service) verifyManifestJWT(token keyaccess.JWT) (*manifest.CredentialManifest, error) {
 	parsed, err := jwt.Parse([]byte(token))
 	if err != nil {
@@ -174,282 +52,21 @@ func (s Service) verifyManifestJWT(token keyaccess.JWT) (*manifest.CredentialMan
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 	var parsedManifest manifest.CredentialManifest
-	if err := json.Unmarshal(claimsJSONBytes, &parsedManifest); err != nil {
+	if err = json.Unmarshal(claimsJSONBytes, &parsedManifest); err != nil {
 		errMsg := "could not unmarshal claims into manifest"
 		logrus.WithError(err).Error(errMsg)
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
-	resolved, err := s.resolver.Resolve(parsedManifest.Issuer.ID)
+	kid, pubKey, err := didint.ResolveKeyForDID(s.didResolver, parsedManifest.Issuer.ID)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to resolve manifest issuer's did: %s", parsedManifest.Issuer.ID)
 	}
-	kid, pubKey, err := keyaccess.GetVerificationInformation(resolved.DIDDocument, "")
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not get verification information from manifest")
-	}
 	verifier, err := keyaccess.NewJWKKeyAccessVerifier(kid, pubKey)
 	if err != nil {
 		return nil, util.LoggingErrorMsg(err, "could not create manifest verifier")
 	}
-	if err := verifier.Verify(token); err != nil {
+	if err = verifier.Verify(token); err != nil {
 		return nil, util.LoggingErrorMsg(err, "could not verify the manifest's signature")
 	}
 	return &parsedManifest, nil
 }
-
-func (s Service) GetManifest(request GetManifestRequest) (*GetManifestResponse, error) {
-
-	logrus.Debugf("getting manifest: %s", request.ID)
-
-	gotManifest, err := s.storage.GetManifest(request.ID)
-	if err != nil {
-		errMsg := fmt.Sprintf("could not get manifest: %s", request.ID)
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-
-	response := GetManifestResponse{Manifest: gotManifest.Manifest, ManifestJWT: gotManifest.ManifestJWT}
-	return &response, nil
-}
-
-func (s Service) GetManifests() (*GetManifestsResponse, error) {
-	gotManifests, err := s.storage.GetManifests()
-
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not get manifests(s)")
-	}
-
-	var manifests []GetManifestResponse
-	for _, m := range gotManifests {
-		response := GetManifestResponse{Manifest: m.Manifest, ManifestJWT: m.ManifestJWT}
-		manifests = append(manifests, response)
-	}
-	response := GetManifestsResponse{Manifests: manifests}
-	return &response, nil
-}
-
-func (s Service) DeleteManifest(request DeleteManifestRequest) error {
-
-	logrus.Debugf("deleting manifest: %s", request.ID)
-
-	if err := s.storage.DeleteManifest(request.ID); err != nil {
-		errMsg := fmt.Sprintf("could not delete manifest with id: %s", request.ID)
-		return util.LoggingErrorMsg(err, errMsg)
-	}
-
-	return nil
-}
-
-func (s Service) ProcessApplicationSubmission(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) {
-	// TODO(gabe) validate the application's signature
-
-	credApp := request.Application
-	if err := credApp.IsValid(); err != nil {
-		return nil, util.LoggingErrorMsg(err, "application is not valid")
-	}
-
-	gotManifest, err := s.storage.GetManifest(credApp.ManifestID)
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "problem with retrieving manifest during application validation")
-	}
-	if gotManifest == nil {
-		errMsg := fmt.Sprintf("application is not valid; a manifest does not exist with id: %s", credApp.ManifestID)
-		return nil, util.LoggingNewError(errMsg)
-	}
-
-	// validation
-
-	// first, validate that the application complies with the associated manifest
-	credentialManifest := gotManifest.Manifest
-	if err := manifest.IsValidCredentialApplicationForManifest(credentialManifest, credApp); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not validate application")
-	}
-
-	// next, validate that the credential(s) provided in the application are valid
-	// TODO(neal): this is coming in a future PR after a change to the SDK, and the below will be removed
-	if credentialManifest.PresentationDefinition != nil &&
-		len(credentialManifest.PresentationDefinition.InputDescriptors) > 0 &&
-		len(request.Credentials) == 0 {
-		errMsg := fmt.Sprintf("no credentials provided for application: %s against manifest: %s", credApp.ID, credentialManifest.ID)
-		return nil, util.LoggingNewError(errMsg)
-	}
-
-	// signature and validity checks
-	for _, credentialContainer := range request.Credentials {
-		verificationResult, err := s.credential.VerifyCredential(credential.VerifyCredentialRequest{
-			DataIntegrityCredential: credentialContainer.Credential,
-			CredentialJWT:           credentialContainer.CredentialJWT,
-		})
-		if err != nil {
-			errMsg := fmt.Sprintf("could not verify credential: %s", credentialContainer.Credential.ID)
-			return nil, util.LoggingErrorMsg(err, errMsg)
-		}
-		if !verificationResult.Verified {
-			errMsg := fmt.Sprintf("submitted credential<%s> is not valid: %s", credentialContainer.Credential.ID, verificationResult.Reason)
-			return nil, util.LoggingNewError(errMsg)
-		}
-	}
-
-	// store the application
-	storageRequest := manifeststorage.StoredApplication{
-		ID:          credApp.ID,
-		Application: credApp,
-		ManifestID:  request.Application.ManifestID,
-	}
-
-	if err := s.storage.StoreApplication(storageRequest); err != nil {
-		errMsg := "could not store application"
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-
-	// build the credential response
-	// TODO(gabe) need to check if this can be fulfilled and conditionally return success/denial
-	responseBuilder := manifest.NewCredentialResponseBuilder(request.Application.ManifestID)
-	if err := responseBuilder.SetApplicationID(credApp.ID); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set application id")
-	}
-
-	var creds []cred.Container
-	for _, od := range credentialManifest.OutputDescriptors {
-		credentialRequest := credential.CreateCredentialRequest{
-			Issuer:     credentialManifest.Issuer.ID,
-			Subject:    request.ApplicantDID,
-			JSONSchema: od.Schema,
-			// TODO(gabe) need to add in data here to match the request + schema
-			Data: map[string]interface{}{},
-		}
-
-		credentialResponse, err := s.credential.CreateCredential(credentialRequest)
-		if err != nil {
-			return nil, util.LoggingErrorMsg(err, "could not create credential")
-		}
-
-		creds = append(creds, credentialResponse.Container)
-	}
-
-	// build descriptor map based on credential type
-	var descriptors []exchange.SubmissionDescriptor
-	for i, c := range creds {
-		var format string
-		if c.HasDataIntegrityCredential() {
-			format = string(exchange.LDPVC)
-		}
-		if c.HasJWTCredential() {
-			format = string(exchange.JWTVC)
-		}
-		descriptors = append(descriptors, exchange.SubmissionDescriptor{
-			ID:     c.ID,
-			Format: format,
-			Path:   fmt.Sprintf("$.verifiableCredential[%d]", i),
-		})
-	}
-
-	// set the information for the fulfilled credentials in the response
-	if err = responseBuilder.SetFulfillment(descriptors); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment")
-	}
-	credRes, err := responseBuilder.Build()
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not build response")
-	}
-
-	// store the response we've generated
-	storeResponseRequest := manifeststorage.StoredResponse{
-		ID:         credRes.ID,
-		Response:   *credRes,
-		ManifestID: request.Application.ManifestID,
-	}
-	if err := s.storage.StoreResponse(storeResponseRequest); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not store manifest response")
-	}
-
-	response := SubmitApplicationResponse{Response: *credRes, Credentials: creds}
-	return &response, nil
-}
-
-func (s Service) GetApplication(request GetApplicationRequest) (*GetApplicationResponse, error) {
-
-	logrus.Debugf("getting application: %s", request.ID)
-
-	gotApp, err := s.storage.GetApplication(request.ID)
-	if err != nil {
-		errMsg := fmt.Sprintf("could not get application: %s", request.ID)
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-
-	response := GetApplicationResponse{Application: gotApp.Application}
-	return &response, nil
-}
-
-func (s Service) GetApplications() (*GetApplicationsResponse, error) {
-
-	logrus.Debugf("getting application(s)")
-
-	gotApps, err := s.storage.GetApplications()
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not get application(s)")
-	}
-
-	var apps []manifest.CredentialApplication
-	for _, cred := range gotApps {
-		apps = append(apps, cred.Application)
-	}
-
-	response := GetApplicationsResponse{Applications: apps}
-	return &response, nil
-}
-
-func (s Service) DeleteApplication(request DeleteApplicationRequest) error {
-
-	logrus.Debugf("deleting application: %s", request.ID)
-
-	if err := s.storage.DeleteApplication(request.ID); err != nil {
-		errMsg := fmt.Sprintf("could not delete application with id: %s", request.ID)
-		return util.LoggingErrorMsg(err, errMsg)
-	}
-
-	return nil
-}
-
-func (s Service) GetResponse(request GetResponseRequest) (*GetResponseResponse, error) {
-
-	logrus.Debugf("getting response: %s", request.ID)
-
-	gotResponse, err := s.storage.GetResponse(request.ID)
-	if err != nil {
-		errMsg := fmt.Sprintf("could not get response: %s", request.ID)
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
-
-	response := GetResponseResponse{Response: gotResponse.Response}
-	return &response, nil
-}
-
-func (s Service) GetResponses() (*GetResponsesResponse, error) {
-
-	logrus.Debugf("getting response(s)")
-
-	gotResponses, err := s.storage.GetResponses()
-	if err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not get response(s)")
-	}
-
-	var responses []manifest.CredentialResponse
-	for _, res := range gotResponses {
-		responses = append(responses, res.Response)
-	}
-
-	response := GetResponsesResponse{Responses: responses}
-	return &response, nil
-}
-
-func (s Service) DeleteResponse(request DeleteResponseRequest) error {
-
-	logrus.Debugf("deleting response: %s", request.ID)
-
-	if err := s.storage.DeleteResponse(request.ID); err != nil {
-		errMsg := fmt.Sprintf("could not delete response with id: %s", request.ID)
-		return util.LoggingErrorMsg(err, errMsg)
-	}
-
-	return nil
-}
diff --git a/pkg/service/manifest/model.go b/pkg/service/manifest/model.go
index cce7aec..eca534f 100644
--- a/pkg/service/manifest/model.go
+++ b/pkg/service/manifest/model.go
@@ -1,6 +1,7 @@
 package manifest
 
 import (
+	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
 
 	cred "github.com/tbd54566975/ssi-service/internal/credential"
@@ -10,7 +11,11 @@ import (
 // Manifest
 
 type CreateManifestRequest struct {
-	Manifest manifestsdk.CredentialManifest `json:"manifest" validate:"required"`
+	IssuerDID              string                           `json:"issuerDid" validate:"required"`
+	IssuerName             *string                          `json:"issuerName,omitempty"`
+	OutputDescriptors      []manifestsdk.OutputDescriptor   `json:"outputDescriptors" validate:"required,dive"`
+	ClaimFormat            *exchange.ClaimFormat            `json:"format" validate:"required,dive"`
+	PresentationDefinition *exchange.PresentationDefinition `json:"presentationDefinition,omitempty" validate:"omitempty,dive"`
 }
 
 type CreateManifestResponse struct {
@@ -47,15 +52,17 @@ type DeleteManifestRequest struct {
 // Application
 
 type SubmitApplicationRequest struct {
-	ApplicantDID   string                            `json:"applicantDid" validate:"required"`
-	Application    manifestsdk.CredentialApplication `json:"application" validate:"required"`
-	Credentials    []cred.Container                  `json:"credentials,omitempty"`
-	ApplicationJWT keyaccess.JWT                     `json:"applicationJWT,omitempty" validate:"required"`
+	ApplicantDID    string                            `json:"applicantDid" validate:"required"`
+	Application     manifestsdk.CredentialApplication `json:"application" validate:"required"`
+	Credentials     []cred.Container                  `json:"credentials,omitempty"`
+	ApplicationJWT  keyaccess.JWT                     `json:"applicationJwt,omitempty" validate:"required"`
+	ApplicationJSON map[string]interface{}            `json:"applicationJson,omitempty"`
 }
 
 type SubmitApplicationResponse struct {
-	Response    manifestsdk.CredentialResponse `json:"response"`
-	Credentials []cred.Container               `json:"credentials,omitempty"`
+	Response    manifestsdk.CredentialResponse `json:"response" validate:"required"`
+	Credentials []interface{}                  `json:"credentials,omitempty"`
+	ResponseJWT keyaccess.JWT                  `json:"responseJwt,omitempty" validate:"required"`
 }
 
 type GetApplicationRequest struct {
diff --git a/pkg/service/manifest/response.go b/pkg/service/manifest/response.go
new file mode 100644
index 0000000..6325ff4
--- /dev/null
+++ b/pkg/service/manifest/response.go
@@ -0,0 +1,100 @@
+package manifest
+
+import (
+	"fmt"
+
+	"github.com/TBD54566975/ssi-sdk/credential/exchange"
+	"github.com/TBD54566975/ssi-sdk/credential/manifest"
+
+	cred "github.com/tbd54566975/ssi-service/internal/credential"
+	"github.com/tbd54566975/ssi-service/internal/keyaccess"
+	"github.com/tbd54566975/ssi-service/internal/util"
+	"github.com/tbd54566975/ssi-service/pkg/service/credential"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
+)
+
+func (s Service) signCredentialResponseJWT(signingDID string, r CredentialResponseContainer) (*keyaccess.JWT, error) {
+	gotKey, err := s.keyStore.GetKey(keystore.GetKeyRequest{ID: signingDID})
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get key for signing response with key<%s>", signingDID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	keyAccess, err := keyaccess.NewJWKKeyAccess(gotKey.ID, gotKey.Key)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not create key access for signing response with key<%s>", gotKey.ID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	// signing the response as a JWT
+	responseToken, err := keyAccess.SignJSON(r)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not sign response with key<%s>", gotKey.ID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	return responseToken, nil
+}
+
+func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID string, credManifest manifest.CredentialManifest) (*manifest.CredentialResponse, []cred.Container, error) {
+	// TODO(gabe) need to check if this can be fulfilled and conditionally return success/denial
+	responseBuilder := manifest.NewCredentialResponseBuilder(manifestID)
+	if err := responseBuilder.SetApplicationID(applicationID); err != nil {
+		errMsg := fmt.Sprintf("could not fulfill credential application: could not set application id: %s", applicationID)
+		return nil, nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	var creds []cred.Container
+	for _, od := range credManifest.OutputDescriptors {
+		credentialRequest := credential.CreateCredentialRequest{
+			Issuer:     credManifest.Issuer.ID,
+			Subject:    applicantDID,
+			JSONSchema: od.Schema,
+			// TODO(gabe) need to add in data here to match the request + schema
+			Data: make(map[string]interface{}),
+		}
+
+		credentialResponse, err := s.credential.CreateCredential(credentialRequest)
+		if err != nil {
+			return nil, nil, util.LoggingErrorMsg(err, "could not create credential")
+		}
+
+		creds = append(creds, credentialResponse.Container)
+	}
+
+	// build descriptor map based on credential type
+	var descriptors []exchange.SubmissionDescriptor
+	for i, c := range creds {
+		var format string
+		if c.HasDataIntegrityCredential() {
+			format = string(exchange.LDPVC)
+		}
+		if c.HasJWTCredential() {
+			format = string(exchange.JWTVC)
+		}
+		descriptors = append(descriptors, exchange.SubmissionDescriptor{
+			ID:     c.ID,
+			Format: format,
+			Path:   fmt.Sprintf("$.verifiableCredentials[%d]", i),
+		})
+	}
+
+	// set the information for the fulfilled credentials in the response
+	if err := responseBuilder.SetFulfillment(descriptors); err != nil {
+		return nil, nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment")
+	}
+	credRes, err := responseBuilder.Build()
+	if err != nil {
+		return nil, nil, util.LoggingErrorMsg(err, "could not build response")
+	}
+	return credRes, creds, nil
+}
+
+func buildDenialCredentialResponse(manifestID, applicationID, reason string, failedOutputDescriptorIDs ...string) (*manifest.CredentialResponse, error) {
+	builder := manifest.NewCredentialResponseBuilder(manifestID)
+	if err := builder.SetApplicationID(applicationID); err != nil {
+		return nil, err
+	}
+	if err := builder.SetDenial(reason, failedOutputDescriptorIDs...); err != nil {
+		return nil, err
+	}
+	return builder.Build()
+}
diff --git a/pkg/service/manifest/service.go b/pkg/service/manifest/service.go
new file mode 100644
index 0000000..8d66b0a
--- /dev/null
+++ b/pkg/service/manifest/service.go
@@ -0,0 +1,367 @@
+package manifest
+
+import (
+	"fmt"
+
+	"github.com/TBD54566975/ssi-sdk/credential/manifest"
+	didsdk "github.com/TBD54566975/ssi-sdk/did"
+	sdkutil "github.com/TBD54566975/ssi-sdk/util"
+	"github.com/sirupsen/logrus"
+
+	"github.com/tbd54566975/ssi-service/config"
+	credint "github.com/tbd54566975/ssi-service/internal/credential"
+	"github.com/tbd54566975/ssi-service/internal/util"
+	"github.com/tbd54566975/ssi-service/pkg/service/credential"
+	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
+	manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
+	"github.com/tbd54566975/ssi-service/pkg/storage"
+)
+
+type Service struct {
+	storage manifeststorage.Storage
+	config  config.ManifestServiceConfig
+
+	// external dependencies
+	keyStore    *keystore.Service
+	didResolver *didsdk.Resolver
+	credential  *credential.Service
+}
+
+func (s Service) Type() framework.Type {
+	return framework.Manifest
+}
+
+func (s Service) Status() framework.Status {
+	ae := sdkutil.NewAppendError()
+	if s.storage == nil {
+		ae.AppendString("no storage configured")
+	}
+	if s.keyStore == nil {
+		ae.AppendString("no keystore service configured")
+	}
+	if s.didResolver == nil {
+		ae.AppendString("no did resolver configured")
+	}
+	if s.credential == nil {
+		ae.AppendString("no credential service configured")
+	}
+	if !ae.IsEmpty() {
+		return framework.Status{
+			Status:  framework.StatusNotReady,
+			Message: fmt.Sprintf("manifest service is not ready: %s", ae.Error().Error()),
+		}
+	}
+	return framework.Status{Status: framework.StatusReady}
+}
+
+func (s Service) Config() config.ManifestServiceConfig {
+	return s.config
+}
+
+func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, didResolver *didsdk.Resolver, credential *credential.Service) (*Service, error) {
+	manifestStorage, err := manifeststorage.NewManifestStorage(s)
+	if err != nil {
+		errMsg := "could not instantiate storage for the manifest service"
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	return &Service{
+		storage:     manifestStorage,
+		config:      config,
+		keyStore:    keyStore,
+		didResolver: didResolver,
+		credential:  credential,
+	}, nil
+}
+
+func (s Service) CreateManifest(request CreateManifestRequest) (*CreateManifestResponse, error) {
+
+	logrus.Debugf("creating manifest: %+v", request)
+
+	// validate the request
+	if err := sdkutil.IsValidStruct(request); err != nil {
+		errMsg := fmt.Sprintf("invalid create manifest request: %s", err.Error())
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	// compose a valid manifest
+	builder := manifest.NewCredentialManifestBuilder()
+
+	// set the issuer
+	var issuerName string
+	if request.IssuerName != nil {
+		issuerName = *request.IssuerName
+	}
+	if err := builder.SetIssuer(manifest.Issuer{
+		ID:   request.IssuerDID,
+		Name: issuerName,
+	}); err != nil {
+		errMsg := fmt.Sprintf("could not set issuer<%s> for manifest", request.IssuerDID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	if err := builder.SetClaimFormat(*request.ClaimFormat); err != nil {
+		errMsg := fmt.Sprintf("could not set claim format<%+v> for manifest", request.ClaimFormat)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	if err := builder.SetOutputDescriptors(request.OutputDescriptors); err != nil {
+		errMsg := fmt.Sprintf("could not set output descriptors<%+v> for manifest", request.OutputDescriptors)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	if request.PresentationDefinition != nil {
+		if err := builder.SetPresentationDefinition(*request.PresentationDefinition); err != nil {
+			errMsg := fmt.Sprintf("could not set presentation definition<%+v> for manifest", request.PresentationDefinition)
+			return nil, util.LoggingErrorMsg(err, errMsg)
+		}
+	}
+
+	// build the manifest
+	m, err := builder.Build()
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not build manifest")
+	}
+
+	// sign the manifest
+	manifestJWT, err := s.signManifestJWT(*m)
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not sign manifest")
+	}
+
+	// store the manifest
+	storageRequest := manifeststorage.StoredManifest{
+		ID:          m.ID,
+		Issuer:      m.Issuer.ID,
+		Manifest:    *m,
+		ManifestJWT: *manifestJWT,
+	}
+
+	if err = s.storage.StoreManifest(storageRequest); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not store manifest")
+	}
+
+	// return the result
+	response := CreateManifestResponse{Manifest: *m, ManifestJWT: *manifestJWT}
+	return &response, nil
+}
+
+// VerifyManifest verifies a manifest's signature and makes sure the manifest is compliant with the specification
+func (s Service) VerifyManifest(request VerifyManifestRequest) (*VerifyManifestResponse, error) {
+	m, err := s.verifyManifestJWT(request.ManifestJWT)
+	if err != nil {
+		return &VerifyManifestResponse{Verified: false, Reason: "could not verify manifest's signature: " + err.Error()}, nil
+	}
+
+	// check the manifest is valid against its specification
+	if err := m.IsValid(); err != nil {
+		return &VerifyManifestResponse{Verified: false, Reason: "manifest is not valid: " + err.Error()}, nil
+	}
+	return &VerifyManifestResponse{Verified: true}, nil
+}
+
+func (s Service) GetManifest(request GetManifestRequest) (*GetManifestResponse, error) {
+
+	logrus.Debugf("getting manifest: %s", request.ID)
+
+	gotManifest, err := s.storage.GetManifest(request.ID)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get manifest: %s", request.ID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	response := GetManifestResponse{Manifest: gotManifest.Manifest, ManifestJWT: gotManifest.ManifestJWT}
+	return &response, nil
+}
+
+func (s Service) GetManifests() (*GetManifestsResponse, error) {
+	gotManifests, err := s.storage.GetManifests()
+
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not get manifests(s)")
+	}
+
+	var manifests []GetManifestResponse
+	for _, m := range gotManifests {
+		response := GetManifestResponse{Manifest: m.Manifest, ManifestJWT: m.ManifestJWT}
+		manifests = append(manifests, response)
+	}
+	response := GetManifestsResponse{Manifests: manifests}
+	return &response, nil
+}
+
+func (s Service) DeleteManifest(request DeleteManifestRequest) error {
+
+	logrus.Debugf("deleting manifest: %s", request.ID)
+
+	if err := s.storage.DeleteManifest(request.ID); err != nil {
+		errMsg := fmt.Sprintf("could not delete manifest with id: %s", request.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	return nil
+}
+
+// CredentialResponseContainer represents what is signed over and return for a credential response
+type CredentialResponseContainer struct {
+	Response    manifest.CredentialResponse `json:"credential_response"`
+	Credentials []interface{}               `json:"verifiableCredentials,omitempty"`
+}
+
+func (s Service) ProcessApplicationSubmission(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) {
+	// get the manifest associated with the application
+	manifestID := request.Application.ManifestID
+	gotManifest, err := s.storage.GetManifest(manifestID)
+	applicationID := request.Application.ID
+	if err != nil {
+		errMsg := fmt.Sprintf("problem with retrieving manifest<%s> during application<%s>'s validation", manifestID, applicationID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+	if gotManifest == nil {
+		errMsg := fmt.Sprintf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID)
+		return nil, util.LoggingNewError(errMsg)
+	}
+	credManifest := gotManifest.Manifest
+
+	// validate the application
+	if err = s.validateCredentialApplication(gotManifest.Manifest, request); err != nil {
+		denialResp, err := buildDenialCredentialResponse(manifestID, applicationID, err.Error())
+		if err != nil {
+			return nil, util.LoggingErrorMsg(err, "could not build denial credential response")
+		}
+		return &SubmitApplicationResponse{Response: *denialResp}, nil
+	}
+
+	// store the application
+	applicantDID := request.ApplicantDID
+	storageRequest := manifeststorage.StoredApplication{
+		ID:             applicationID,
+		ManifestID:     manifestID,
+		ApplicantDID:   applicantDID,
+		Application:    request.Application,
+		Credentials:    request.Credentials,
+		ApplicationJWT: request.ApplicationJWT,
+	}
+	if err = s.storage.StoreApplication(storageRequest); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not store application")
+	}
+
+	// build the credential response
+	credResp, creds, err := s.buildCredentialResponse(applicantDID, manifestID, applicationID, credManifest)
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not build credential response")
+	}
+
+	// prepare credentials for the response
+	credentials := credint.ContainersToInterface(creds)
+
+	// sign the response before returning
+	responseJWT, err := s.signCredentialResponseJWT(gotManifest.Issuer, CredentialResponseContainer{
+		Response:    *credResp,
+		Credentials: credentials,
+	})
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not sign credential response")
+	}
+
+	// store the response we've generated
+	storeResponseRequest := manifeststorage.StoredResponse{
+		ID:           credResp.ID,
+		ManifestID:   manifestID,
+		ApplicantDID: applicantDID,
+		Response:     *credResp,
+		Credentials:  creds,
+		ResponseJWT:  *responseJWT,
+	}
+	if err = s.storage.StoreResponse(storeResponseRequest); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not store manifest response")
+	}
+
+	response := SubmitApplicationResponse{Response: *credResp, Credentials: credentials, ResponseJWT: *responseJWT}
+	return &response, nil
+}
+
+func (s Service) GetApplication(request GetApplicationRequest) (*GetApplicationResponse, error) {
+
+	logrus.Debugf("getting application: %s", request.ID)
+
+	gotApp, err := s.storage.GetApplication(request.ID)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get application: %s", request.ID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	response := GetApplicationResponse{Application: gotApp.Application}
+	return &response, nil
+}
+
+func (s Service) GetApplications() (*GetApplicationsResponse, error) {
+
+	logrus.Debugf("getting application(s)")
+
+	gotApps, err := s.storage.GetApplications()
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not get application(s)")
+	}
+
+	var apps []manifest.CredentialApplication
+	for _, cred := range gotApps {
+		apps = append(apps, cred.Application)
+	}
+
+	response := GetApplicationsResponse{Applications: apps}
+	return &response, nil
+}
+
+func (s Service) DeleteApplication(request DeleteApplicationRequest) error {
+
+	logrus.Debugf("deleting application: %s", request.ID)
+
+	if err := s.storage.DeleteApplication(request.ID); err != nil {
+		errMsg := fmt.Sprintf("could not delete application with id: %s", request.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	return nil
+}
+
+func (s Service) GetResponse(request GetResponseRequest) (*GetResponseResponse, error) {
+
+	logrus.Debugf("getting response: %s", request.ID)
+
+	gotResponse, err := s.storage.GetResponse(request.ID)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get response: %s", request.ID)
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	response := GetResponseResponse{Response: gotResponse.Response}
+	return &response, nil
+}
+
+func (s Service) GetResponses() (*GetResponsesResponse, error) {
+
+	logrus.Debugf("getting response(s)")
+
+	gotResponses, err := s.storage.GetResponses()
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not get response(s)")
+	}
+
+	var responses []manifest.CredentialResponse
+	for _, res := range gotResponses {
+		responses = append(responses, res.Response)
+	}
+
+	response := GetResponsesResponse{Responses: responses}
+	return &response, nil
+}
+
+func (s Service) DeleteResponse(request DeleteResponseRequest) error {
+
+	logrus.Debugf("deleting response: %s", request.ID)
+
+	if err := s.storage.DeleteResponse(request.ID); err != nil {
+		errMsg := fmt.Sprintf("could not delete response with id: %s", request.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	return nil
+}
diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go
index d36e1a2..ca7d10b 100644
--- a/pkg/service/manifest/storage/storage.go
+++ b/pkg/service/manifest/storage/storage.go
@@ -21,15 +21,19 @@ type StoredManifest struct {
 type StoredApplication struct {
 	ID             string                         `json:"id"`
 	ManifestID     string                         `json:"manifestId"`
+	ApplicantDID   string                         `json:"applicantDid"`
 	Application    manifest.CredentialApplication `json:"application"`
 	Credentials    []cred.Container               `json:"credentials"`
-	ApplicationJWT string                         `json:"applicationJwt"`
+	ApplicationJWT keyaccess.JWT                  `json:"applicationJwt"`
 }
 
 type StoredResponse struct {
-	ID         string                      `json:"id"`
-	Response   manifest.CredentialResponse `json:"response"`
-	ManifestID string                      `json:"manifestId"`
+	ID           string                      `json:"id"`
+	ManifestID   string                      `json:"manifestId"`
+	ApplicantDID string                      `json:"applicantId"`
+	Response     manifest.CredentialResponse `json:"response"`
+	Credentials  []cred.Container            `json:"credentials"`
+	ResponseJWT  keyaccess.JWT               `json:"responseJwt"`
 }
 
 type Storage interface {
diff --git a/pkg/service/schema/schema.go b/pkg/service/schema/service.go
similarity index 98%
rename from pkg/service/schema/schema.go
rename to pkg/service/schema/service.go
index 2d59a18..5f64329 100644
--- a/pkg/service/schema/schema.go
+++ b/pkg/service/schema/service.go
@@ -15,6 +15,7 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/tbd54566975/ssi-service/config"
+	"github.com/tbd54566975/ssi-service/internal/did"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
 	"github.com/tbd54566975/ssi-service/internal/util"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
@@ -215,7 +216,7 @@ func (s Service) verifySchemaJWT(token keyaccess.JWT) (*schema.VCJSONSchema, err
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to resolve schema author's did: %s", parsedSchema.Author)
 	}
-	kid, pubKey, err := keyaccess.GetVerificationInformation(resolved.DIDDocument, "")
+	kid, pubKey, err := did.GetVerificationInformation(resolved.DIDDocument, "")
 	if err != nil {
 		return nil, util.LoggingErrorMsg(err, "could not get verification information from schema")
 	}


Test patch:
diff --git a/pkg/server/router/keystore_test.go b/pkg/server/router/keystore_test.go
index a0636bc..870f21e 100644
--- a/pkg/server/router/keystore_test.go
+++ b/pkg/server/router/keystore_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/TBD54566975/ssi-sdk/crypto"
+	"github.com/mr-tron/base58"
 	"github.com/stretchr/testify/assert"
 
 	"github.com/tbd54566975/ssi-service/config"
@@ -53,10 +54,10 @@ func TestKeyStoreRouter(t *testing.T) {
 
 		// store an invalid key type
 		err = keyStoreService.StoreKey(keystore.StoreKeyRequest{
-			ID:         "test-kid",
-			Type:       "bad",
-			Controller: "me",
-			Key:        []byte("bad"),
+			ID:               "test-kid",
+			Type:             "bad",
+			Controller:       "me",
+			PrivateKeyBase58: base58.Encode([]byte("bad")),
 		})
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "unsupported key type: bad")
@@ -67,11 +68,13 @@ func TestKeyStoreRouter(t *testing.T) {
 		assert.NotEmpty(tt, privKey)
 
 		keyID := "did:test:me#key-1"
+		privKeyBytes, err := crypto.PrivKeyToBytes(privKey)
+		assert.NoError(tt, err)
 		err = keyStoreService.StoreKey(keystore.StoreKeyRequest{
-			ID:         keyID,
-			Type:       crypto.Ed25519,
-			Controller: "did:test:me",
-			Key:        privKey,
+			ID:               keyID,
+			Type:             crypto.Ed25519,
+			Controller:       "did:test:me",
+			PrivateKeyBase58: base58.Encode(privKeyBytes),
 		})
 		assert.NoError(tt, err)
 
diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go
index ed85567..228d22b 100644
--- a/pkg/server/router/manifest_test.go
+++ b/pkg/server/router/manifest_test.go
@@ -9,10 +9,12 @@ import (
 	"github.com/TBD54566975/ssi-sdk/crypto"
 	didsdk "github.com/TBD54566975/ssi-sdk/did"
 	"github.com/google/uuid"
+	"github.com/mr-tron/base58"
 	"github.com/stretchr/testify/assert"
 
 	"github.com/tbd54566975/ssi-service/config"
 	credmodel "github.com/tbd54566975/ssi-service/internal/credential"
+	"github.com/tbd54566975/ssi-service/internal/keyaccess"
 	"github.com/tbd54566975/ssi-service/pkg/service/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/did"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
@@ -98,7 +100,6 @@ func TestManifestRouter(t *testing.T) {
 
 		// good manifest request, which asks for a single verifiable credential in the VC-JWT format
 		createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, createdSchema.ID)
-
 		createdManifest, err := manifestService.CreateManifest(createManifestRequest)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, createdManifest)
@@ -116,59 +117,69 @@ func TestManifestRouter(t *testing.T) {
 			ID:            createdCred.ID,
 			CredentialJWT: createdCred.CredentialJWT,
 		}}
-		createApplicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
+		applicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
 			m.PresentationDefinition.InputDescriptors[0].ID, containers)
 
-		createdApplicationResponse, err := manifestService.ProcessApplicationSubmission(createApplicationRequest)
+		// sign application
+		applicantPrivKeyBytes, err := base58.Decode(applicantDID.PrivateKeyBase58)
+		assert.NoError(tt, err)
+		applicantPrivKey, err := crypto.BytesToPrivKey(applicantPrivKeyBytes, applicantDID.KeyType)
+		assert.NoError(tt, err)
+		signer, err := keyaccess.NewJWKKeyAccess(applicantDID.DID.ID, applicantPrivKey)
+		assert.NoError(tt, err)
+		signed, err := signer.SignJSON(applicationRequest)
+		assert.NoError(tt, err)
+
+		submitApplicationRequest := SubmitApplicationRequest{ApplicationJWT: *signed}
+		sar, err := submitApplicationRequest.ToServiceRequest()
+		assert.NoError(tt, err)
+		createdApplicationResponse, err := manifestService.ProcessApplicationSubmission(*sar)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, createdManifest)
 		assert.NotEmpty(tt, createdApplicationResponse.Response.ID)
-		assert.Equal(tt, len(createManifestRequest.Manifest.OutputDescriptors), len(createdApplicationResponse.Credentials))
+		assert.Equal(tt, len(createManifestRequest.OutputDescriptors), len(createdApplicationResponse.Credentials))
 	})
 }
 
 // getValidManifestRequest returns a valid manifest request, expecting a single JWT-VC EdDSA credential
 func getValidManifestRequest(issuerDID, schemaID string) manifest.CreateManifestRequest {
 	createManifestRequest := manifest.CreateManifestRequest{
-		Manifest: manifestsdk.CredentialManifest{
-			ID:          "WA-DL-CLASS-A",
-			SpecVersion: manifestsdk.SpecVersion,
-			Issuer: manifestsdk.Issuer{
-				ID: issuerDID,
-			},
-			PresentationDefinition: &exchange.PresentationDefinition{
-				ID: "id123",
-				InputDescriptors: []exchange.InputDescriptor{
-					{
-						ID: "test-id",
-						Constraints: &exchange.Constraints{
-							Fields: []exchange.Field{
-								{
-									Path: []string{".verifiableCredential.id"},
-								},
+		IssuerDID: issuerDID,
+		ClaimFormat: &exchange.ClaimFormat{
+			JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+		},
+		PresentationDefinition: &exchange.PresentationDefinition{
+			ID: "id123",
+			InputDescriptors: []exchange.InputDescriptor{
+				{
+					ID: "test-id",
+					Constraints: &exchange.Constraints{
+						Fields: []exchange.Field{
+							{
+								Path: []string{"$.credentialSubject.licenseType"},
 							},
 						},
-						Format: &exchange.ClaimFormat{
-							JWTVC: &exchange.JWTType{
-								Alg: []crypto.SignatureAlgorithm{crypto.EdDSA},
-							},
+					},
+					Format: &exchange.ClaimFormat{
+						JWTVC: &exchange.JWTType{
+							Alg: []crypto.SignatureAlgorithm{crypto.EdDSA},
 						},
 					},
 				},
 			},
-			OutputDescriptors: []manifestsdk.OutputDescriptor{
-				{
-					ID:          "id1",
-					Schema:      schemaID,
-					Name:        "good ID",
-					Description: "it's all good",
-				},
-				{
-					ID:          "id2",
-					Schema:      schemaID,
-					Name:        "good ID",
-					Description: "it's all good",
-				},
+		},
+		OutputDescriptors: []manifestsdk.OutputDescriptor{
+			{
+				ID:          "id1",
+				Schema:      schemaID,
+				Name:        "good ID",
+				Description: "it's all good",
+			},
+			{
+				ID:          "id2",
+				Schema:      schemaID,
+				Name:        "good ID",
+				Description: "it's all good",
 			},
 		},
 	}
@@ -176,13 +187,13 @@ func getValidManifestRequest(issuerDID, schemaID string) manifest.CreateManifest
 	return createManifestRequest
 }
 
-func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionDescriptorID string, credentials []credmodel.Container) manifest.SubmitApplicationRequest {
+func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionDescriptorID string, credentials []credmodel.Container) manifestsdk.CredentialApplicationWrapper {
 	createApplication := manifestsdk.CredentialApplication{
 		ID:          uuid.New().String(),
 		SpecVersion: manifestsdk.SpecVersion,
 		ManifestID:  manifestID,
 		Format: &exchange.ClaimFormat{
-			JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+			JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
 		},
 		PresentationSubmission: &exchange.PresentationSubmission{
 			ID:           "psid",
@@ -191,16 +202,15 @@ func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionD
 				{
 					ID:     submissionDescriptorID,
 					Format: exchange.JWTVC.String(),
-					Path:   "$.verifiableCredential[0]",
+					Path:   "$.verifiableCredentials[0]",
 				},
 			},
 		},
 	}
 
-	// TODO(gabe) sign the request
-	return manifest.SubmitApplicationRequest{
-		ApplicantDID: applicantDID,
-		Application:  createApplication,
-		Credentials:  credentials,
+	creds := credmodel.ContainersToInterface(credentials)
+	return manifestsdk.CredentialApplicationWrapper{
+		CredentialApplication: createApplication,
+		Credentials:           creds,
 	}
 }
diff --git a/pkg/server/server_dwn_test.go b/pkg/server/server_dwn_test.go
index 5ce22ba..52e4b60 100644
--- a/pkg/server/server_dwn_test.go
+++ b/pkg/server/server_dwn_test.go
@@ -74,7 +74,7 @@ func TestDWNAPI(t *testing.T) {
 
 		w = httptest.NewRecorder()
 
-		dwnRequest := router.PublishManifestRequest{ManifestID: "WA-DL-CLASS-A"}
+		dwnRequest := router.PublishManifestRequest{ManifestID: resp.Manifest.ID}
 		dwnRequestValue := newRequestValue(tt, dwnRequest)
 		dwnReq := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dwn/manifests", dwnRequestValue)
 		err = dwnService.PublishManifest(newRequestContext(), w, dwnReq)
diff --git a/pkg/server/server_keystore_test.go b/pkg/server/server_keystore_test.go
index 6357042..1df30d4 100644
--- a/pkg/server/server_keystore_test.go
+++ b/pkg/server/server_keystore_test.go
@@ -36,7 +36,7 @@ func TestKeyStoreAPI(t *testing.T) {
 			ID:               "test-kid",
 			Type:             "bad",
 			Controller:       "me",
-			Base58PrivateKey: "bad",
+			PrivateKeyBase58: "bad",
 		}
 		badRequestValue := newRequestValue(tt, badKeyStoreRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", badRequestValue)
@@ -60,7 +60,7 @@ func TestKeyStoreAPI(t *testing.T) {
 			ID:               "did:test:me#key-1",
 			Type:             crypto.Ed25519,
 			Controller:       "did:test:me",
-			Base58PrivateKey: base58.Encode(privKeyBytes),
+			PrivateKeyBase58: base58.Encode(privKeyBytes),
 		}
 		requestValue := newRequestValue(tt, storeKeyRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", requestValue)
@@ -96,7 +96,7 @@ func TestKeyStoreAPI(t *testing.T) {
 			ID:               keyID,
 			Type:             crypto.Ed25519,
 			Controller:       controller,
-			Base58PrivateKey: base58.Encode(privKeyBytes),
+			PrivateKeyBase58: base58.Encode(privKeyBytes),
 		}
 		requestValue := newRequestValue(tt, storeKeyRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", requestValue)
diff --git a/pkg/server/server_manifest_test.go b/pkg/server/server_manifest_test.go
index 4d8f8d4..27d9445 100644
--- a/pkg/server/server_manifest_test.go
+++ b/pkg/server/server_manifest_test.go
@@ -10,9 +10,12 @@ import (
 	"github.com/TBD54566975/ssi-sdk/crypto"
 	didsdk "github.com/TBD54566975/ssi-sdk/did"
 	"github.com/goccy/go-json"
+	"github.com/mr-tron/base58"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	credmodel "github.com/tbd54566975/ssi-service/internal/credential"
+	"github.com/tbd54566975/ssi-service/internal/keyaccess"
 	"github.com/tbd54566975/ssi-service/pkg/server/router"
 	"github.com/tbd54566975/ssi-service/pkg/service/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/did"
@@ -348,7 +351,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// missing required field: Application
 		badManifestRequest := router.SubmitApplicationRequest{
-			ApplicantDID: "did:example:abcd",
+			ApplicationJWT: "bad",
 		}
 
 		badRequestValue := newRequestValue(tt, badManifestRequest)
@@ -419,10 +422,21 @@ func TestManifestAPI(t *testing.T) {
 		assert.Equal(tt, m.Issuer.ID, issuerDID.DID.ID)
 
 		// good application request
-		createApplicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
-			m.PresentationDefinition.InputDescriptors[0].ID, []interface{}{createdCred.CredentialJWT})
+		container := []credmodel.Container{{CredentialJWT: createdCred.CredentialJWT}}
+		applicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
+			m.PresentationDefinition.InputDescriptors[0].ID, container)
 
-		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		// sign application
+		applicantPrivKeyBytes, err := base58.Decode(applicantDID.PrivateKeyBase58)
+		assert.NoError(tt, err)
+		applicantPrivKey, err := crypto.BytesToPrivKey(applicantPrivKeyBytes, applicantDID.KeyType)
+		assert.NoError(tt, err)
+		signer, err := keyaccess.NewJWKKeyAccess(applicantDID.DID.ID, applicantPrivKey)
+		assert.NoError(tt, err)
+		signed, err := signer.SignJSON(applicationRequest)
+		assert.NoError(tt, err)
+
+		applicationRequestValue := newRequestValue(tt, router.SubmitApplicationRequest{ApplicationJWT: *signed})
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
 		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
@@ -517,10 +531,21 @@ func TestManifestAPI(t *testing.T) {
 		assert.Equal(tt, m.Issuer.ID, issuerDID.DID.ID)
 
 		// good application request
-		createApplicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
-			m.PresentationDefinition.InputDescriptors[0].ID, []interface{}{createdCred.CredentialJWT})
+		container := []credmodel.Container{{CredentialJWT: createdCred.CredentialJWT}}
+		applicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
+			m.PresentationDefinition.InputDescriptors[0].ID, container)
+
+		// sign application
+		applicantPrivKeyBytes, err := base58.Decode(applicantDID.PrivateKeyBase58)
+		assert.NoError(tt, err)
+		applicantPrivKey, err := crypto.BytesToPrivKey(applicantPrivKeyBytes, applicantDID.KeyType)
+		assert.NoError(tt, err)
+		signer, err := keyaccess.NewJWKKeyAccess(applicantDID.DID.ID, applicantPrivKey)
+		assert.NoError(tt, err)
+		signed, err := signer.SignJSON(applicationRequest)
+		assert.NoError(tt, err)
 
-		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		applicationRequestValue := newRequestValue(tt, router.SubmitApplicationRequest{ApplicationJWT: *signed})
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
 		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
@@ -528,6 +553,9 @@ func TestManifestAPI(t *testing.T) {
 		err = json.NewDecoder(w.Body).Decode(&appResp)
 		assert.NoError(tt, err)
 
+		assert.NotEmpty(tt, appResp.Response.Fulfillment)
+		assert.Empty(tt, appResp.Response.Denial)
+
 		// get response by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/responses/%s", appResp.Response.ID), nil)
 		err = manifestRouter.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
@@ -648,10 +676,21 @@ func TestManifestAPI(t *testing.T) {
 		assert.Equal(tt, m.Issuer.ID, issuerDID.DID.ID)
 
 		// good application request
-		createApplicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
-			m.PresentationDefinition.InputDescriptors[0].ID, []interface{}{createdCred.CredentialJWT})
+		container := []credmodel.Container{{CredentialJWT: createdCred.CredentialJWT}}
+		applicationRequest := getValidApplicationRequest(applicantDID.DID.ID, m.ID, m.PresentationDefinition.ID,
+			m.PresentationDefinition.InputDescriptors[0].ID, container)
+
+		// sign application
+		applicantPrivKeyBytes, err := base58.Decode(applicantDID.PrivateKeyBase58)
+		assert.NoError(tt, err)
+		applicantPrivKey, err := crypto.BytesToPrivKey(applicantPrivKeyBytes, applicantDID.KeyType)
+		assert.NoError(tt, err)
+		signer, err := keyaccess.NewJWKKeyAccess(applicantDID.DID.ID, applicantPrivKey)
+		assert.NoError(tt, err)
+		signed, err := signer.SignJSON(applicationRequest)
+		assert.NoError(tt, err)
 
-		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		applicationRequestValue := newRequestValue(tt, router.SubmitApplicationRequest{ApplicationJWT: *signed})
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
 		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go
index 1bbb9f2..dc8ad49 100644
--- a/pkg/server/server_test.go
+++ b/pkg/server/server_test.go
@@ -12,6 +12,7 @@ import (
 
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 
+	credmodel "github.com/tbd54566975/ssi-service/internal/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/dwn"
 
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
@@ -119,40 +120,37 @@ func newRequestContextWithParams(params map[string]string) context.Context {
 
 func getValidManifestRequest(issuerDID, schemaID string) manifest.CreateManifestRequest {
 	createManifestRequest := manifest.CreateManifestRequest{
-		Manifest: manifestsdk.CredentialManifest{
-			ID:          "WA-DL-CLASS-A",
-			SpecVersion: manifestsdk.SpecVersion,
-			Issuer: manifestsdk.Issuer{
-				ID: issuerDID,
-			},
-			PresentationDefinition: &exchange.PresentationDefinition{
-				ID: "id123",
-				InputDescriptors: []exchange.InputDescriptor{
-					{
-						ID: "test-id",
-						Constraints: &exchange.Constraints{
-							Fields: []exchange.Field{
-								{
-									Path: []string{".vc.id"},
-								},
+		IssuerDID: issuerDID,
+		ClaimFormat: &exchange.ClaimFormat{
+			JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+		},
+		PresentationDefinition: &exchange.PresentationDefinition{
+			ID: "id123",
+			InputDescriptors: []exchange.InputDescriptor{
+				{
+					ID: "test-id",
+					Constraints: &exchange.Constraints{
+						Fields: []exchange.Field{
+							{
+								Path: []string{"$.credentialSubject.licenseType"},
 							},
 						},
 					},
 				},
 			},
-			OutputDescriptors: []manifestsdk.OutputDescriptor{
-				{
-					ID:          "id1",
-					Schema:      schemaID,
-					Name:        "good ID",
-					Description: "it's all good",
-				},
-				{
-					ID:          "id2",
-					Schema:      schemaID,
-					Name:        "good ID",
-					Description: "it's all good",
-				},
+		},
+		OutputDescriptors: []manifestsdk.OutputDescriptor{
+			{
+				ID:          "id1",
+				Schema:      schemaID,
+				Name:        "good ID",
+				Description: "it's all good",
+			},
+			{
+				ID:          "id2",
+				Schema:      schemaID,
+				Name:        "good ID",
+				Description: "it's all good",
 			},
 		},
 	}
@@ -160,13 +158,13 @@ func getValidManifestRequest(issuerDID, schemaID string) manifest.CreateManifest
 	return createManifestRequest
 }
 
-func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionDescriptorID string, credentials []interface{}) router.SubmitApplicationRequest {
+func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionDescriptorID string, credentials []credmodel.Container) manifestsdk.CredentialApplicationWrapper {
 	createApplication := manifestsdk.CredentialApplication{
 		ID:          uuid.New().String(),
 		SpecVersion: manifestsdk.SpecVersion,
 		ManifestID:  manifestID,
 		Format: &exchange.ClaimFormat{
-			JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+			JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
 		},
 		PresentationSubmission: &exchange.PresentationSubmission{
 			ID:           "psid",
@@ -175,17 +173,16 @@ func getValidApplicationRequest(applicantDID, manifestID, presDefID, submissionD
 				{
 					ID:     submissionDescriptorID,
 					Format: exchange.JWTVC.String(),
-					Path:   "$.verifiableCredential[0]",
+					Path:   "$.verifiableCredentials[0]",
 				},
 			},
 		},
 	}
 
-	// TODO(gabe) sign the request
-	return router.SubmitApplicationRequest{
-		ApplicantDID: applicantDID,
-		Application:  createApplication,
-		Credentials:  credentials,
+	creds := credmodel.ContainersToInterface(credentials)
+	return manifestsdk.CredentialApplicationWrapper{
+		CredentialApplication: createApplication,
+		Credentials:           creds,
 	}
 }
 
diff --git a/pkg/service/keystore/keystore_test.go b/pkg/service/keystore/service_test.go
similarity index 95%
rename from pkg/service/keystore/keystore_test.go
rename to pkg/service/keystore/service_test.go
index 5e7c7cb..fb1a971 100644
--- a/pkg/service/keystore/keystore_test.go
+++ b/pkg/service/keystore/service_test.go
@@ -115,10 +115,10 @@ func TestStoreAndGetKey(t *testing.T) {
 	// store the key
 	_, privKey, err := crypto.GenerateEd25519Key()
 	err = keyStore.StoreKey(StoreKeyRequest{
-		ID:         "test-id",
-		Type:       crypto.Ed25519,
-		Controller: "test-controller",
-		Key:        privKey,
+		ID:               "test-id",
+		Type:             crypto.Ed25519,
+		Controller:       "test-controller",
+		PrivateKeyBase58: base58.Encode(privKey),
 	})
 	assert.NoError(t, err)
 
diff --git a/test/steelthread.go b/test/steelthread.go
index f89d0c7..fa41208 100644
--- a/test/steelthread.go
+++ b/test/steelthread.go
@@ -4,12 +4,13 @@ import (
 	"bytes"
 	"embed"
 	"fmt"
+	"io"
+	"net/http"
+	"strings"
+
 	"github.com/goccy/go-json"
 	"github.com/oliveagle/jsonpath"
 	"github.com/pkg/errors"
-	"io/ioutil"
-	"net/http"
-	"strings"
 )
 
 const (
@@ -97,6 +98,9 @@ func RunTest() error {
 	applicationJSON := getJSONFromFile("application-input.json")
 	applicationJSON = strings.Replace(applicationJSON, "<DEFINITIONID>", presentationDefinitionID, -1)
 	applicationJSON = strings.Replace(applicationJSON, "<VCJWT>", credentialJWT, -1)
+
+	// sign the application as a jwt
+
 	output, err = put(endpoint+version+"manifests/applications", applicationJSON)
 	if err != nil {
 		return errors.Wrapf(err, "problem with application endpoint with output: %s", output)
@@ -109,8 +113,7 @@ func RunTest() error {
 
 func getJSONElement(jsonString string, jsonPath string) (string, error) {
 	jsonMap := make(map[string]interface{})
-	err := json.Unmarshal([]byte(jsonString), &jsonMap)
-	if err != nil {
+	if err := json.Unmarshal([]byte(jsonString), &jsonMap); err != nil {
 		return "", errors.Wrap(err, "problem with unmarshalling json string")
 	}
 
@@ -128,13 +131,13 @@ func get(url string) (string, error) {
 		return "", errors.Wrap(err, "problem with finding element in json string")
 	}
 
-	body, err := ioutil.ReadAll(resp.Body)
+	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return "", errors.Wrap(err, "problem with parsing body")
 	}
 
-	if resp.StatusCode/100 != 2 {
-		return "", errors.New(fmt.Sprintf("status code not in the 200s. body: %s", string(body)))
+	if is200Response(resp.StatusCode) {
+		return "", fmt.Errorf("status code not in the 200s. body: %s", string(body))
 	}
 
 	return string(body), err
@@ -154,13 +157,13 @@ func put(url string, json string) (string, error) {
 		return "", errors.Wrap(err, "problem client http client")
 	}
 
-	body, err := ioutil.ReadAll(resp.Body)
+	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return "", errors.Wrap(err, "problem with parsing body")
 	}
 
-	if resp.StatusCode/100 != 2 {
-		return "", errors.New(fmt.Sprintf("status code not in the 200s. body: %s", string(body)))
+	if is200Response(resp.StatusCode) {
+		return "", fmt.Errorf("status code not in the 200s. body: %s", string(body))
 	}
 
 	return string(body), err
@@ -170,3 +173,7 @@ func getJSONFromFile(fileName string) string {
 	b, _ := testVectors.ReadFile("testdata/" + fileName)
 	return string(b)
 }
+
+func is200Response(statusCode int) bool {
+	return statusCode/100 != 2
+}