Repository: TBD54566975/ssi-service
Pull request #240 (2023-01-06 18:01:16)

ReviewApplication endpoint for fulfilling or denying applications
# Overview
The existing SubmitApplication endpoint was updated so it returns an Operation that is not done. In order to mark the operation as done, it needs to be cancelled, or the application needs to be reviewed. This PR does the latter. Note that when an application is reviewed, the application's status is updated and a response is also recorded in the DB. 

# How Has This Been Tested?
As this doesn't introduce new functionality, the existing tests suffice.

# Tracking
OSE-203

codecov-commenter: # [Codecov](https://codecov.io/gh/TBD54566975/ssi-service/pull/240?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) Report
> Merging [#240](https://codecov.io/gh/TBD54566975/ssi-service/pull/240?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (2ed6d2f) into [main](https://codecov.io/gh/TBD54566975/ssi-service/commit/866989907df585c93656c336be56d0037e2b0a3f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (8669899) will **decrease** coverage by `0.20%`.
> The diff coverage is `3.57%`.

> :exclamation: Current head 2ed6d2f differs from pull request most recent head 89453c7. Consider uploading reports for the commit 89453c7 to get more accurate results

```diff
@@            Coverage Diff             @@
##             main     #240      +/-   ##
==========================================
- Coverage   24.99%   24.79%   -0.21%     
==========================================
  Files          31       31              
  Lines        2969     2997      +28     
==========================================
+ Hits          742      743       +1     
- Misses       2105     2132      +27     
  Partials      122      122              
```


| [Impacted Files](https://codecov.io/gh/TBD54566975/ssi-service/pull/240?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) | Coverage Δ | |
|---|---|---|
| [pkg/server/router/manifest.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/240?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvbWFuaWZlc3QuZ28=) | `9.81% <0.00%> (-1.07%)` | :arrow_down: |
| [pkg/server/server.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/240?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9zZXJ2ZXIuZ28=) | `81.86% <100.00%> (+0.10%)` | :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: noticed the e2e test failing - is that new? cc: @nitro-neal 

Patch:
diff --git a/doc/swagger.yaml b/doc/swagger.yaml
index 3493539..56298ac 100644
--- a/doc/swagger.yaml
+++ b/doc/swagger.yaml
@@ -1,16 +1,4 @@
 definitions:
-  credential.Container:
-    properties:
-      credential:
-        $ref: '#/definitions/credential.VerifiableCredential'
-      credentialJWT:
-        type: string
-      id:
-        description: Credential ID
-        type: string
-      revoked:
-        type: boolean
-    type: object
   credential.CredentialSchema:
     properties:
       id:
@@ -68,7 +56,8 @@ definitions:
         $ref: '#/definitions/credential.CredentialSchema'
       credentialStatus: {}
       credentialSubject:
-        $ref: '#/definitions/credential.CredentialSubject'
+        allOf:
+        - $ref: '#/definitions/credential.CredentialSubject'
         description: This is where the subject's ID *may* be present
       evidence:
         items: {}
@@ -101,6 +90,26 @@ definitions:
     - issuer
     - type
     type: object
+  crypto.KeyType:
+    enum:
+    - Ed25519
+    - X25519
+    - secp256k1
+    - P-224
+    - P-256
+    - P-384
+    - P-521
+    - RSA
+    type: string
+    x-enum-varnames:
+    - Ed25519
+    - X25519
+    - SECP256k1
+    - P224
+    - P256
+    - P384
+    - P521
+    - RSA
   crypto.PublicKeyJWK:
     properties:
       alg:
@@ -126,6 +135,20 @@ definitions:
     required:
     - kty
     type: object
+  crypto.SignatureAlgorithm:
+    enum:
+    - EdDSA
+    - ES256K
+    - ES256
+    - ES384
+    - PS256
+    type: string
+    x-enum-varnames:
+    - EdDSA
+    - ES256K
+    - ES256
+    - ES384
+    - PS256
   did.DIDDocument:
     properties:
       '@context': {}
@@ -155,7 +178,7 @@ definitions:
         type: array
       service:
         items:
-          $ref: '#/definitions/did.Service'
+          $ref: '#/definitions/github_com_TBD54566975_ssi-sdk_did.Service'
         type: array
       verificationMethod:
         items:
@@ -188,6 +211,18 @@ definitions:
       error:
         $ref: '#/definitions/did.ResolutionError'
     type: object
+  did.Method:
+    enum:
+    - key
+    - peer
+    - pkh
+    - web
+    type: string
+    x-enum-varnames:
+    - KeyMethod
+    - PeerMethod
+    - PKHMethod
+    - WebMethod
   did.ResolutionError:
     properties:
       code:
@@ -199,8 +234,6 @@ definitions:
       representationNotSupported:
         type: boolean
     type: object
-  did.Service:
-    type: object
   did.VerificationMethod:
     properties:
       blockchainAccountId:
@@ -213,7 +246,8 @@ definitions:
       publicKeyBase58:
         type: string
       publicKeyJwk:
-        $ref: '#/definitions/crypto.PublicKeyJWK'
+        allOf:
+        - $ref: '#/definitions/crypto.PublicKeyJWK'
         description: must conform to https://datatracker.ietf.org/doc/html/rfc7517
       publicKeyMultibase:
         description: https://datatracker.ietf.org/doc/html/draft-multiformats-multibase-03
@@ -249,38 +283,34 @@ definitions:
       is_holder:
         $ref: '#/definitions/exchange.RelationalConstraint'
       limit_disclosure:
-        description: |-
-          If a predicate property is present, filter must be too
-          https://identity.foundation/presentation-exchange/#predicate-feature
-        type: string
+        $ref: '#/definitions/exchange.Preference'
       same_subject:
         $ref: '#/definitions/exchange.RelationalConstraint'
       statuses:
-        $ref: '#/definitions/exchange.CredentialStatus'
+        allOf:
+        - $ref: '#/definitions/exchange.CredentialStatus'
         description: https://identity.foundation/presentation-exchange/#credential-status-constraint-feature
       subject_is_issuer:
+        allOf:
+        - $ref: '#/definitions/exchange.Preference'
         description: https://identity.foundation/presentation-exchange/#relational-constraint-feature
-        type: string
     type: object
   exchange.CredentialStatus:
     properties:
       active:
         properties:
           directive:
-            description: https://identity.foundation/presentation-exchange/#relational-constraint-feature
-            type: string
+            $ref: '#/definitions/exchange.Preference'
         type: object
       revoked:
         properties:
           directive:
-            description: https://identity.foundation/presentation-exchange/#relational-constraint-feature
-            type: string
+            $ref: '#/definitions/exchange.Preference'
         type: object
       suspended:
         properties:
           directive:
-            description: https://identity.foundation/presentation-exchange/#relational-constraint-feature
-            type: string
+            $ref: '#/definitions/exchange.Preference'
         type: object
     type: object
   exchange.Field:
@@ -300,10 +330,11 @@ definitions:
           type: string
         type: array
       predicate:
+        allOf:
+        - $ref: '#/definitions/exchange.Preference'
         description: |-
           If a predicate property is present, filter must be too
           https://identity.foundation/presentation-exchange/#predicate-feature
-        type: string
       purpose:
         type: string
     required:
@@ -368,7 +399,7 @@ definitions:
     properties:
       alg:
         items:
-          type: string
+          $ref: '#/definitions/crypto.SignatureAlgorithm'
         type: array
     required:
     - alg
@@ -382,6 +413,18 @@ definitions:
     required:
     - proof_type
     type: object
+  exchange.Preference:
+    enum:
+    - required
+    - preferred
+    - allowed
+    - disallowed
+    type: string
+    x-enum-varnames:
+    - Required
+    - Preferred
+    - Allowed
+    - Disallowed
   exchange.PresentationDefinition:
     properties:
       format:
@@ -424,14 +467,21 @@ definitions:
   exchange.RelationalConstraint:
     properties:
       directive:
-        description: https://identity.foundation/presentation-exchange/#relational-constraint-feature
-        type: string
+        $ref: '#/definitions/exchange.Preference'
       field_id:
         type: string
     required:
     - directive
     - field_id
     type: object
+  exchange.Selection:
+    enum:
+    - all
+    - pick
+    type: string
+    x-enum-varnames:
+    - All
+    - Pick
   exchange.SubmissionDescriptor:
     properties:
       format:
@@ -468,11 +518,46 @@ definitions:
       purpose:
         type: string
       rule:
-        type: string
+        $ref: '#/definitions/exchange.Selection'
     required:
     - rule
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest:
+  github_com_TBD54566975_ssi-sdk_did.Service:
+    properties:
+      accept:
+        items:
+          type: string
+        type: array
+      id:
+        type: string
+      routingKeys:
+        items:
+          type: string
+        type: array
+      serviceEndpoint:
+        description: |-
+          A string, map, or set composed of one or more strings and/or maps
+          All string values must be valid URIs
+      type:
+        type: string
+    required:
+    - id
+    - serviceEndpoint
+    - type
+    type: object
+  github_com_tbd54566975_ssi-service_internal_credential.Container:
+    properties:
+      credential:
+        $ref: '#/definitions/credential.VerifiableCredential'
+      credentialJWT:
+        type: string
+      id:
+        description: Credential ID
+        type: string
+      revoked:
+        type: boolean
+    type: object
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest:
     properties:
       '@context':
         description: A context is optional. If not present, we'll apply default, required
@@ -498,32 +583,32 @@ definitions:
     - issuer
     - subject
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse:
     properties:
       credential:
         $ref: '#/definitions/credential.VerifiableCredential'
       credentialJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodRequest:
     properties:
       didWebId:
         type: string
       keyType:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     required:
     - keyType
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateDIDByMethodResponse:
     properties:
       did:
         $ref: '#/definitions/did.DIDDocument'
       keyType:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
       privateKeyBase58:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest:
     properties:
       credentialManifest:
         description: ID of the credential manifest that this template corresponds
@@ -532,13 +617,19 @@ definitions:
       credentials:
         description: Info required to create a credential from a credential application.
         items:
-          $ref: '#/definitions/issuing.CredentialTemplate'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate'
         type: array
+      id:
+        description: ID of this template.
+        type: string
       issuer:
         description: ID of the issuer that will be issuing the credentials.
         type: string
+    required:
+    - credentialManifest
+    - issuer
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest:
     properties:
       description:
         type: string
@@ -561,14 +652,14 @@ definitions:
     - issuerDid
     - outputDescriptors
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse:
     properties:
       credential_manifest:
         $ref: '#/definitions/manifest.CredentialManifest'
       manifestJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest:
     properties:
       format:
         $ref: '#/definitions/exchange.ClaimFormat'
@@ -587,12 +678,12 @@ definitions:
     required:
     - inputDescriptors
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse:
     properties:
       presentation_definition:
         $ref: '#/definitions/exchange.PresentationDefinition'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaRequest:
     properties:
       author:
         type: string
@@ -609,7 +700,7 @@ definitions:
     - name
     - schema
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateSchemaResponse:
     properties:
       id:
         type: string
@@ -618,28 +709,28 @@ definitions:
       schemaJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest:
     properties:
       submissionJwt:
         type: string
     required:
     - submissionJwt
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse:
     properties:
       application:
         $ref: '#/definitions/manifest.CredentialApplication'
       id:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetApplicationsResponse:
     properties:
       applications:
         items:
           $ref: '#/definitions/manifest.CredentialApplication'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse:
     properties:
       credential:
         $ref: '#/definitions/credential.VerifiableCredential'
@@ -648,7 +739,7 @@ definitions:
       id:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse:
     properties:
       credential:
         $ref: '#/definitions/credential.VerifiableCredential'
@@ -657,43 +748,43 @@ definitions:
       id:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse:
     properties:
       revoked:
         type: boolean
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse:
     properties:
       credentials:
         items:
-          $ref: '#/definitions/credential.Container'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetDIDByMethodResponse:
     properties:
       did:
         $ref: '#/definitions/did.DIDDocument'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetDIDMethodsResponse:
     properties:
       methods:
         items:
-          type: string
+          $ref: '#/definitions/did.Method'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetDIDsByMethodResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetDIDsByMethodResponse:
     properties:
       dids:
         items:
           $ref: '#/definitions/did.DIDDocument'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse:
     properties:
       status:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse:
     properties:
       controller:
         type: string
@@ -702,9 +793,9 @@ definitions:
       id:
         type: string
       type:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse:
     properties:
       credential_manifest:
         $ref: '#/definitions/manifest.CredentialManifest'
@@ -713,14 +804,14 @@ definitions:
       manifestJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse:
     properties:
       manifests:
         items:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetOperationsRequest:
     properties:
       filter:
         description: |-
@@ -731,47 +822,47 @@ definitions:
         description: 'The name of the parent''s resource. For example: "/presentation/submissions".'
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetOperationsResponse:
     properties:
       operations:
         items:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.Operation'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse:
     properties:
       presentation_definition:
         $ref: '#/definitions/exchange.PresentationDefinition'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse:
     properties:
       id:
         type: string
       response:
         $ref: '#/definitions/manifest.CredentialResponse'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetResponsesResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetResponsesResponse:
     properties:
       responses:
         items:
           $ref: '#/definitions/manifest.CredentialResponse'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse:
     properties:
       schema:
         $ref: '#/definitions/schema.VCJSONSchema'
       schemaJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemasResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemasResponse:
     properties:
       schemas:
         items:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse:
     properties:
       definition_id:
         type: string
@@ -793,14 +884,14 @@ definitions:
     - id
     - status
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ListIssuanceTemplatesResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ListIssuanceTemplatesResponse:
     properties:
       issuanceTemplates:
         items:
-          $ref: '#/definitions/issuing.IssuanceTemplate'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest:
     properties:
       filter:
         description: |-
@@ -808,14 +899,14 @@ definitions:
           For example: `status = "done"`.
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse:
     properties:
       submissions:
         items:
-          $ref: '#/definitions/model.Submission'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission'
         type: array
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.Operation:
+  github_com_tbd54566975_ssi-service_pkg_server_router.Operation:
     properties:
       done:
         description: Whether this operation has finished.
@@ -824,10 +915,11 @@ definitions:
         description: The name of the resource related to this operation. E.g. "presentations/submissions/<uuid>"
         type: string
       result:
-        $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.OperationResult'
+        allOf:
+        - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.OperationResult'
         description: Populated if Done == true.
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.OperationResult:
+  github_com_tbd54566975_ssi-service_pkg_server_router.OperationResult:
     properties:
       error:
         description: Populated when there was an error with the operation.
@@ -836,7 +928,7 @@ definitions:
         description: Populated iff Error == "". The type should be specified in the
           calling APIs documentation.
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse:
     properties:
       didDocument:
         $ref: '#/definitions/did.DIDDocument'
@@ -845,7 +937,14 @@ definitions:
       didResolutionMetadata:
         $ref: '#/definitions/did.DIDResolutionMetadata'
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ReviewApplicationRequest:
+    properties:
+      approved:
+        type: boolean
+      reason:
+        type: string
+    type: object
+  github_com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest:
     properties:
       approved:
         type: boolean
@@ -854,7 +953,7 @@ definitions:
     required:
     - approved
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse:
     properties:
       definition_id:
         type: string
@@ -876,7 +975,7 @@ definitions:
     - id
     - status
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest:
     properties:
       base58PrivateKey:
         type: string
@@ -885,61 +984,71 @@ definitions:
       id:
         type: string
       type:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     required:
     - base58PrivateKey
     - controller
     - id
     - type
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest:
     properties:
       applicationJwt:
         type: string
     required:
     - applicationJwt
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationResponse:
+    properties:
+      credential_response:
+        $ref: '#/definitions/manifest.CredentialResponse'
+      responseJwt:
+        type: string
+      verifiableCredentials:
+        description: this is an interface type to union Data Integrity and JWT style
+          VCs
+    type: object
+  github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest:
     properties:
       revoked:
         type: boolean
     required:
     - revoked
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse:
     properties:
       revoked:
         type: boolean
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest:
     properties:
       credential:
         $ref: '#/definitions/credential.VerifiableCredential'
       credentialJwt:
         type: string
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse:
     properties:
       reason:
         type: string
       verified:
         type: boolean
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaRequest:
+  github_com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaRequest:
     properties:
       schemaJwt:
         type: string
     required:
     - schemaJwt
     type: object
-  github.com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaResponse:
+  github_com_tbd54566975_ssi-service_pkg_server_router.VerifySchemaResponse:
     properties:
       reason:
         type: string
       verified:
         type: boolean
     type: object
-  issuing.ClaimTemplates:
+  github_com_tbd54566975_ssi-service_pkg_service_issuing.ClaimTemplates:
     properties:
       data:
         additionalProperties: {}
@@ -948,13 +1057,15 @@ definitions:
           claim about the credentialSubject in the credential that will be issued.
         type: object
     type: object
-  issuing.CredentialTemplate:
+  github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate:
     properties:
       data:
-        $ref: '#/definitions/issuing.CredentialTemplateData'
+        allOf:
+        - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplateData'
         description: Date that will be used to determine credential claims.
       expiry:
-        $ref: '#/definitions/issuing.TimeLike'
+        allOf:
+        - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.TimeLike'
         description: Parameter to determine the expiry of the credential.
       id:
         description: ID corresponding to an OutputDescriptor.ID from the manifest.
@@ -966,24 +1077,19 @@ definitions:
         description: ID of the CredentialSchema to be used for the issued credential.
         type: string
     type: object
-  issuing.CredentialTemplateData:
+  github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplateData:
     properties:
       claims:
-        $ref: '#/definitions/issuing.ClaimTemplates'
+        allOf:
+        - $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.ClaimTemplates'
         description: The set of information that will be used to create claims.
       credentialInputDescriptor:
         description: |-
-          ID of the input descriptor in the application. Correponds to one of the
+          Optional. When present, it's the ID of the input descriptor in the application. Corresponds to one of the
           PresentationDefinition.InputDescriptors[].ID in the credential manifest.
         type: string
     type: object
-  issuing.GetIssuanceTemplateResponse:
-    properties:
-      issuanceTemplate:
-        $ref: '#/definitions/issuing.IssuanceTemplate'
-        description: The template that was requested.
-    type: object
-  issuing.IssuanceTemplate:
+  github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate:
     properties:
       credentialManifest:
         description: ID of the credential manifest that this template corresponds
@@ -992,19 +1098,49 @@ definitions:
       credentials:
         description: Info required to create a credential from a credential application.
         items:
-          $ref: '#/definitions/issuing.CredentialTemplate'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate'
         type: array
+      id:
+        description: ID of this template.
+        type: string
       issuer:
         description: ID of the issuer that will be issuing the credentials.
         type: string
+    required:
+    - credentialManifest
+    - issuer
     type: object
-  issuing.TimeLike:
+  github_com_tbd54566975_ssi-service_pkg_service_issuing.TimeLike:
     properties:
-      time.Duration:
+      duration:
+        description: For a fixed offset from when it was issued.
         type: integer
-      time.Time:
+      time:
+        description: For fixed time in the future.
         type: string
     type: object
+  github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission:
+    properties:
+      definition_id:
+        type: string
+      descriptor_map:
+        items:
+          $ref: '#/definitions/exchange.SubmissionDescriptor'
+        type: array
+      id:
+        type: string
+      reason:
+        description: The reason why the submission was approved or denied.
+        type: string
+      status:
+        description: One of {`pending`, `approved`, `denied`, `cancelled`}.
+        type: string
+    required:
+    - definition_id
+    - descriptor_map
+    - id
+    - status
+    type: object
   manifest.CredentialApplication:
     properties:
       format:
@@ -1014,7 +1150,8 @@ definitions:
       manifest_id:
         type: string
       presentation_submission:
-        $ref: '#/definitions/exchange.PresentationSubmission'
+        allOf:
+        - $ref: '#/definitions/exchange.PresentationSubmission'
         description: Must be present if the corresponding manifest contains a presentation_definition
       spec_version:
         type: string
@@ -1092,7 +1229,8 @@ definitions:
       name:
         type: string
       styles:
-        $ref: '#/definitions/rendering.EntityStyleDescriptor'
+        allOf:
+        - $ref: '#/definitions/rendering.EntityStyleDescriptor'
         description: |-
           an object or URI as defined by the DIF Entity Styles specification
           https://identity.foundation/wallet-rendering/#entity-styles
@@ -1104,7 +1242,8 @@ definitions:
       description:
         type: string
       display:
-        $ref: '#/definitions/rendering.DataDisplay'
+        allOf:
+        - $ref: '#/definitions/rendering.DataDisplay'
         description: 'both below: an object or URI as defined by the DIF Entity Styles
           specification'
       id:
@@ -1120,28 +1259,6 @@ definitions:
     - id
     - schema
     type: object
-  model.Submission:
-    properties:
-      definition_id:
-        type: string
-      descriptor_map:
-        items:
-          $ref: '#/definitions/exchange.SubmissionDescriptor'
-        type: array
-      id:
-        type: string
-      reason:
-        description: The reason why the submission was approved or denied.
-        type: string
-      status:
-        description: One of {`pending`, `approved`, `denied`, `cancelled`}.
-        type: string
-    required:
-    - definition_id
-    - descriptor_map
-    - id
-    - status
-    type: object
   pkg_server_router.CreateCredentialRequest:
     properties:
       '@context':
@@ -1180,7 +1297,7 @@ definitions:
       didWebId:
         type: string
       keyType:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     required:
     - keyType
     type: object
@@ -1189,7 +1306,7 @@ definitions:
       did:
         $ref: '#/definitions/did.DIDDocument'
       keyType:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
       privateKeyBase58:
         type: string
     type: object
@@ -1202,11 +1319,17 @@ definitions:
       credentials:
         description: Info required to create a credential from a credential application.
         items:
-          $ref: '#/definitions/issuing.CredentialTemplate'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.CredentialTemplate'
         type: array
+      id:
+        description: ID of this template.
+        type: string
       issuer:
         description: ID of the issuer that will be issuing the credentials.
         type: string
+    required:
+    - credentialManifest
+    - issuer
     type: object
   pkg_server_router.CreateManifestRequest:
     properties:
@@ -1336,7 +1459,7 @@ definitions:
     properties:
       credentials:
         items:
-          $ref: '#/definitions/credential.Container'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container'
         type: array
     type: object
   pkg_server_router.GetDIDByMethodResponse:
@@ -1348,7 +1471,7 @@ definitions:
     properties:
       methods:
         items:
-          type: string
+          $ref: '#/definitions/did.Method'
         type: array
     type: object
   pkg_server_router.GetDIDsByMethodResponse:
@@ -1372,7 +1495,7 @@ definitions:
       id:
         type: string
       type:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     type: object
   pkg_server_router.GetManifestResponse:
     properties:
@@ -1467,7 +1590,7 @@ definitions:
     properties:
       issuanceTemplates:
         items:
-          $ref: '#/definitions/issuing.IssuanceTemplate'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate'
         type: array
     type: object
   pkg_server_router.ListSubmissionRequest:
@@ -1482,7 +1605,7 @@ definitions:
     properties:
       submissions:
         items:
-          $ref: '#/definitions/model.Submission'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission'
         type: array
     type: object
   pkg_server_router.Operation:
@@ -1494,7 +1617,8 @@ definitions:
         description: The name of the resource related to this operation. E.g. "presentations/submissions/<uuid>"
         type: string
       result:
-        $ref: '#/definitions/pkg_server_router.OperationResult'
+        allOf:
+        - $ref: '#/definitions/pkg_server_router.OperationResult'
         description: Populated if Done == true.
     type: object
   pkg_server_router.OperationResult:
@@ -1515,6 +1639,13 @@ definitions:
       didResolutionMetadata:
         $ref: '#/definitions/did.DIDResolutionMetadata'
     type: object
+  pkg_server_router.ReviewApplicationRequest:
+    properties:
+      approved:
+        type: boolean
+      reason:
+        type: string
+    type: object
   pkg_server_router.ReviewSubmissionRequest:
     properties:
       approved:
@@ -1555,7 +1686,7 @@ definitions:
       id:
         type: string
       type:
-        type: string
+        $ref: '#/definitions/crypto.KeyType'
     required:
     - base58PrivateKey
     - controller
@@ -1569,6 +1700,16 @@ definitions:
     required:
     - applicationJwt
     type: object
+  pkg_server_router.SubmitApplicationResponse:
+    properties:
+      credential_response:
+        $ref: '#/definitions/manifest.CredentialResponse'
+      responseJwt:
+        type: string
+      verifiableCredentials:
+        description: this is an interface type to union Data Integrity and JWT style
+          VCs
+    type: object
   pkg_server_router.UpdateCredentialStatusRequest:
     properties:
       revoked:
@@ -1744,7 +1885,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetHealthCheckResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse'
       summary: Health Check
       tags:
       - HealthCheck
@@ -1790,7 +1931,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetCredentialsResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialsResponse'
         "400":
           description: Bad request
           schema:
@@ -1812,14 +1953,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.CreateCredentialRequest'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/pkg_server_router.CreateCredentialResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateCredentialResponse'
         "400":
           description: Bad request
           schema:
@@ -1876,7 +2017,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetCredentialResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialResponse'
         "400":
           description: Bad request
           schema:
@@ -1901,7 +2042,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetCredentialStatusResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusResponse'
         "400":
           description: Bad request
           schema:
@@ -1919,14 +2060,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.UpdateCredentialStatusRequest'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/pkg_server_router.UpdateCredentialStatusResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.UpdateCredentialStatusResponse'
         "400":
           description: Bad request
           schema:
@@ -1955,7 +2096,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.GetCredentialStatusListResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.GetCredentialStatusListResponse'
         "400":
           description: Bad request
           schema:
@@ -1974,14 +2115,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.VerifyCredentialRequest'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialRequest'
       produces:
       - application/json
       responses:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/pkg_server_router.VerifyCredentialResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.VerifyCredentialResponse'
         "400":
           description: Bad request
           schema:
@@ -2135,14 +2276,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/pkg_server_router.CreateIssuanceTemplateRequest'
+          $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_server_router.CreateIssuanceTemplateRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/issuing.IssuanceTemplate'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate'
         "400":
           description: Bad request
           schema:
@@ -2199,7 +2340,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/issuing.GetIssuanceTemplateResponse'
+            $ref: '#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuing.IssuanceTemplate'
         "400":
           description: Bad request
           schema:
@@ -2218,7 +2359,7 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest'
+          $ref: '#/definitions/pkg_server_router.StoreKeyRequest'
       produces:
       - application/json
       responses:
@@ -2252,7 +2393,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse'
+            $ref: '#/definitions/pkg_server_router.GetKeyDetailsResponse'
         "400":
           description: Bad request
           schema:
@@ -2285,7 +2426,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestsResponse'
+            $ref: '#/definitions/pkg_server_router.GetManifestsResponse'
         "400":
           description: Bad request
           schema:
@@ -2307,14 +2448,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest'
+          $ref: '#/definitions/pkg_server_router.CreateManifestRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestResponse'
+            $ref: '#/definitions/pkg_server_router.CreateManifestResponse'
         "400":
           description: Bad request
           schema:
@@ -2371,7 +2512,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse'
+            $ref: '#/definitions/pkg_server_router.GetManifestResponse'
         "400":
           description: Bad request
           schema:
@@ -2391,7 +2532,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationsResponse'
+            $ref: '#/definitions/pkg_server_router.GetApplicationsResponse'
         "400":
           description: Bad request
           schema:
@@ -2414,7 +2555,7 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.SubmitApplicationRequest'
+          $ref: '#/definitions/pkg_server_router.SubmitApplicationRequest'
       produces:
       - application/json
       responses:
@@ -2422,7 +2563,7 @@ paths:
           description: Operation with a SubmitApplicationResponse type in the `result.response`
             field.
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation'
+            $ref: '#/definitions/pkg_server_router.Operation'
         "400":
           description: Bad request
           schema:
@@ -2479,7 +2620,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetApplicationResponse'
+            $ref: '#/definitions/pkg_server_router.GetApplicationResponse'
         "400":
           description: Bad request
           schema:
@@ -2487,6 +2628,36 @@ paths:
       summary: Get application
       tags:
       - ApplicationAPI
+  /v1/manifests/applications/{id}/review:
+    put:
+      consumes:
+      - application/json
+      description: Reviewing an application either fulfills or denies the credential.
+      parameters:
+      - description: request body
+        in: body
+        name: request
+        required: true
+        schema:
+          $ref: '#/definitions/pkg_server_router.ReviewApplicationRequest'
+      produces:
+      - application/json
+      responses:
+        "201":
+          description: Credential Response
+          schema:
+            $ref: '#/definitions/pkg_server_router.SubmitApplicationResponse'
+        "400":
+          description: Bad request
+          schema:
+            type: string
+        "500":
+          description: Internal server error
+          schema:
+            type: string
+      summary: Reviews an application
+      tags:
+      - ApplicationAPI
   /v1/manifests/responses:
     get:
       consumes:
@@ -2499,7 +2670,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetResponsesResponse'
+            $ref: '#/definitions/pkg_server_router.GetResponsesResponse'
         "400":
           description: Bad request
           schema:
@@ -2556,7 +2727,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetResponseResponse'
+            $ref: '#/definitions/pkg_server_router.GetResponseResponse'
         "400":
           description: Bad request
           schema:
@@ -2663,14 +2834,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest'
+          $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionRequest'
       produces:
       - application/json
       responses:
         "201":
           description: Created
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse'
+            $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionResponse'
         "400":
           description: Bad request
           schema:
@@ -2727,7 +2898,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse'
+            $ref: '#/definitions/pkg_server_router.GetPresentationDefinitionResponse'
         "400":
           description: Bad request
           schema:
@@ -2747,14 +2918,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionRequest'
+          $ref: '#/definitions/pkg_server_router.ListSubmissionRequest'
       produces:
       - application/json
       responses:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ListSubmissionResponse'
+            $ref: '#/definitions/pkg_server_router.ListSubmissionResponse'
         "400":
           description: Bad request
           schema:
@@ -2776,14 +2947,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreateSubmissionRequest'
+          $ref: '#/definitions/pkg_server_router.CreateSubmissionRequest'
       produces:
       - application/json
       responses:
         "201":
           description: The type of response is Submission once the operation has finished.
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation'
+            $ref: '#/definitions/pkg_server_router.Operation'
         "400":
           description: Bad request
           schema:
@@ -2812,7 +2983,7 @@ paths:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSubmissionResponse'
+            $ref: '#/definitions/pkg_server_router.GetSubmissionResponse'
         "400":
           description: Bad request
           schema:
@@ -2833,14 +3004,14 @@ paths:
         name: request
         required: true
         schema:
-          $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionRequest'
+          $ref: '#/definitions/pkg_server_router.ReviewSubmissionRequest'
       produces:
       - application/json
       responses:
         "200":
           description: OK
           schema:
-            $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.ReviewSubmissionResponse'
+            $ref: '#/definitions/pkg_server_router.ReviewSubmissionResponse'
         "400":
           description: Bad request
           schema:
diff --git a/integration/common.go b/integration/common.go
index eb91722..2922e83 100644
--- a/integration/common.go
+++ b/integration/common.go
@@ -307,7 +307,23 @@ func getJSONElement(jsonString string, jsonPath string) (string, error) {
 		return "", errors.Wrap(err, "finding element in json string")
 	}
 
-	elementStr := fmt.Sprintf("%v", element)
+	if element == nil {
+		return "<nil>", nil
+	}
+	var elementStr string
+	switch element.(type) {
+	case bool:
+		elementStr = fmt.Sprintf("%v", element)
+	case string:
+		elementStr = fmt.Sprintf("%v", element)
+	case map[string]any:
+		data, err := json.Marshal(element)
+		if err != nil {
+			return "", err
+		}
+		elementStr = compactJSONOutput(string(data))
+	}
+
 	return elementStr, nil
 }
 
@@ -328,6 +344,7 @@ func get(url string) (string, error) {
 		return "", fmt.Errorf("status code not in the 200s. body: %s", string(body))
 	}
 
+	logrus.Infof("Received:  %s", string(body))
 	return string(body), err
 }
 
