Repository: TBD54566975/ssi-service
Pull request #94 (2022-09-13 21:58:08)

Adding credential application CRUD and validation
This is the implementation of the Credential Application CRUD and Apply functionality according to SIP 2
https://github.com/TBD54566975/ssi-service/tree/main/sip/sips/sip_2

PUT Manifest Input (We need a valid manifest ID to do an application)
```

{
  "@context": "",
  "issuer" : "did:example:123",
  "outputDescriptors": [
            {
                "id": "odid1",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            },
            {
                "id": "odid2",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            }
        ],
   "presentationDefinition": {
    "id": "test",
    "input_descriptors": [
      {
        "id": "id1",
        "constraints" : 
            {
                "fields" : [ 
                    {
                    "path" : [
                        "path1"
                    ]
                    }
                ]
            }
        

      }
    ]
  }
}
```

PUT Application Input
```

{
  "manifestId" : "manifest-id-on-put-manifest-response",
  "presentationSubmission": {
    "id": "id1",
    "definition_id" :"defid",
    "descriptor_map": [
        {
        "id": "id1",
        "format": "jwt",
        "path": "pth"
        }
    ]
    }
}
```

Application Output
```

{
    "application": {
        "credential_application": {
            "id": "b4ced4a4-3568-4885-874b-b95efebc7e80",
            "manifest_id": "14fdc7c5-0b37-47b5-a711-7da1215cd118",
            "format": {
                "jwt": {
                    "alg": [
                        "EdDSA"
                    ]
                }
            }
        },
        "presentation_submission": {
            "id": "id1",
            "definition_id": "defid",
            "descriptor_map": [
                {
                    "id": "id1",
                    "format": "jwt",
                    "path": "pth"
                }
            ]
        }
    }
}
```

<img width="718" alt="image" src="https://user-images.githubusercontent.com/5314059/190016521-1f04549b-931e-472b-93cd-09fa80201ce3.png">