@@ -389,3 +406,23 @@ func getValidApplicationRequest(credAppJSON string, credentialJWT string) manife
 		Credentials:           creds,
 	}
 }
+
+type reviewApplicationParams struct {
+	ID       string
+	Approved bool
+	Reason   string
+}
+
+func ReviewApplication(params reviewApplicationParams) (string, error) {
+	trueApplicationJSON, err := resolveTemplate(params, "review-application-input.json")
+	if err != nil {
+		return "", err
+	}
+
+	output, err := put(endpoint+version+"manifests/applications/"+params.ID+"/review", trueApplicationJSON)
+	if err != nil {
+		return "", errors.Wrapf(err, "application endpoint with output: %s", output)
+	}
+
+	return output, nil
+}
diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go
index 1056380..113a317 100644
--- a/pkg/server/router/manifest.go
+++ b/pkg/server/router/manifest.go
@@ -283,7 +283,7 @@ func (sar SubmitApplicationRequest) ToServiceRequest() (*model.SubmitApplication
 type SubmitApplicationResponse struct {
 	Response manifestsdk.CredentialResponse `json:"credential_response"`
 	// this is an interface type to union Data Integrity and JWT style VCs
-	Credentials []any         `json:"verifiableCredentials,omitempty"`
+	Credentials any           `json:"verifiableCredentials,omitempty"`
 	ResponseJWT keyaccess.JWT `json:"responseJwt,omitempty"`
 }
 
@@ -513,3 +513,52 @@ func (mr ManifestRouter) DeleteResponse(ctx context.Context, w http.ResponseWrit
 
 	return framework.Respond(ctx, w, nil, http.StatusOK)
 }
+
+type ReviewApplicationRequest struct {
+	Approved bool   `json:"approved"`
+	Reason   string `json:"reason"`
+}
+
+func (r ReviewApplicationRequest) toServiceRequest(id string) model.ReviewApplicationRequest {
+	return model.ReviewApplicationRequest{
+		ID:       id,
+		Approved: r.Approved,
+		Reason:   r.Reason,
+	}
+}
+
+// ReviewApplication godoc
+// @Summary      Reviews an application
+// @Description  Reviewing an application either fulfills or denies the credential.
+// @Tags         ApplicationAPI
+// @Accept       json
+// @Produce      json
+// @Param        request  body      ReviewApplicationRequest  true  "request body"
+// @Success      201      {object}  SubmitApplicationResponse "Credential Response"
+// @Failure      400      {string}  string  "Bad request"
+// @Failure      500      {string}  string  "Internal server error"
+// @Router       /v1/manifests/applications/{id}/review [put]
+func (mr ManifestRouter) ReviewApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+	id := framework.GetParam(ctx, IDParam)
+	if id == nil {
+		return framework.NewRequestError(
+			util.LoggingNewError("review application request requires id"), http.StatusBadRequest)
+	}
+
+	var request ReviewApplicationRequest
+	if err := framework.Decode(r, &request); err != nil {
+		return framework.NewRequestError(
+			util.LoggingErrorMsg(err, "invalid review application request"), http.StatusBadRequest)
+	}
+
+	applicationResponse, err := mr.service.ReviewApplication(request.toServiceRequest(*id))
+	if err != nil {
+		return framework.NewRequestError(
+			util.LoggingErrorMsg(err, "failed reviewing application"), http.StatusInternalServerError)
+	}
+	return framework.Respond(ctx, w, SubmitApplicationResponse{
+		Response:    applicationResponse.Response,
+		Credentials: applicationResponse.Credentials,
+		ResponseJWT: applicationResponse.ResponseJWT,
+	}, http.StatusOK)
+}
diff --git a/pkg/server/server.go b/pkg/server/server.go
index d68bc58..64918ca 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -245,6 +245,7 @@ func (s *SSIServer) ManifestAPI(service svcframework.Service) (err error) {
 	s.Handle(http.MethodGet, applicationsHandlerPath, manifestRouter.GetApplications)
 	s.Handle(http.MethodGet, path.Join(applicationsHandlerPath, "/:id"), manifestRouter.GetApplication)
 	s.Handle(http.MethodDelete, path.Join(applicationsHandlerPath, "/:id"), manifestRouter.DeleteApplication)
+	s.Handle(http.MethodPut, path.Join(applicationsHandlerPath, "/:id", "/review"), manifestRouter.ReviewApplication)
 
 	s.Handle(http.MethodGet, responsesHandlerPath, manifestRouter.GetResponses)
 	s.Handle(http.MethodGet, path.Join(responsesHandlerPath, "/:id"), manifestRouter.GetResponse)
diff --git a/pkg/service/manifest/model/model.go b/pkg/service/manifest/model/model.go
index 30c49bd..bf50625 100644
--- a/pkg/service/manifest/model/model.go
+++ b/pkg/service/manifest/model/model.go
@@ -87,6 +87,14 @@ type DeleteApplicationRequest struct {
 	ID string `json:"id,omitempty" validate:"required"`
 }
 
+// ReviewApplicationRequest is something foobar
+type ReviewApplicationRequest struct {
+	// ID of the application.
+	ID       string `json:"id" validate:"required"`
+	Approved bool   `json:"approved"`
+	Reason   string `json:"reason"`
+}
+
 // Response
 
 type GetResponseRequest struct {
diff --git a/pkg/service/manifest/response.go b/pkg/service/manifest/response.go
index c3b8b0b..96db6e9 100644
--- a/pkg/service/manifest/response.go
+++ b/pkg/service/manifest/response.go
@@ -6,6 +6,7 @@ import (
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
 	errresp "github.com/TBD54566975/ssi-sdk/error"
+	"github.com/pkg/errors"
 
 	cred "github.com/tbd54566975/ssi-service/internal/credential"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
@@ -37,7 +38,7 @@ func (s Service) signCredentialResponseJWT(signingDID string, r CredentialRespon
 	return responseToken, nil
 }
 
-func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID string, credManifest manifest.CredentialManifest) (*manifest.CredentialResponse, []cred.Container, error) {
+func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID string, credManifest manifest.CredentialManifest, approved bool, reason string) (*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 {
@@ -80,8 +81,14 @@ func (s Service) buildCredentialResponse(applicantDID, manifestID, applicationID
 	}
 
 	// 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")
+	if approved {
+		if err := responseBuilder.SetFulfillment(descriptors); err != nil {
+			return nil, nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment")
+		}
+	} else {
+		if err := responseBuilder.SetDenial(reason); err != nil {
+			return nil, nil, errors.Wrap(err, "setting denial")
+		}
 	}
 	credRes, err := responseBuilder.Build()
 	if err != nil {
diff --git a/pkg/service/manifest/service.go b/pkg/service/manifest/service.go
index c42d19d..60d57f3 100644
--- a/pkg/service/manifest/service.go
+++ b/pkg/service/manifest/service.go
@@ -10,18 +10,17 @@ import (
 	"github.com/goccy/go-json"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
-	"github.com/tbd54566975/ssi-service/pkg/service/manifest/model"
-	manifeststg "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
-	"github.com/tbd54566975/ssi-service/pkg/service/operation"
-	opcredential "github.com/tbd54566975/ssi-service/pkg/service/operation/credential"
-	opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
-
 	"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"
+	"github.com/tbd54566975/ssi-service/pkg/service/manifest/model"
+	manifeststg "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation"
+	opcredential "github.com/tbd54566975/ssi-service/pkg/service/operation/credential"
+	opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
 
@@ -227,6 +226,11 @@ type CredentialResponseContainer struct {
 	Credentials []any                       `json:"verifiableCredentials,omitempty"`
 }
 
+// ProcessApplicationSubmission stores the application in a pending state, along with an operation. Once the operation
+// is done, the Operation.Response field will be of type model.SubmitApplicationResponse.
+// Invalid applications return an operation marked as done, with Response that represents denial.
+// The state of the application can be updated by calling CancelOperation, or by calling ReviewApplicationSubmission.
+// When the state is updated, the operation is marked as done.
 func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationRequest) (*operation.Operation, error) {
 	// get the manifest associated with the application
 	manifestID := request.Application.ManifestID
@@ -238,7 +242,6 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq
 	if gotManifest == nil {
 		return nil, util.LoggingNewErrorf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID)
 	}
-	credManifest := gotManifest.Manifest
 
 	opID := opcredential.IDFromResponseID(applicationID)
 	// validate the application
@@ -271,7 +274,7 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq
 	applicantDID := request.ApplicantDID
 	storageRequest := manifeststg.StoredApplication{
 		ID:             applicationID,
-		Status:         opcredential.StatusFulfilled,
+		Status:         opcredential.StatusPending,
 		ManifestID:     manifestID,
 		ApplicantDID:   applicantDID,
 		Application:    request.Application,
@@ -282,8 +285,37 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq
 		return nil, util.LoggingErrorMsg(err, "could not store application")
 	}
 
+	storedOp := opstorage.StoredOperation{
+		ID: opID,
+	}
+	if err = s.opsStorage.StoreOperation(storedOp); err != nil {
+		return nil, errors.Wrap(err, "storing operation")
+	}
+	return operation.ServiceModel(storedOp)
+}
+
+// ReviewApplication moves an application state and marks the operation associated with it as done. A credential
+// response is stored.
+func (s Service) ReviewApplication(request model.ReviewApplicationRequest) (*model.SubmitApplicationResponse, error) {
+	application, err := s.storage.GetApplication(request.ID)
+	if err != nil {
+		return nil, errors.Wrap(err, "fetching application")
+	}
+
+	manifestID := application.ManifestID
+	gotManifest, err := s.storage.GetManifest(manifestID)
+	if err != nil {
+		return nil, errors.Wrap(err, "fetching manifest")
+	}
+	applicationID := application.ID
+	if gotManifest == nil {
+		return nil, util.LoggingNewErrorf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID)
+	}
+	credManifest := gotManifest.Manifest
+	applicantDID := application.ApplicantDID
+
 	// build the credential response
-	credResp, creds, err := s.buildCredentialResponse(applicantDID, manifestID, applicationID, credManifest)
+	credResp, creds, err := s.buildCredentialResponse(applicantDID, manifestID, applicationID, credManifest, request.Approved, request.Reason)
 	if err != nil {
 		return nil, util.LoggingErrorMsg(err, "could not build credential response")
 	}
@@ -309,23 +341,13 @@ func (s Service) ProcessApplicationSubmission(request model.SubmitApplicationReq
 		Credentials:  creds,
 		ResponseJWT:  *responseJWT,
 	}
-	if err = s.storage.StoreResponse(storeResponseRequest); err != nil {
-		return nil, util.LoggingErrorMsg(err, "could not store manifest response")
-	}
-
-	sarData, err := json.Marshal(storeResponseRequest)
+	storedResponse, _, err := s.storage.ReviewApplication(request.ID, request.Approved, request.Reason, opcredential.IDFromResponseID(request.ID), storeResponseRequest)
 	if err != nil {
-		return nil, errors.Wrap(err, "marshalling response")
-	}
-	storedOp := opstorage.StoredOperation{
-		ID:       opID,
-		Done:     true,
-		Response: sarData,
+		return nil, errors.Wrap(err, "updating submission")
 	}
-	if err = s.opsStorage.StoreOperation(storedOp); err != nil {
-		return nil, errors.Wrap(err, "storing operation")
-	}
-	return operation.ServiceModel(storedOp)
+
+	m := model.ServiceModel(storedResponse)
+	return &m, nil
 }
 
 func (s Service) GetApplication(request model.GetApplicationRequest) (*model.GetApplicationResponse, error) {
diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go
index 2c0bfdb..b51ca82 100644
--- a/pkg/service/manifest/storage/storage.go
+++ b/pkg/service/manifest/storage/storage.go
@@ -3,16 +3,17 @@ package storage
 import (
 	"fmt"
 
+	"github.com/TBD54566975/ssi-sdk/credential/manifest"
 	"github.com/goccy/go-json"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
-	"github.com/tbd54566975/ssi-service/pkg/service/operation/credential"
-
-	"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/operation/credential"
+	opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation/storage/namespace"
+	opsubmission "github.com/tbd54566975/ssi-service/pkg/service/operation/submission"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
 
@@ -237,3 +238,54 @@ func (ms *Storage) DeleteResponse(id string) error {
 	}
 	return nil
 }
+
+// ReviewApplication does the following:
+//  1. Updates the application status according to the approved parameter.
+//  2. Creates a Credential Response corresponding to the approved parameter and with the given reason.
+//  3. Marks the operation with id == opID as done, and sets operation.Response to the StoredResponse from the object
+//     creates in step 2.
+//
+// The operation and it's response (from 3) are returned.
+func (ms *Storage) ReviewApplication(id string, approved bool, reason string, opID string, response StoredResponse) (*StoredResponse, *opstorage.StoredOperation, error) {
+	// TODO: everything should be in a single Tx.
+	m := map[string]any{
+		"status": opsubmission.StatusDenied,
+		"reason": reason,
+	}
+	if approved {
+		m["status"] = opsubmission.StatusApproved
+	}
+	if _, err := ms.db.Update(credential.ApplicationNamespace, id, m); err != nil {
+		return nil, nil, errors.Wrap(err, "updating application")
+	}
+
+	if err := ms.StoreResponse(response); err != nil {
+		return nil, nil, errors.Wrap(err, "storing credential response")
+	}
+
+	responseData, operationData, err := ms.db.UpdateValueAndOperation(
+		responseNamespace,
+		response.ID,
+		storage.NewUpdater(m),
+		namespace.FromID(opID),
+		opID,
+		opsubmission.OperationUpdater{
+			UpdaterWithMap: storage.NewUpdater(map[string]any{
+				"done": true,
+			}),
+		})
+	if err != nil {
+		return nil, nil, errors.Wrap(err, "updating value and operation")
+	}
+
+	var s StoredResponse
+	if err = json.Unmarshal(responseData, &s); err != nil {
+		return nil, nil, errors.Wrap(err, "unmarshalling written credential response")
+	}
+	var op opstorage.StoredOperation
+	if err = json.Unmarshal(operationData, &op); err != nil {
+		return nil, nil, errors.Wrap(err, "unmarshalling written operation")
+	}
+
+	return &s, &op, nil
+}


Test patch:
diff --git a/integration/didweb_integration_test.go b/integration/didweb_integration_test.go
index 73ddb92..54fd744 100644
--- a/integration/didweb_integration_test.go
+++ b/integration/didweb_integration_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
 )
 
 var didWebContext = NewTestContext("DIDWeb")
@@ -118,7 +119,7 @@ func TestDidWebCreateCredentialManifestIntegration(t *testing.T) {
 	assert.NotEmpty(t, manifestID)
 }
 
-func TestDidWebSubmitApplicationIntegration(t *testing.T) {
+func TestDidWebSubmitAndReviewApplicationIntegration(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping integration test")
 	}
@@ -150,17 +151,39 @@ func TestDidWebSubmitApplicationIntegration(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NotEmpty(t, credAppJWT)
 
-	credentialResponseOutput, err := SubmitApplication(applicationParams{
+	submitApplicationOutput, err := SubmitApplication(applicationParams{
 		ApplicationJWT: credAppJWT,
 	})
 	assert.NoError(t, err)
-	assert.NotEmpty(t, credentialResponseOutput)
+	assert.NotEmpty(t, submitApplicationOutput)
 
-	crManifestID, err := getJSONElement(credentialResponseOutput, "$.result.response.credential_response.manifest_id")
+	isDone, err := getJSONElement(submitApplicationOutput, "$.done")
+	assert.NoError(t, err)
+	assert.Equal(t, "false", isDone)
+	opID, err := getJSONElement(submitApplicationOutput, "$.id")
+	assert.NoError(t, err)
+
+	reviewApplicationOutput, err := ReviewApplication(reviewApplicationParams{
+		ID:       storage.StatusObjectID(opID),
+		Approved: true,
+		Reason:   "oh yeah im testing",
+	})
+	assert.NoError(t, err)
+	crManifestID, err := getJSONElement(reviewApplicationOutput, "$.credential_response.manifest_id")
 	assert.NoError(t, err)
 	assert.Equal(t, manifestID, crManifestID)
 
-	vc, err := getJSONElement(credentialResponseOutput, "$.result.response.verifiableCredentials[0]")
+	vc, err := getJSONElement(reviewApplicationOutput, "$.verifiableCredentials[0]")
 	assert.NoError(t, err)
 	assert.NotEmpty(t, vc)
+
+	operationOutput, err := get(endpoint + version + "operations/" + opID)
+	assert.NoError(t, err)
+	isDone, err = getJSONElement(operationOutput, "$.done")
+	assert.NoError(t, err)
+	assert.Equal(t, "true", isDone)
+
+	opCredentialResponse, err := getJSONElement(operationOutput, "$.result.response")
+	assert.NoError(t, err)
+	assert.JSONEq(t, reviewApplicationOutput, opCredentialResponse)
 }
diff --git a/integration/steelthread_integration_test.go b/integration/steelthread_integration_test.go
index bb718d2..b765b3d 100644
--- a/integration/steelthread_integration_test.go
+++ b/integration/steelthread_integration_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
 )
 
 var steelThreadContext = NewTestContext("SteelThread")
@@ -118,7 +119,7 @@ func TestCreateCredentialManifestIntegration(t *testing.T) {
 	assert.NotEmpty(t, manifestID)
 }
 
-func TestSubmitApplicationIntegration(t *testing.T) {
+func TestSubmitAndReviewApplicationIntegration(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping integration test")
 	}
@@ -150,17 +151,40 @@ func TestSubmitApplicationIntegration(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NotEmpty(t, credAppJWT)
 
-	credentialResponseOutput, err := SubmitApplication(applicationParams{
+	submitApplicationOutput, err := SubmitApplication(applicationParams{
 		ApplicationJWT: credAppJWT,
 	})
 	assert.NoError(t, err)
-	assert.NotEmpty(t, credentialResponseOutput)
+	assert.NotEmpty(t, submitApplicationOutput)
 
-	crManifestID, err := getJSONElement(credentialResponseOutput, "$.result.response.credential_response.manifest_id")
+	isDone, err := getJSONElement(submitApplicationOutput, "$.done")
+	assert.NoError(t, err)
+	assert.Equal(t, "false", isDone)
+	opID, err := getJSONElement(submitApplicationOutput, "$.id")
+	assert.NoError(t, err)
+
+	reviewApplicationOutput, err := ReviewApplication(reviewApplicationParams{
+		ID:       storage.StatusObjectID(opID),
+		Approved: true,
+		Reason:   "oh yeah im testing",
+	})
+	assert.NoError(t, err)
+
+	crManifestID, err := getJSONElement(reviewApplicationOutput, "$.credential_response.manifest_id")
 	assert.NoError(t, err)
 	assert.Equal(t, manifestID, crManifestID)
 
-	vc, err := getJSONElement(credentialResponseOutput, "$.result.response.verifiableCredentials[0]")
+	vc, err := getJSONElement(reviewApplicationOutput, "$.verifiableCredentials[0]")
 	assert.NoError(t, err)
 	assert.NotEmpty(t, vc)
+
+	operationOutput, err := get(endpoint + version + "operations/" + opID)
+	assert.NoError(t, err)
+	isDone, err = getJSONElement(operationOutput, "$.done")
+	assert.NoError(t, err)
+	assert.Equal(t, "true", isDone)
+
+	opCredentialResponse, err := getJSONElement(operationOutput, "$.result.response")
+	assert.NoError(t, err)
+	assert.JSONEq(t, reviewApplicationOutput, opCredentialResponse)
 }
diff --git a/integration/testdata/review-application-input.json b/integration/testdata/review-application-input.json
new file mode 100644
index 0000000..305d0f8
--- /dev/null
+++ b/integration/testdata/review-application-input.json
@@ -0,0 +1,4 @@
+{
+  "approved": {{.Approved}},
+  "reason": "{{.Reason}}"
+}
\ No newline at end of file
diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go
index db17427..dd88b47 100644
--- a/pkg/server/router/manifest_test.go
+++ b/pkg/server/router/manifest_test.go
@@ -10,8 +10,8 @@ import (
 	"github.com/google/uuid"
 	"github.com/mr-tron/base58"
 	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
 	"github.com/tbd54566975/ssi-service/pkg/service/manifest/model"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
 
 	credmodel "github.com/tbd54566975/ssi-service/internal/credential"
 	"github.com/tbd54566975/ssi-service/internal/keyaccess"
@@ -125,8 +125,14 @@ func TestManifestRouter(t *testing.T) {
 		assert.NoError(tt, err)
 		createdApplicationResponseOp, err := manifestService.ProcessApplicationSubmission(*sar)
 		assert.NoError(tt, err)
-		createdApplicationResponse, ok := createdApplicationResponseOp.Result.Response.(model.SubmitApplicationResponse)
-		require.True(tt, ok)
+		assert.False(tt, createdApplicationResponseOp.Done)
+
+		createdApplicationResponse, err := manifestService.ReviewApplication(model.ReviewApplicationRequest{
+			ID:       storage.StatusObjectID(createdApplicationResponseOp.ID),
+			Approved: true,
+			Reason:   "ApprovalMan is here",
+		})
+		assert.NoError(tt, err)
 		assert.NotEmpty(tt, createdManifest)
 		assert.NotEmpty(tt, createdApplicationResponse.Response.ID)
 		assert.NotEmpty(tt, createdApplicationResponse.Response.Fulfillment)
diff --git a/pkg/server/server_manifest_test.go b/pkg/server/server_manifest_test.go
index f15f035..c4d8129 100644
--- a/pkg/server/server_manifest_test.go
+++ b/pkg/server/server_manifest_test.go
@@ -12,13 +12,13 @@ import (
 	"github.com/mr-tron/base58"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-	manifestsvc "github.com/tbd54566975/ssi-service/pkg/service/manifest/model"
-
 	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"
+	manifestsvc "github.com/tbd54566975/ssi-service/pkg/service/manifest/model"
+	"github.com/tbd54566975/ssi-service/pkg/service/operation/storage"
 	"github.com/tbd54566975/ssi-service/pkg/service/schema"
 )
 
@@ -416,10 +416,18 @@ func TestManifestAPI(t *testing.T) {
 		err = json.NewDecoder(w.Body).Decode(&op)
 		assert.NoError(tt, err)
 
-		var appResp router.SubmitApplicationResponse
-		respData, err := json.Marshal(op.Result.Response)
+		assert.False(tt, op.Done)
+		assert.Contains(tt, op.ID, "credentials/responses/")
+
+		// review application
+		reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{Approved: true, Reason: "I'm the almighty approver"})
+		applicationID := storage.StatusObjectID(op.ID)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications/"+applicationID+"/review", reviewApplicationRequestValue)
+		err = manifestRouter.ReviewApplication(newRequestContextWithParams(map[string]string{"id": applicationID}), w, req)
 		assert.NoError(tt, err)
-		err = json.Unmarshal(respData, &appResp)
+
+		var appResp router.SubmitApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&appResp)
 		assert.NoError(tt, err)
 
 		assert.NotEmpty(tt, appResp.Response)
@@ -685,10 +693,15 @@ func TestManifestAPI(t *testing.T) {
 		err = json.NewDecoder(w.Body).Decode(&op)
 		assert.NoError(tt, err)
 
-		var appResp router.SubmitApplicationResponse
-		respData, err := json.Marshal(op.Result.Response)
+		// review application
+		reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{Approved: true, Reason: "I'm the almighty approver"})
+		applicationID := storage.StatusObjectID(op.ID)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications/"+applicationID+"/review", reviewApplicationRequestValue)
+		err = manifestRouter.ReviewApplication(newRequestContextWithParams(map[string]string{"id": applicationID}), w, req)
 		assert.NoError(tt, err)
-		err = json.Unmarshal(respData, &appResp)
+
+		var appResp router.SubmitApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&appResp)
 		assert.NoError(tt, err)
 
 		assert.NotEmpty(tt, appResp.Response.Fulfillment)