codecov-commenter: # [Codecov](https://codecov.io/gh/TBD54566975/ssi-service/pull/94?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) Report
> Merging [#94](https://codecov.io/gh/TBD54566975/ssi-service/pull/94?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (229a6de) into [main](https://codecov.io/gh/TBD54566975/ssi-service/commit/62b812c1148b7c4adec03de855b1b9a713325ae1?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (62b812c) will **decrease** coverage by `1.38%`.
> The diff coverage is `15.18%`.

```diff
@@            Coverage Diff             @@
##             main      #94      +/-   ##
==========================================
- Coverage   25.94%   24.56%   -1.39%     
==========================================
  Files          14       14              
  Lines         844      916      +72     
==========================================
+ Hits          219      225       +6     
- Misses        594      660      +66     
  Partials       31       31              
```


| [Impacted Files](https://codecov.io/gh/TBD54566975/ssi-service/pull/94?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/94/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIvbWFuaWZlc3QuZ28=) | `5.51% <1.47%> (-4.61%)` | :arrow_down: |
| [pkg/server/server.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/94/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9zZXJ2ZXIuZ28=) | `70.53% <100.00%> (+1.66%)` | :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)

nitro-neal: Updated Input:

Create Manifest Input:
```
{
  "@context": "",
  "issuer" : "did:example:123",
  "outputDescriptors": [
            {
                "id": "odid1",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            },
            {
                "id": "odid2",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            }
        ],
   "presentationDefinition": {
    "id": "test",
    "input_descriptors": [
      {
        "id": "id1",
        "constraints" : 
            {
                "fields" : [ 
                    {
                    "path" : [
                        "path1"
                    ]
                    }
                ]
            }
        

      }
    ]
  }
}
```

Create Manifest Output:

```
{
    "manifest": {
        "id": "2552f418-39c8-4fb1-83c6-d9dc17b81980",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "issuer": {
            "id": "did:example:123",
            "name": "did:example:123"
        },
        "output_descriptors": [
            {
                "id": "odid1",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            },
            {
                "id": "odid2",
                "schema": "https://test.com/schema",
                "name": "good ID",
                "description": "it's all good"
            }
        ],
        "format": {
            "jwt": {
                "alg": [
                    "EdDSA"
                ]
            }
        },
        "presentation_definition": {
            "id": "test",
            "input_descriptors": [
                {
                    "id": "id1",
                    "constraints": {
                        "fields": [
                            {
                                "path": [
                                    "path1"
                                ]
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

Submit Application Input:
```
{
  "manifestId" : "2552f418-39c8-4fb1-83c6-d9dc17b81980",
  "presentationSubmission": {
    "id": "id1",
    "definition_id" :"defid",
    "descriptor_map": [
        {
        "id": "id1",
        "format": "jwt",
        "path": "pth"
        }
    ]
    }
}
```

Submit Application Output:

```
{
    "response": {
        "id": "7e6e314c-4545-4243-ab1c-ba28aacc6aa9",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "manifest_id": "2552f418-39c8-4fb1-83c6-d9dc17b81980",
        "application_id": "0105f88f-12cf-446b-aecf-4deb6d537ed4",
        "fulfillment": {
            "descriptor_map": [
                {
                    "id": "id1",
                    "format": "jwt",
                    "path": "pth"
                }
            ]
        }
    },
    "credentials": [
        {
            "@context": [
                "https://www.w3.org/2018/credentials/v1"
            ],
            "id": "8b85cd47-c5a5-403c-a892-759d730bb761",
            "type": [
                "VerifiableCredential"
            ],
            "issuer": "did:example:123",
            "issuanceDate": "2022-09-16T18:50:27Z",
            "credentialSubject": {
                "id": "0105f88f-12cf-446b-aecf-4deb6d537ed4"
            }
        },
        {
            "@context": [
                "https://www.w3.org/2018/credentials/v1"
            ],
            "id": "e668b563-b848-400a-8e1d-cb47e064a5a0",
            "type": [
                "VerifiableCredential"
            ],
            "issuer": "did:example:123",
            "issuanceDate": "2022-09-16T18:50:27Z",
            "credentialSubject": {
                "id": "0105f88f-12cf-446b-aecf-4deb6d537ed4"
            }
        }
    ]
}
```




nitro-neal: Ok much better now with objects at top level of request:

Create Manifest Input:
```
{
    "manifest":
        {
        "id": "WA-DL-CLASS-A",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "issuer": {
            "id": "did:example:123?linked-domains=3"
        },
        "output_descriptors": [
            {
            "id": "driver_license_output",
            "schema": "https://schema.org/EducationalOccupationalCredential"
            }
        ],
        "presentation_definition": {
            "id": "test",
            "input_descriptors": [
                {
                "id": "id1",
                "constraints" : 
                    {
                        "fields" : [ 
                            {
                            "path" : [
                                "path1"
                            ]
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

Create Manifest Output:

```
{
    "manifest": {
        "id": "WA-DL-CLASS-A",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "issuer": {
            "id": "did:example:123?linked-domains=3"
        },
        "output_descriptors": [
            {
                "id": "driver_license_output",
                "schema": "https://schema.org/EducationalOccupationalCredential"
            }
        ],
        "presentation_definition": {
            "id": "test",
            "input_descriptors": [
                {
                    "id": "id1",
                    "constraints": {
                        "fields": [
                            {
                                "path": [
                                    "path1"
                                ]
                            }
                        ]
                    }
                }
            ]
        }
    }
}
```

Submit Application Input:

```
{
    "requesterDid" : "did:user:123",
    "application": {
        "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "manifest_id": "WA-DL-CLASS-A",
        "format": {
            "ldp_vc": {
                "proof_type": [
                    "JsonWebSignature2020",
                    "EcdsaSecp256k1Signature2019"
                ]
            }
        },
        "presentation_submission": {
            "id": "a30e3b91-fb77-4d22-95fa-871689c322e2",
            "definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653",
            "descriptor_map": [
                {
                    "id": "id1",
                    "format": "jwt_vc",
                    "path": "$.verifiableCredential[0]"
                }
            ]
        }
    }
}
```

Submit Application Output:

```
{
    "response": {
        "id": "b7dc34e4-b8b3-4331-8fb7-b5d5bfb17799",
        "spec_version": "https://identity.foundation/credential-manifest/spec/v1.0.0/",
        "manifest_id": "WA-DL-CLASS-A",
        "application_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
        "fulfillment": {
            "descriptor_map": [
                {
                    "id": "id1",
                    "format": "jwt_vc",
                    "path": "$.verifiableCredential[0]"
                }
            ]
        }
    },
    "credentials": [
        {
            "@context": [
                "https://www.w3.org/2018/credentials/v1"
            ],
            "id": "43738ead-6172-4fc2-849b-7e04d502c41e",
            "type": [
                "VerifiableCredential"
            ],
            "issuer": "did:example:123?linked-domains=3",
            "issuanceDate": "2022-09-16T23:45:52Z",
            "credentialSubject": {
                "id": "did:user:123"
            }
        }
    ]
}
```

Patch:
diff --git a/go.mod b/go.mod
index 176345f..1cbbfe5 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.17
 
 require (
 	github.com/BurntSushi/toml v1.2.0
-	github.com/TBD54566975/ssi-sdk v0.0.0-20220719010135-e2fdcfb80e49
+	github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901
 	github.com/ardanlabs/conf v1.5.0
 	github.com/dimfeld/httptreemux/v5 v5.4.0
 	github.com/go-playground/locales v0.14.0
@@ -28,7 +28,7 @@ require github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indi
 
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
+	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // 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.0 // indirect
@@ -42,7 +42,7 @@ require (
 	github.com/multiformats/go-base32 v0.0.3 // indirect
 	github.com/multiformats/go-base36 v0.1.0 // indirect
 	github.com/multiformats/go-multibase v0.1.1 // indirect
-	github.com/multiformats/go-multicodec v0.5.0 // indirect
+	github.com/multiformats/go-multicodec v0.6.0 // indirect
 	github.com/multiformats/go-varint v0.0.6 // indirect
 	github.com/piprate/json-gold v0.4.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -53,7 +53,7 @@ require (
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
 	go.opentelemetry.io/otel v1.9.0
 	go.opentelemetry.io/otel/sdk v1.9.0
-	golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
+	golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
 	golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
diff --git a/go.sum b/go.sum
index bde0148..3992e30 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,8 @@ 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.0-20220719010135-e2fdcfb80e49 h1:BozkJ4jg1nZyTzBs/ltNq+KtTuveZDh48Ax85cVh0M4=
 github.com/TBD54566975/ssi-sdk v0.0.0-20220719010135-e2fdcfb80e49/go.mod h1:uWJkLbobBINP2QFVFL5kku5GtCmbmggzCHh8sTH5NYs=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901 h1:7cT1hMDiWQlsQYNP2U0mxpUjc5AxKVElcAdvTt5amnM=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901/go.mod h1:uXrbtCwqgsbZvL/zM3+DpAOuuIax9qG2aeUhZrGPCck=
 github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
 github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
 github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
@@ -13,6 +15,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
+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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -73,6 +77,8 @@ github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyD
 github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
 github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
 github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues=
+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-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=
@@ -137,6 +143,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
+golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
 golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go
index 6a05892..c8ab631 100644
--- a/pkg/server/router/manifest.go
+++ b/pkg/server/router/manifest.go
@@ -3,7 +3,7 @@ package router
 import (
 	"context"
 	"fmt"
-	"github.com/TBD54566975/ssi-sdk/credential/exchange"
+	"github.com/TBD54566975/ssi-sdk/credential"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
 	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
 	"net/http"
@@ -23,29 +23,22 @@ func NewManifestRouter(s svcframework.Service) (*ManifestRouter, error) {
 	if s == nil {
 		return nil, errors.New("service cannot be nil")
 	}
-	credService, ok := s.(*manifest.Service)
+	manifestService, ok := s.(*manifest.Service)
 	if !ok {
 		return nil, fmt.Errorf("could not create manifest router with service type: %s", s.Type())
 	}
 	return &ManifestRouter{
-		service: credService,
+		service: manifestService,
 	}, nil
 }
 
 type CreateManifestRequest struct {
-	Issuer string `json:"issuer" validate:"required"`
-	// A context is optional. If not present, we'll apply default, required context values.
-	Context                string                          `json:"@context"`
-	OutputDescriptors      []manifestsdk.OutputDescriptor  `json:"outputDescriptors" validate:"required"`
-	PresentationDefinition exchange.PresentationDefinition `json:"presentationDefinition" validate:"required"`
+	Manifest manifestsdk.CredentialManifest `json:"manifest" validate:"required"`
 }
 
 func (c CreateManifestRequest) ToServiceRequest() manifest.CreateManifestRequest {
 	return manifest.CreateManifestRequest{
-		Issuer:                 c.Issuer,
-		Context:                c.Context,
-		OutputDescriptors:      c.OutputDescriptors,
-		PresentationDefinition: c.PresentationDefinition,
+		Manifest: c.Manifest,
 	}
 }
 
@@ -182,3 +175,243 @@ func (mr ManifestRouter) DeleteManifest(ctx context.Context, w http.ResponseWrit
 
 	return framework.Respond(ctx, w, nil, http.StatusOK)
 }
+
+type SubmitApplicationRequest struct {
+	Application manifestsdk.CredentialApplication `json:"application" validate:"required"`
+	// Once we have JWT signed wrapper that can get the did this can be removed
+	RequesterDID string `json:"requesterDid" validate:"required"`
+}
+
+func (sar SubmitApplicationRequest) ToServiceRequest() manifest.SubmitApplicationRequest {
+	return manifest.SubmitApplicationRequest{
+		Application:  sar.Application,
+		RequesterDID: sar.RequesterDID,
+	}
+}
+
+type SubmitApplicationResponse struct {
+	Response    manifestsdk.CredentialResponse    `json:"response"`
+	Credentials []credential.VerifiableCredential `json:"credentials"`
+}
+
+// SubmitApplication godoc
+// @Summary      Submit application
+// @Description  Submit application
+// @Tags         ApplicationAPI
+// @Accept       json
+// @Produce      json
+// @Param        request  body      SubmitApplicationRequest  true  "request body"
+// @Success      201      {object}  SubmitApplicationResponse
+// @Failure      400      {string}  string  "Bad request"
+// @Failure      500      {string}  string  "Internal server error"
+// @Router       /v1/manifests/applications [put]
+func (mr ManifestRouter) SubmitApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
+	var request SubmitApplicationRequest
+	if err := framework.Decode(r, &request); err != nil {
+		errMsg := "invalid submit application request"
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
+	}
+
+	req := request.ToServiceRequest()
+	submitApplicationResponse, err := mr.service.SubmitApplication(req)
+	if err != nil {
+		errMsg := "could not submit application"
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
+	}
+
+	resp := SubmitApplicationResponse{Response: submitApplicationResponse.Response, Credentials: submitApplicationResponse.Credential}
+
+	return framework.Respond(ctx, w, resp, http.StatusCreated)
+}
+
+type GetApplicationResponse struct {
+	ID          string                            `json:"id"`
+	Application manifestsdk.CredentialApplication `json:"application"`
+}
+
+// GetApplication godoc
+// @Summary      Get application
+// @Description  Get application by id
+// @Tags         ApplicationAPI
+// @Accept       json
+// @Produce      json
+// @Param        id   path      string  true  "ID"
+// @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 {
+	id := framework.GetParam(ctx, IDParam)
+	if id == nil {
+		errMsg := "cannot get application without ID parameter"
+		logrus.Error(errMsg)
+		return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
+	}
+
+	gotApplication, err := mr.service.GetApplication(manifest.GetApplicationRequest{ID: *id})
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get application with id: %s", *id)
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
+	}
+
+	resp := GetApplicationResponse{
+		ID:          gotApplication.Application.ID,
+		Application: gotApplication.Application,
+	}
+	return framework.Respond(ctx, w, resp, http.StatusOK)
+}
+
+type GetApplicationsResponse struct {
+	Applications []manifestsdk.CredentialApplication `json:"applications"`
+}
+
+// GetApplications godoc
+// @Summary      Get applications
+// @Description  Checks for the presence of a query parameter and calls the associated filtered get method
+// @Tags         ApplicationAPI
+// @Accept       json
+// @Produce      json
+// @Success      200      {object}  GetApplicationsResponse
+// @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 {
+	gotApplications, err := mr.service.GetApplications()
+
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get applications")
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
+	}
+
+	resp := GetApplicationsResponse{
+		Applications: gotApplications.Applications,
+	}
+
+	return framework.Respond(ctx, w, resp, http.StatusOK)
+}
+
+// DeleteApplication godoc
+// @Summary      Delete applications
+// @Description  Delete application by ID
+// @Tags         ApplicationAPI
+// @Accept       json
+// @Produce      json
+// @Param        id   path      string  true  "ID"
+// @Success      200  {string}  string  "OK"
+// @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 {
+	id := framework.GetParam(ctx, IDParam)
+	if id == nil {
+		errMsg := "cannot delete application without ID parameter"
+		logrus.Error(errMsg)
+		return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
+	}
+
+	if err := mr.service.DeleteApplication(manifest.DeleteApplicationRequest{ID: *id}); err != nil {
+		errMsg := fmt.Sprintf("could not delete application with id: %s", *id)
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
+	}
+
+	return framework.Respond(ctx, w, nil, http.StatusOK)
+}
+
+type GetResponseResponse struct {
+	ID       string                         `json:"id"`
+	Response manifestsdk.CredentialResponse `json:"response"`
+}
+
+// GetResponse godoc
+// @Summary      Get response
+// @Description  Get response by id
+// @Tags         ResponseAPI
+// @Accept       json
+// @Produce      json
+// @Param        id   path      string  true  "ID"
+// @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 {
+	id := framework.GetParam(ctx, IDParam)
+	if id == nil {
+		errMsg := "cannot get response without ID parameter"
+		logrus.Error(errMsg)
+		return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
+	}
+
+	gotResponse, err := mr.service.GetResponse(manifest.GetResponseRequest{ID: *id})
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get response with id: %s", *id)
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
+	}
+
+	resp := GetResponseResponse{
+		ID:       gotResponse.Response.ID,
+		Response: gotResponse.Response,
+	}
+	return framework.Respond(ctx, w, resp, http.StatusOK)
+}
+
+type GetResponsesResponse struct {
+	Responses []manifestsdk.CredentialResponse `json:"responses"`
+}
+
+// GetResponses godoc
+// @Summary      Get responses
+// @Description  Checks for the presence of a query parameter and calls the associated filtered get method
+// @Tags         ResponseAPI
+// @Accept       json
+// @Produce      json
+// @Success      200      {object}  GetResponsesResponse
+// @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 {
+	gotResponses, err := mr.service.GetResponses()
+
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get responses")
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
+	}
+
+	resp := GetResponsesResponse{
+		Responses: gotResponses.Responses,
+	}
+
+	return framework.Respond(ctx, w, resp, http.StatusOK)
+}
+
+// DeleteResponse godoc
+// @Summary      Delete responses
+// @Description  Delete response by ID
+// @Tags         ResponseAPI
+// @Accept       json
+// @Produce      json
+// @Param        id   path      string  true  "ID"
+// @Success      200  {string}  string  "OK"
+// @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 {
+	id := framework.GetParam(ctx, IDParam)
+	if id == nil {
+		errMsg := "cannot delete response without ID parameter"
+		logrus.Error(errMsg)
+		return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
+	}
+
+	if err := mr.service.DeleteResponse(manifest.DeleteResponseRequest{ID: *id}); err != nil {
+		errMsg := fmt.Sprintf("could not delete response with id: %s", *id)
+		logrus.WithError(err).Error(errMsg)
+		return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
+	}
+
+	return framework.Respond(ctx, w, nil, http.StatusOK)
+}
diff --git a/pkg/server/server.go b/pkg/server/server.go
index 96bda5e..94edf36 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -20,14 +20,16 @@ import (
 )
 
 const (
-	HealthPrefix      = "/health"
-	ReadinessPrefix   = "/readiness"
-	V1Prefix          = "/v1"
-	DIDsPrefix        = "/dids"
-	SchemasPrefix     = "/schemas"
-	CredentialsPrefix = "/credentials"
-	ManifestsPrefix   = "/manifests"
-	KeyStorePrefix    = "/keys"
+	HealthPrefix       = "/health"
+	ReadinessPrefix    = "/readiness"
+	V1Prefix           = "/v1"
+	DIDsPrefix         = "/dids"
+	SchemasPrefix      = "/schemas"
+	CredentialsPrefix  = "/credentials"
+	ManifestsPrefix    = "/manifests"
+	ApplicationsPrefix = "/applications"
+	ResponsesPrefix    = "/responses"
+	KeyStorePrefix     = "/keys"
 )
 
 // SSIServer exposes all dependencies needed to run a http server and all its services
@@ -163,11 +165,22 @@ func (s *SSIServer) ManifestAPI(service svcframework.Service) (err error) {
 		return util.LoggingErrorMsg(err, "could not create manifest router")
 	}
 
-	handlerPath := V1Prefix + ManifestsPrefix
+	manifestHandlerPath := V1Prefix + ManifestsPrefix
+	applicationsHandlerPath := V1Prefix + ManifestsPrefix + ApplicationsPrefix
+	responsesHandlerPath := V1Prefix + ManifestsPrefix + ResponsesPrefix
 
-	s.Handle(http.MethodPut, handlerPath, manifestRouter.CreateManifest)
-	s.Handle(http.MethodGet, handlerPath, manifestRouter.GetManifests)
-	s.Handle(http.MethodGet, path.Join(handlerPath, "/:id"), manifestRouter.GetManifest)
-	s.Handle(http.MethodDelete, path.Join(handlerPath, "/:id"), manifestRouter.DeleteManifest)
+	s.Handle(http.MethodPut, manifestHandlerPath, manifestRouter.CreateManifest)
+	s.Handle(http.MethodGet, manifestHandlerPath, manifestRouter.GetManifests)
+	s.Handle(http.MethodGet, path.Join(manifestHandlerPath, "/:id"), manifestRouter.GetManifest)
+	s.Handle(http.MethodDelete, path.Join(manifestHandlerPath, "/:id"), manifestRouter.DeleteManifest)
+
+	s.Handle(http.MethodPut, applicationsHandlerPath, manifestRouter.SubmitApplication)
+	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.MethodGet, responsesHandlerPath, manifestRouter.GetResponses)
+	s.Handle(http.MethodGet, path.Join(responsesHandlerPath, "/:id"), manifestRouter.GetResponse)
+	s.Handle(http.MethodDelete, path.Join(responsesHandlerPath, "/:id"), manifestRouter.DeleteResponse)
 	return
 }
diff --git a/pkg/service/manifest/manifest.go b/pkg/service/manifest/manifest.go
index 8abb735..5be797f 100644
--- a/pkg/service/manifest/manifest.go
+++ b/pkg/service/manifest/manifest.go
@@ -1,22 +1,23 @@
 package manifest
 
 import (
-	"encoding/json"
 	"fmt"
-	"github.com/TBD54566975/ssi-sdk/credential/exchange"
+	"github.com/TBD54566975/ssi-sdk/credential"
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
-	"github.com/TBD54566975/ssi-sdk/crypto"
 	"github.com/sirupsen/logrus"
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
+	credentialstorage "github.com/tbd54566975/ssi-service/pkg/service/credential/storage"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
+	"time"
 )
 
 type Service struct {
-	storage manifeststorage.Storage
-	config  config.ManifestServiceConfig
+	manifestStorage   manifeststorage.Storage
+	credentialStorage credentialstorage.Storage
+	config            config.ManifestServiceConfig
 }
 
 func (s Service) Type() framework.Type {
@@ -24,12 +25,20 @@ func (s Service) Type() framework.Type {
 }
 
 func (s Service) Status() framework.Status {
-	if s.storage == nil {
+	if s.manifestStorage == nil {
 		return framework.Status{
 			Status:  framework.StatusNotReady,
-			Message: "no storage",
+			Message: "no manifestStorage",
 		}
 	}
+
+	if s.credentialStorage == nil {
+		return framework.Status{
+			Status:  framework.StatusNotReady,
+			Message: "no credentialStorage",
+		}
+	}
+
 	return framework.Status{Status: framework.StatusReady}
 }
 
@@ -40,124 +49,286 @@ func (s Service) Config() config.ManifestServiceConfig {
 func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage) (*Service, error) {
 	manifestStorage, err := manifeststorage.NewManifestStorage(s)
 	if err != nil {
-		errMsg := "could not instantiate storage for the manifest service"
+		errMsg := "could not instantiate manifestStorage for the manifest service"
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	credentialStorage, err := credentialstorage.NewCredentialStorage(s)
+	if err != nil {
+		errMsg := "could not instantiate credentialStorage for the manifest service"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 	return &Service{
-		storage: manifestStorage,
-		config:  config,
+		manifestStorage:   manifestStorage,
+		credentialStorage: credentialStorage,
+		config:            config,
 	}, nil
 }
 
 func (s Service) CreateManifest(request CreateManifestRequest) (*CreateManifestResponse, error) {
 	logrus.Debugf("creating manifest: %+v", request)
 
-	builder := manifest.NewCredentialManifestBuilder()
-	issuer := manifest.Issuer{ID: request.Issuer, Name: request.Issuer}
-
-	if err := builder.SetIssuer(issuer); err != nil {
-		errMsg := fmt.Sprintf("could not build manifest when setting issuer: %s", request.Issuer)
+	mfst := request.Manifest
+	if err := mfst.IsValid(); err != nil {
+		errMsg := "manifest is not valid"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	// TODO: (Neal) Add dynamic claim formats
-	if err := builder.SetClaimFormat(exchange.ClaimFormat{
-		JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
-	}); err != nil {
-		errMsg := fmt.Sprintf("could not build manifest when setting claim format")
+	// store the manifest
+	storageRequest := manifeststorage.StoredManifest{
+		ID:       mfst.ID,
+		Manifest: mfst,
+		Issuer:   mfst.Issuer.ID,
+	}
+
+	if err := s.manifestStorage.StoreManifest(storageRequest); err != nil {
+		errMsg := "could not store manifest"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	// parse OutputDescriptors
-	odJsonString, err := json.Marshal(request.OutputDescriptors)
+	// return the result
+	response := CreateManifestResponse{Manifest: mfst}
+	return &response, nil
+}
+
+func (s Service) GetManifest(request GetManifestRequest) (*GetManifestResponse, error) {
+
+	logrus.Debugf("getting manifest: %s", request.ID)
+
+	gotManifest, err := s.manifestStorage.GetManifest(request.ID)
 	if err != nil {
-		errMsg := "could not marshal request output descriptors"
+		errMsg := fmt.Sprintf("could not get manifest: %s", request.ID)
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	od := []manifest.OutputDescriptor{}
-	err = json.Unmarshal(odJsonString, &od)
+	response := GetManifestResponse{Manifest: gotManifest.Manifest}
+	return &response, nil
+}
+
+func (s Service) GetManifests() (*GetManifestsResponse, error) {
+	gotManifests, err := s.manifestStorage.GetManifests()
+
 	if err != nil {
-		errMsg := "could not unmarshal output descriptors"
+		errMsg := fmt.Sprintf("could not get manifests(s)")
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	builder.SetOutputDescriptors(od)
+	var manifests []manifest.CredentialManifest
+	for _, manifest := range gotManifests {
+		manifests = append(manifests, manifest.Manifest)
+	}
+	response := GetManifestsResponse{Manifests: manifests}
+	return &response, nil
+}
+
+func (s Service) DeleteManifest(request DeleteManifestRequest) error {
 
-	// parse PresentationDefinition
-	pdJsonString, err := json.Marshal(request.PresentationDefinition)
-	if err != nil {
-		errMsg := "could not marshal request presentation definition"
+	logrus.Debugf("deleting manifest: %s", request.ID)
+
+	if err := s.manifestStorage.DeleteManifest(request.ID); err != nil {
+		errMsg := fmt.Sprintf("could not delete manifest with id: %s", request.ID)
+		return util.LoggingErrorMsg(err, errMsg)
+	}
+
+	return nil
+}
+
+// TODO: (Neal) Add entire validation framework in place of these validation checks - https://github.com/TBD54566975/ssi-service/issues/95
+func isValidApplication(gotManifest *manifeststorage.StoredManifest, application manifest.CredentialApplication) error {
+	if gotManifest == nil {
+		return util.LoggingNewError(fmt.Sprintf("application is not valid. A manifest does not exist with id: %s", application.ManifestID))
+	}
+
+	inputDescriptors := gotManifest.Manifest.PresentationDefinition.InputDescriptors
+	inputDescriptorIDs := make(map[string]bool)
+	for _, inputDescriptor := range inputDescriptors {
+		inputDescriptorIDs[inputDescriptor.ID] = true
+	}
+
+	for _, submissionDescriptor := range application.PresentationSubmission.DescriptorMap {
+		if inputDescriptorIDs[submissionDescriptor.ID] != true {
+			return util.LoggingNewError("application is not valid. The submission descriptor ids do not match the input descriptor ids")
+		}
+	}
+
+	return nil
+}
+
+func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) {
+	credApp := request.Application
+
+	if err := credApp.IsValid(); err != nil {
+		errMsg := "application is not valid"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	pd := exchange.PresentationDefinition{}
-	err = json.Unmarshal(pdJsonString, &pd)
+	gotManifest, err := s.manifestStorage.GetManifest(credApp.ManifestID)
 	if err != nil {
-		errMsg := "could not unmarshal presentation definition"
+		return nil, util.LoggingErrorMsg(err, "problem with retrieving manifest during application validation")
+	}
+
+	// validate
+	if err := isValidApplication(gotManifest, credApp); err != nil {
+		errMsg := fmt.Sprintf("could not validate application")
+		return nil, util.LoggingErrorMsg(err, errMsg)
+	}
+
+	// store the application
+	storageRequest := manifeststorage.StoredApplication{
+		ID:          credApp.ID,
+		Application: credApp,
+		ManifestID:  request.Application.ManifestID,
+	}
+
+	if err := s.manifestStorage.StoreApplication(storageRequest); err != nil {
+		errMsg := "could not store application"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
-	builder.SetPresentationDefinition(pd)
 
-	mfst, err := builder.Build()
+	// build the credential response
+	responseBuilder := manifest.NewCredentialResponseBuilder(request.Application.ManifestID)
+	responseBuilder.SetApplicationID(credApp.ID)
+	responseBuilder.SetFulfillment(credApp.PresentationSubmission.DescriptorMap)
+
+	credRes, err := responseBuilder.Build()
 	if err != nil {
-		errMsg := "could not build manifest"
+		errMsg := "could not build response"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	// store the manifest
-	storageRequest := manifeststorage.StoredManifest{
-		ID:       mfst.ID,
-		Manifest: *mfst,
-		Issuer:   request.Issuer,
+	// store the response
+	responseStorageRequest := manifeststorage.StoredResponse{
+		ID:         credRes.ID,
+		Response:   *credRes,
+		ManifestID: request.Application.ManifestID,
 	}
 
-	if err := s.storage.StoreManifest(storageRequest); err != nil {
-		errMsg := "could not store manifest"
+	var creds []credential.VerifiableCredential
+	for _, od := range gotManifest.Manifest.OutputDescriptors {
+
+		if err := s.manifestStorage.StoreResponse(responseStorageRequest); err != nil {
+			errMsg := "could not store response"
+			return nil, util.LoggingErrorMsg(err, errMsg)
+		}
+
+		credentialBuilder := credential.NewVerifiableCredentialBuilder()
+		credentialBuilder.SetIssuer(gotManifest.Manifest.Issuer.ID)
+		credentialBuilder.SetCredentialSubject(map[string]interface{}{
+			"id": request.RequesterDID,
+		})
+		credentialBuilder.SetIssuanceDate(time.Now().Format(time.RFC3339))
+
+		cred, err := credentialBuilder.Build()
+		if err != nil {
+			errMsg := "could not build credential"
+			return nil, util.LoggingErrorMsg(err, errMsg)
+		}
+
+		credentialStorageRequest := credentialstorage.StoredCredential{
+			ID:           cred.ID,
+			Credential:   *cred,
+			Issuer:       gotManifest.Manifest.Issuer.ID,
+			Subject:      request.RequesterDID,
+			Schema:       od.Schema,
+			IssuanceDate: time.Now().Format(time.RFC3339),
+		}
+
+		if err := s.credentialStorage.StoreCredential(credentialStorageRequest); err != nil {
+			errMsg := "could not store credential"
+			return nil, util.LoggingErrorMsg(err, errMsg)
+		}
+
+		creds = append(creds, *cred)
+	}
+
+	response := SubmitApplicationResponse{Response: *credRes, Credential: creds}
+	return &response, nil
+}
+
+func (s Service) GetApplication(request GetApplicationRequest) (*GetApplicationResponse, error) {
+
+	logrus.Debugf("getting application: %s", request.ID)
+
+	gotApp, err := s.manifestStorage.GetApplication(request.ID)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get application: %s", request.ID)
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	// return the result
-	response := CreateManifestResponse{Manifest: *mfst}
+	response := GetApplicationResponse{Application: gotApp.Application}
 	return &response, nil
 }
 
-func (s Service) GetManifest(request GetManifestRequest) (*GetManifestResponse, error) {
+func (s Service) GetApplications() (*GetApplicationsResponse, error) {
 
-	logrus.Debugf("getting manifest: %s", request.ID)
+	logrus.Debugf("getting application(s)")
 
-	gotManifest, err := s.storage.GetManifest(request.ID)
+	gotApps, err := s.manifestStorage.GetApplications()
 	if err != nil {
-		errMsg := fmt.Sprintf("could not get manifest: %s", request.ID)
+		errMsg := fmt.Sprintf("could not get application(s)")
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	response := GetManifestResponse{Manifest: gotManifest.Manifest}
+	var apps []manifest.CredentialApplication
+	for _, cred := range gotApps {
+		apps = append(apps, cred.Application)
+	}
+
+	response := GetApplicationsResponse{Applications: apps}
 	return &response, nil
 }
 
-func (s Service) GetManifests() (*GetManifestsResponse, error) {
-	gotManifests, err := s.storage.GetManifests()
+func (s Service) DeleteApplication(request DeleteApplicationRequest) error {
+
+	logrus.Debugf("deleting application: %s", request.ID)
+
+	if err := s.manifestStorage.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.manifestStorage.GetResponse(request.ID)
 	if err != nil {
-		errMsg := fmt.Sprintf("could not get manifests(s)")
+		errMsg := fmt.Sprintf("could not get response: %s", request.ID)
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	var manifests []manifest.CredentialManifest
-	for _, manifest := range gotManifests {
-		manifests = append(manifests, manifest.Manifest)
+	response := GetResponseResponse{Response: gotResponse.Response}
+	return &response, nil
+}
+
+func (s Service) GetResponses() (*GetResponsesResponse, error) {
+
+	logrus.Debugf("getting response(s)")
+
+	gotResponses, err := s.manifestStorage.GetResponses()
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get response(s)")
+		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
-	response := GetManifestsResponse{Manifests: manifests}
+
+	var responses []manifest.CredentialResponse
+	for _, res := range gotResponses {
+		responses = append(responses, res.Response)
+	}
+
+	response := GetResponsesResponse{Responses: responses}
 	return &response, nil
 }
 
-func (s Service) DeleteManifest(request DeleteManifestRequest) error {
+func (s Service) DeleteResponse(request DeleteResponseRequest) error {
 
-	logrus.Debugf("deleting manifest: %s", request.ID)
+	logrus.Debugf("deleting response: %s", request.ID)
 
-	if err := s.storage.DeleteManifest(request.ID); err != nil {
-		errMsg := fmt.Sprintf("could not delete manifest with id: %s", request.ID)
+	if err := s.manifestStorage.DeleteResponse(request.ID); err != nil {
+		errMsg := fmt.Sprintf("could not delete response with id: %s", request.ID)
 		return util.LoggingErrorMsg(err, errMsg)
 	}
 
diff --git a/pkg/service/manifest/model.go b/pkg/service/manifest/model.go
index 8ad3105..b8f971d 100644
--- a/pkg/service/manifest/model.go
+++ b/pkg/service/manifest/model.go
@@ -1,16 +1,13 @@
 package manifest
 
 import (
-	"github.com/TBD54566975/ssi-sdk/credential/exchange"
+	"github.com/TBD54566975/ssi-sdk/credential"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
 )
 
+// Manifest
 type CreateManifestRequest struct {
-	Issuer string
-	// A context is optional. If not present, we'll apply default, required context values.
-	Context                string
-	OutputDescriptors      []manifestsdk.OutputDescriptor
-	PresentationDefinition exchange.PresentationDefinition
+	Manifest manifestsdk.CredentialManifest
 }
 
 type CreateManifestResponse struct {
@@ -25,10 +22,6 @@ type GetManifestResponse struct {
 	Manifest manifestsdk.CredentialManifest
 }
 
-type GetManifestByIssuerRequest struct {
-	Issuer string
-}
-
 type GetManifestsResponse struct {
 	Manifests []manifestsdk.CredentialManifest
 }
@@ -36,3 +29,47 @@ type GetManifestsResponse struct {
 type DeleteManifestRequest struct {
 	ID string
 }
+
+// Application
+type SubmitApplicationRequest struct {
+	Application  manifestsdk.CredentialApplication
+	RequesterDID string
+}
+
+type SubmitApplicationResponse struct {
+	Response   manifestsdk.CredentialResponse
+	Credential []credential.VerifiableCredential
+}
+
+type GetApplicationRequest struct {
+	ID string
+}
+
+type GetApplicationResponse struct {
+	Application manifestsdk.CredentialApplication
+}
+
+type GetApplicationsResponse struct {
+	Applications []manifestsdk.CredentialApplication
+}
+
+type DeleteApplicationRequest struct {
+	ID string
+}
+
+// Response
+type GetResponseRequest struct {
+	ID string
+}
+
+type GetResponseResponse struct {
+	Response manifestsdk.CredentialResponse
+}
+
+type GetResponsesResponse struct {
+	Responses []manifestsdk.CredentialResponse
+}
+
+type DeleteResponseRequest struct {
+	ID string
+}
diff --git a/pkg/service/manifest/storage/bolt.go b/pkg/service/manifest/storage/bolt.go
index 6be43ed..da60880 100644
--- a/pkg/service/manifest/storage/bolt.go
+++ b/pkg/service/manifest/storage/bolt.go
@@ -9,7 +9,9 @@ import (
 )
 
 const (
-	namespace = "manifest"
+	manifestNamespace    = "manifest"
+	applicationNamespace = "application"
+	responseNamespace    = "response"
 )
 
 type BoltManifestStorage struct {
@@ -36,11 +38,11 @@ func (b BoltManifestStorage) StoreManifest(manifest StoredManifest) error {
 		logrus.WithError(err).Error(errMsg)
 		return errors.Wrapf(err, errMsg)
 	}
-	return b.db.Write(namespace, id, manifestBytes)
+	return b.db.Write(manifestNamespace, id, manifestBytes)
 }
 
 func (b BoltManifestStorage) GetManifest(id string) (*StoredManifest, error) {
-	manifestBytes, err := b.db.Read(namespace, id)
+	manifestBytes, err := b.db.Read(manifestNamespace, id)
 	if err != nil {
 		errMsg := fmt.Sprintf("could not get manifest: %s", id)
 		logrus.WithError(err).Error(errMsg)
@@ -62,7 +64,7 @@ func (b BoltManifestStorage) GetManifest(id string) (*StoredManifest, error) {
 
 // GetManifests attempts to get all stored manifests. It will return those it can even if it has trouble with some.
 func (b BoltManifestStorage) GetManifests() ([]StoredManifest, error) {
-	gotManifests, err := b.db.ReadAll(namespace)
+	gotManifests, err := b.db.ReadAll(manifestNamespace)
 	if err != nil {
 		errMsg := "could not get all manifests"
 		logrus.WithError(err).Error(errMsg)
@@ -83,10 +85,146 @@ func (b BoltManifestStorage) GetManifests() ([]StoredManifest, error) {
 }
 
 func (b BoltManifestStorage) DeleteManifest(id string) error {
-	if err := b.db.Delete(namespace, id); err != nil {
+	if err := b.db.Delete(manifestNamespace, id); err != nil {
 		errMsg := fmt.Sprintf("could not delete manifest: %s", id)
 		logrus.WithError(err).Error(errMsg)
 		return errors.Wrapf(err, errMsg)
 	}
 	return nil
 }
+
+func (b BoltManifestStorage) StoreApplication(application StoredApplication) error {
+	id := application.Application.ID
+	if id == "" {
+		err := errors.New("could not store application without an ID")
+		logrus.WithError(err).Error()
+		return err
+	}
+	applicationBytes, err := json.Marshal(application)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not store application: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return errors.Wrapf(err, errMsg)
+	}
+	return b.db.Write(applicationNamespace, id, applicationBytes)
+}
+
+func (b BoltManifestStorage) GetApplication(id string) (*StoredApplication, error) {
+	applicationBytes, err := b.db.Read(applicationNamespace, id)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get application: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrapf(err, errMsg)
+	}
+	if len(applicationBytes) == 0 {
+		err := fmt.Errorf("application not found with id: %s", id)
+		logrus.WithError(err).Error("could not get application from storage")
+		return nil, err
+	}
+	var stored StoredApplication
+	if err := json.Unmarshal(applicationBytes, &stored); err != nil {
+		errMsg := fmt.Sprintf("could not unmarshal stored application: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrapf(err, errMsg)
+	}
+	return &stored, nil
+}
+
+// GetApplications attempts to get all stored applications. It will return those it can even if it has trouble with some.
+func (b BoltManifestStorage) GetApplications() ([]StoredApplication, error) {
+	gotApplications, err := b.db.ReadAll(applicationNamespace)
+	if err != nil {
+		errMsg := "could not get all applications"
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrap(err, errMsg)
+	}
+	if len(gotApplications) == 0 {
+		logrus.Info("no applications to get")
+		return nil, nil
+	}
+	var stored []StoredApplication
+	for _, applicationBytes := range gotApplications {
+		var nextApplication StoredApplication
+		if err := json.Unmarshal(applicationBytes, &nextApplication); err == nil {
+			stored = append(stored, nextApplication)
+		}
+	}
+	return stored, nil
+}
+
+func (b BoltManifestStorage) DeleteApplication(id string) error {
+	if err := b.db.Delete(applicationNamespace, id); err != nil {
+		errMsg := fmt.Sprintf("could not delete application: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return errors.Wrapf(err, errMsg)
+	}
+	return nil
+}
+
+func (b BoltManifestStorage) StoreResponse(response StoredResponse) error {
+	id := response.Response.ID
+	if id == "" {
+		err := errors.New("could not store response without an ID")
+		logrus.WithError(err).Error()
+		return err
+	}
+	responseBytes, err := json.Marshal(response)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not store response: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return errors.Wrapf(err, errMsg)
+	}
+	return b.db.Write(responseNamespace, id, responseBytes)
+}
+
+func (b BoltManifestStorage) GetResponse(id string) (*StoredResponse, error) {
+	responseBytes, err := b.db.Read(responseNamespace, id)
+	if err != nil {
+		errMsg := fmt.Sprintf("could not get response: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrapf(err, errMsg)
+	}
+	if len(responseBytes) == 0 {
+		err := fmt.Errorf("response not found with id: %s", id)
+		logrus.WithError(err).Error("could not get response from storage")
+		return nil, err
+	}
+	var stored StoredResponse
+	if err := json.Unmarshal(responseBytes, &stored); err != nil {
+		errMsg := fmt.Sprintf("could not unmarshal stored response: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrapf(err, errMsg)
+	}
+	return &stored, nil
+}
+
+// GetResponses attempts to get all stored responses. It will return those it can even if it has trouble with some.
+func (b BoltManifestStorage) GetResponses() ([]StoredResponse, error) {
+	gotResponses, err := b.db.ReadAll(responseNamespace)
+	if err != nil {
+		errMsg := "could not get all responses"
+		logrus.WithError(err).Error(errMsg)
+		return nil, errors.Wrap(err, errMsg)
+	}
+	if len(gotResponses) == 0 {
+		logrus.Info("no responses to get")
+		return nil, nil
+	}
+	var stored []StoredResponse
+	for _, responseBytes := range gotResponses {
+		var nextResponse StoredResponse
+		if err := json.Unmarshal(responseBytes, &nextResponse); err == nil {
+			stored = append(stored, nextResponse)
+		}
+	}
+	return stored, nil
+}
+
+func (b BoltManifestStorage) DeleteResponse(id string) error {
+	if err := b.db.Delete(responseNamespace, id); err != nil {
+		errMsg := fmt.Sprintf("could not delete response: %s", id)
+		logrus.WithError(err).Error(errMsg)
+		return errors.Wrapf(err, errMsg)
+	}
+	return nil
+}
diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go
index b78a39c..9a94780 100644
--- a/pkg/service/manifest/storage/storage.go
+++ b/pkg/service/manifest/storage/storage.go
@@ -14,11 +14,36 @@ type StoredManifest struct {
 	Issuer   string                      `json:"issuer"`
 }
 
+type StoredApplication struct {
+	ID          string                         `json:"id"`
+	Application manifest.CredentialApplication `json:"application"`
+	ManifestID  string                         `json:"manifestId"`
+}
+
+type StoredResponse struct {
+	ID         string                      `json:"id"`
+	Response   manifest.CredentialResponse `json:"response"`
+	ManifestID string                      `json:"manifestId"`
+}
+
 type Storage interface {
+	// Credential Manifest
 	StoreManifest(manifest StoredManifest) error
 	GetManifest(id string) (*StoredManifest, error)
 	GetManifests() ([]StoredManifest, error)
 	DeleteManifest(id string) error
+
+	// Credential Application
+	StoreApplication(application StoredApplication) error
+	GetApplication(id string) (*StoredApplication, error)
+	GetApplications() ([]StoredApplication, error)
+	DeleteApplication(id string) error
+
+	// Credential Response
+	StoreResponse(response StoredResponse) error
+	GetResponse(id string) (*StoredResponse, error)
+	GetResponses() ([]StoredResponse, error)
+	DeleteResponse(id string) error
 }
 
 // NewManifestStorage finds the manifest storage impl for a given ServiceStorage value
diff --git a/pkg/service/service.go b/pkg/service/service.go
index 8945daa..111eb89 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -2,13 +2,13 @@ package service
 
 import (
 	"fmt"
-	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
 
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
 	"github.com/tbd54566975/ssi-service/pkg/service/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/did"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
 	"github.com/tbd54566975/ssi-service/pkg/service/schema"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )


Test patch:
diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go
index 57b564b..c936bde 100644
--- a/pkg/server/router/manifest_test.go
+++ b/pkg/server/router/manifest_test.go
@@ -3,6 +3,8 @@ package router
 import (
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
+	"github.com/TBD54566975/ssi-sdk/crypto"
+	"github.com/google/uuid"
 	"github.com/stretchr/testify/assert"
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
@@ -46,50 +48,94 @@ func TestManifestRouter(t *testing.T) {
 		assert.Equal(tt, framework.Manifest, manifestService.Type())
 		assert.Equal(tt, framework.StatusReady, manifestService.Status().Status)
 
-		// good request
+		// good manifest request
 		createManifestRequest := getValidManifestRequest()
 
 		createdManifest, err := manifestService.CreateManifest(createManifestRequest)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, createdManifest)
 		assert.NotEmpty(tt, createdManifest.Manifest)
+
+		// good application request
+		createApplicationRequest := getValidApplicationRequest(createdManifest.Manifest.ID, createManifestRequest.Manifest.PresentationDefinition.InputDescriptors[0].ID)
+
+		createdApplication, err := manifestService.SubmitApplication(createApplicationRequest)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, createdManifest)
+		assert.NotEmpty(tt, createdApplication.Response.ID)
 	})
+
 }
 
 func getValidManifestRequest() manifest.CreateManifestRequest {
 	createManifestRequest := manifest.CreateManifestRequest{
-		Issuer:  "did:abc:123",
-		Context: "context123",
-		PresentationDefinition: exchange.PresentationDefinition{
-			ID: "pres-def-id",
-			InputDescriptors: []exchange.InputDescriptor{
-				{
-					ID: "test-id",
-					Constraints: &exchange.Constraints{
-						Fields: []exchange.Field{
-							{
-								Path: []string{".vc.id"},
+		Manifest: manifestsdk.CredentialManifest{
+			ID:          "WA-DL-CLASS-A",
+			SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
+			Issuer: manifestsdk.Issuer{
+				ID: "did:abc:123",
+			},
+			PresentationDefinition: &exchange.PresentationDefinition{
+				ID: "pres-def-id",
+				InputDescriptors: []exchange.InputDescriptor{
+					{
+						ID: "test-id",
+						Constraints: &exchange.Constraints{
+							Fields: []exchange.Field{
+								{
+									Path: []string{".vc.id"},
+								},
 							},
 						},
 					},
 				},
 			},
-		},
-		OutputDescriptors: []manifestsdk.OutputDescriptor{
-			{
-				ID:          "id1",
-				Schema:      "https://test.com/schema",
-				Name:        "good ID",
-				Description: "it's all good",
-			},
-			{
-				ID:          "id2",
-				Schema:      "https://test.com/schema",
-				Name:        "good ID",
-				Description: "it's all good",
+			OutputDescriptors: []manifestsdk.OutputDescriptor{
+				{
+					ID:          "id1",
+					Schema:      "https://test.com/schema",
+					Name:        "good ID",
+					Description: "it's all good",
+				},
+				{
+					ID:          "id2",
+					Schema:      "https://test.com/schema",
+					Name:        "good ID",
+					Description: "it's all good",
+				},
 			},
 		},
 	}
 
 	return createManifestRequest
 }
+
+func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest {
+
+	createApplication := manifestsdk.CredentialApplication{
+		ID:          uuid.New().String(),
+		SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
+		ManifestID:  manifestID,
+		Format: &exchange.ClaimFormat{
+			JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+		},
+		PresentationSubmission: &exchange.PresentationSubmission{
+			ID:           "psid",
+			DefinitionID: "definitionId",
+			DescriptorMap: []exchange.SubmissionDescriptor{
+				{
+					ID:     submissionDescriptorId,
+					Format: "jwt",
+					Path:   "path",
+				},
+			},
+		},
+	}
+
+	createApplicationRequest := manifest.SubmitApplicationRequest{
+		Application:  createApplication,
+		RequesterDID: "did:user:123",
+	}
+
+	return createApplicationRequest
+}
diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go
index 6854dc8..b9fccdd 100644
--- a/pkg/server/server_test.go
+++ b/pkg/server/server_test.go
@@ -748,10 +748,8 @@ func TestManifestAPI(t *testing.T) {
 
 		manifestService := newManifestService(tt, bolt)
 
-		// missing required field: OutputDescriptors
-		badManifestRequest := router.CreateManifestRequest{
-			Issuer: "did:abc:123",
-		}
+		// missing required field: Manifest
+		badManifestRequest := router.CreateManifestRequest{}
 
 		badRequestValue := newRequestValue(tt, badManifestRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", badRequestValue)
@@ -765,39 +763,7 @@ func TestManifestAPI(t *testing.T) {
 		w.Flush()
 
 		// good request
-		createManifestRequest := router.CreateManifestRequest{
-			Issuer:  "did:abc:123",
-			Context: "context123",
-			PresentationDefinition: exchange.PresentationDefinition{
-				ID: "pres-def-id",
-				InputDescriptors: []exchange.InputDescriptor{
-					{
-						ID: "test-id",
-						Constraints: &exchange.Constraints{
-							Fields: []exchange.Field{
-								{
-									Path: []string{".vc.id"},
-								},
-							},
-						},
-					},
-				},
-			},
-			OutputDescriptors: []manifestsdk.OutputDescriptor{
-				{
-					ID:          "id1",
-					Schema:      "https://test.com/schema",
-					Name:        "good ID",
-					Description: "it's all good",
-				},
-				{
-					ID:          "id2",
-					Schema:      "https://test.com/schema",
-					Name:        "good ID",
-					Description: "it's all good",
-				},
-			},
-		}
+		createManifestRequest := getValidManifestRequest()
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
@@ -957,6 +923,225 @@ func TestManifestAPI(t *testing.T) {
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), fmt.Sprintf("could not get manifest with id: %s", resp.Manifest.ID))
 	})
+
+	t.Run("Test Submit Application", func(tt *testing.T) {
+		bolt, err := storage.NewBoltDB()
+
+		// remove the db file after the test
+		tt.Cleanup(func() {
+			_ = bolt.Close()
+			_ = os.Remove(storage.DBFile)
+		})
+
+		manifestService := newManifestService(tt, bolt)
+
+		// missing required field: Application
+		badManifestRequest := router.SubmitApplicationRequest{
+			RequesterDID: "id123",
+		}
+
+		badRequestValue := newRequestValue(tt, badManifestRequest)
+		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", badRequestValue)
+		w := httptest.NewRecorder()
+
+		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+		assert.Error(tt, err)
+		assert.Contains(tt, err.Error(), "invalid submit application request")
+
+		// reset the http recorder
+		w.Flush()
+
+		// good request
+		createManifestRequest := getValidManifestRequest()
+
+		requestValue := newRequestValue(tt, createManifestRequest)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
+		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		assert.NoError(tt, err)
+
+		var resp router.CreateManifestResponse
+		err = json.NewDecoder(w.Body).Decode(&resp)
+		assert.NoError(tt, err)
+
+		assert.NotEmpty(tt, resp.Manifest)
+		assert.Equal(tt, resp.Manifest.Issuer.ID, "did:abc:123")
+
+		// good application request
+		createApplicationRequest := getValidApplicationRequest(resp.Manifest.ID, resp.Manifest.PresentationDefinition.InputDescriptors[0].ID)
+
+		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
+		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+
+		var appResp router.SubmitApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&appResp)
+		assert.NoError(tt, err)
+
+		assert.NotEmpty(tt, appResp.Response)
+		assert.Equal(tt, appResp.Response.ManifestID, resp.Manifest.ID)
+
+	})
+
+	t.Run("Test Get Application By ID and Get Applications", func(tt *testing.T) {
+		bolt, err := storage.NewBoltDB()
+
+		// remove the db file after the test
+		tt.Cleanup(func() {
+			_ = bolt.Close()
+			_ = os.Remove(storage.DBFile)
+		})
+
+		manifestService := newManifestService(tt, bolt)
+
+		w := httptest.NewRecorder()
+
+		// get a application that doesn't exit
+		req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications/bad", nil)
+		err = manifestService.GetApplication(newRequestContext(), w, req)
+		assert.Error(tt, err)
+		assert.Contains(tt, err.Error(), "cannot get application without ID parameter")
+
+		// reset recorder between calls
+		w.Flush()
+
+		// good manifest request
+		createManifestRequest := getValidManifestRequest()
+
+		requestValue := newRequestValue(tt, createManifestRequest)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
+		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		assert.NoError(tt, err)
+
+		var resp router.CreateManifestResponse
+		err = json.NewDecoder(w.Body).Decode(&resp)
+		assert.NoError(tt, err)
+
+		// good application request
+		createApplicationRequest := getValidApplicationRequest(resp.Manifest.ID, resp.Manifest.PresentationDefinition.InputDescriptors[0].ID)
+
+		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
+		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+
+		var appResp router.SubmitApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&appResp)
+		assert.NoError(tt, err)
+
+		// get response by id
+		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/responses/%s", appResp.Response.ID), nil)
+		err = manifestService.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
+		assert.NoError(tt, err)
+
+		var getResponseResponse router.GetResponseResponse
+		err = json.NewDecoder(w.Body).Decode(&getResponseResponse)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getResponseResponse)
+		assert.Equal(tt, appResp.Response.ID, getResponseResponse.Response.ID)
+
+		// get all responses
+		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/responses", nil)
+		err = manifestService.GetResponses(newRequestContext(), w, req)
+
+		var getResponsesResp router.GetResponsesResponse
+		err = json.NewDecoder(w.Body).Decode(&getResponsesResp)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getResponsesResp)
+
+		assert.Len(tt, getResponsesResp.Responses, 1)
+
+		// get all applications
+		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
+		err = manifestService.GetApplications(newRequestContext(), w, req)
+
+		var getApplicationsResp router.GetApplicationsResponse
+		err = json.NewDecoder(w.Body).Decode(&getApplicationsResp)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getApplicationsResp)
+
+		assert.Len(tt, getApplicationsResp.Applications, 1)
+
+		// get application by id
+		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil)
+		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
+		assert.NoError(tt, err)
+
+		var getApplicationResponse router.GetApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&getApplicationResponse)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getApplicationResponse)
+		assert.Equal(tt, getApplicationsResp.Applications[0].ID, getApplicationResponse.ID)
+	})
+
+	t.Run("Test Delete Application", func(tt *testing.T) {
+		bolt, err := storage.NewBoltDB()
+
+		// remove the db file after the test
+		tt.Cleanup(func() {
+			_ = bolt.Close()
+			_ = os.Remove(storage.DBFile)
+		})
+
+		manifestService := newManifestService(tt, bolt)
+
+		// good manifest request
+		createManifestRequest := getValidManifestRequest()
+
+		requestValue := newRequestValue(tt, createManifestRequest)
+		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
+		w := httptest.NewRecorder()
+		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		assert.NoError(tt, err)
+
+		var resp router.CreateManifestResponse
+		err = json.NewDecoder(w.Body).Decode(&resp)
+		assert.NoError(tt, err)
+
+		// good application request
+		createApplicationRequest := getValidApplicationRequest(resp.Manifest.ID, resp.Manifest.PresentationDefinition.InputDescriptors[0].ID)
+
+		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
+		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
+		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+
+		var appResp router.SubmitApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&appResp)
+		assert.NoError(tt, err)
+
+		// get all applications
+		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
+		err = manifestService.GetApplications(newRequestContext(), w, req)
+
+		var getApplicationsResp router.GetApplicationsResponse
+		err = json.NewDecoder(w.Body).Decode(&getApplicationsResp)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getApplicationsResp)
+
+		assert.Len(tt, getApplicationsResp.Applications, 1)
+
+		// get the application
+		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil)
+		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
+		assert.NoError(tt, err)
+
+		var getApplicationResp router.GetApplicationResponse
+		err = json.NewDecoder(w.Body).Decode(&getApplicationResp)
+		assert.NoError(tt, err)
+		assert.NotEmpty(tt, getApplicationResp)
+		assert.Equal(tt, resp.Manifest.ID, getApplicationResp.Application.ManifestID)
+
+		// delete the application
+		req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationResp.Application.ID), nil)
+		err = manifestService.DeleteApplication(newRequestContextWithParams(map[string]string{"id": getApplicationResp.Application.ID}), w, req)
+		assert.NoError(tt, err)
+
+		w.Flush()
+
+		// get it back
+		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", appResp.Response.ID), nil)
+		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
+		assert.Error(tt, err)
+		assert.Contains(tt, err.Error(), fmt.Sprintf("could not get application with id: %s", appResp.Response.ID))
+	})
 }
 
 func newManifestService(t *testing.T, bolt *storage.BoltDB) *router.ManifestRouter {
@@ -1111,40 +1296,75 @@ func newRequestContextWithParams(params map[string]string) context.Context {
 	return httptreemux.AddParamsToContext(ctx, params)
 }
 
-func getValidManifestRequest() router.CreateManifestRequest {
-	createManifestRequest := router.CreateManifestRequest{
-		Issuer:  "did:abc:123",
-		Context: "context123",
-		PresentationDefinition: exchange.PresentationDefinition{
-			ID: "pres-def-id",
-			InputDescriptors: []exchange.InputDescriptor{
-				{
-					ID: "test-id",
-					Constraints: &exchange.Constraints{
-						Fields: []exchange.Field{
-							{
-								Path: []string{".vc.id"},
+func getValidManifestRequest() manifest.CreateManifestRequest {
+	createManifestRequest := manifest.CreateManifestRequest{
+		Manifest: manifestsdk.CredentialManifest{
+			ID:          "WA-DL-CLASS-A",
+			SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
+			Issuer: manifestsdk.Issuer{
+				ID: "did:abc:123",
+			},
+			PresentationDefinition: &exchange.PresentationDefinition{
+				ID: "pres-def-id",
+				InputDescriptors: []exchange.InputDescriptor{
+					{
+						ID: "test-id",
+						Constraints: &exchange.Constraints{
+							Fields: []exchange.Field{
+								{
+									Path: []string{".vc.id"},
+								},
 							},
 						},
 					},
 				},
 			},
-		},
-		OutputDescriptors: []manifestsdk.OutputDescriptor{
-			{
-				ID:          "id1",
-				Schema:      "https://test.com/schema",
-				Name:        "good ID",
-				Description: "it's all good",
-			},
-			{
-				ID:          "id2",
-				Schema:      "https://test.com/schema",
-				Name:        "good ID",
-				Description: "it's all good",
+			OutputDescriptors: []manifestsdk.OutputDescriptor{
+				{
+					ID:          "id1",
+					Schema:      "https://test.com/schema",
+					Name:        "good ID",
+					Description: "it's all good",
+				},
+				{
+					ID:          "id2",
+					Schema:      "https://test.com/schema",
+					Name:        "good ID",
+					Description: "it's all good",
+				},
 			},
 		},
 	}
 
 	return createManifestRequest
 }
+
+func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest {
+
+	createApplication := manifestsdk.CredentialApplication{
+		ID:          uuid.New().String(),
+		SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
+		ManifestID:  manifestID,
+		Format: &exchange.ClaimFormat{
+			JWT: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}},
+		},
+		PresentationSubmission: &exchange.PresentationSubmission{
+			ID:           "psid",
+			DefinitionID: "definitionId",
+			DescriptorMap: []exchange.SubmissionDescriptor{
+				{
+					ID:     submissionDescriptorId,
+					Format: "jwt",
+					Path:   "path",
+				},
+			},
+		},
+	}
+
+	createApplicationRequest := manifest.SubmitApplicationRequest{
+		Application:  createApplication,
+		RequesterDID: "did:user:123",
+	}
+
+	return createApplicationRequest
+}