---
title: "Tutorial (30 min)"
description: "Please note: You need to be an Enterprise Stack customer & have access to the private enterprise stack images, to go through this tutorial."
stack: "Enterprise Stack (commercial) — version 0.21.0"
stack_version: "0.21.0"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/home/tutorial-30-min
generated: 2026-07-08
---
# Tutorial (30 min)

**Note:**

Please note: You need to be an Enterprise Stack customer & have access to the private enterprise stack images, to go
through this tutorial.

<br/> 

In this tutorial, we will provide a comprehensive guide on **setting up the enterprise API on your local machine**. We
will
demonstrate the **complete process of issuing and verifying a W3C credential** that includes a revocation status
property.
Additionally, you can watch the accompanying video guide below.

Video: https://youtu.be/_oNwxT1-7ns

## 1. Setup

For the setup, we will be using
the [walt.id enterprise quickstart repository](https://github.com/walt-id/waltid-enterprise-quickstart). It can be used
to explore enterprise
features via a CLI tool and/or to bring up the whole stack using Docker Compose. We will be using the latter for this
tutorial.

**Clone the repo**

```bash
git clone https://github.com/walt-id/waltid-enterprise-quickstart.git
```

**Change Working Directory**

```bash
cd waltid-enterprise-quickstart
```

**Add Docker Token**

Save the docker-access token provided by walt.id to get access to the private enterprise stack img.

```bash
echo "DOCKER_TOKEN_PROVIDED_BY_WALT_ID_HERE" > .docker-token
```

**Run the stack via docker-compose**

```bash
./waltid-enterprise run
```

When running the docker-compose a mongoDB database is created (used to store data for the Enterprise Stack) and the
Enterprise API is started.

**Visit the API**

Visit [enterprise.localhost:3000/swagger](http://enterprise.localhost:3000/swagger) to view the API.

**Note:**

Learn more about the base domain (enterprise.localhost)
configuration [here](https://docs.walt.id/enterprise-stack/setup/configurations/config-files/enterprise.md)
and in general about the configurations files available for the Enterprise
Stack [here](https://docs.walt.id/enterprise-stack/setup/configurations/config-files/overview.md).

## 2. Super Admin - Auth

The first step, after the Enterprise Stack API is up and running is to register a super-admin user. One or multiple
super admin accounts can be specified via
the [`superadmin-registration.conf`](https://docs.walt.id/enterprise-stack/setup/configurations/config-files/superadmin-registration.md) file.
This file can be found in the `config` folder of the quickstart-repo in your local
setup. (`waltid-enterprise-quickstart/config`)

### Activate Super Admin

**Option: CURL**

Endpoint:`/v1/superadmin/create-by-token` | [API Reference](http://waltid.enterprise.localhost:3000/swagger/index.html#/Administration%20%2F%20Superadmin/post_v1_superadmin_create_by_token)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/superadmin/create-by-token' \
  -H 'accept: */*' \
  -H 'Content-Type: text/plain' \
  -d '<super-admin-token-specified-in-super-admin-conf-file>'
```

**Body**

```text
<super-admin-token>
```

**Body Content**
<br/>
Please provide the super-admin-token in the body without any quotation marks.
Use the token map key from `superadmin-registration.conf` as value (eg. `super-admin-token`).

---

**Response Codes**

- `200` - Super admin account activated successfully

Now that we have activated the super-admin user, we can login with the super-admin credentials also specified in
the [`superadmin-registration.conf`](https://docs.walt.id/enterprise-stack/setup/configurations/config-files/superadmin-registration.md) using the
regular account/user login endpoint.

### Login as Super Admin

**Option: CURL**

Endpoint:`/auth/account/emailpass` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Authentication/post_auth_account_emailpass)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/auth/account/emailpass' \
  -H 'accept: */*' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "superadmin@walt.id",
    "password": "pw-according-super-admin-conf"
  }'
```

**Body**

```json
{
  "email": "superadmin@walt.id",
  "password": "pw-according-super-admin-conf"
}
```

**Body Parameters**

- `email`: _String_ - Email of the super admin account. Defined in `superadmin-registration.conf`.
- `password`: _String_ - Password of the super admin account. Defined in `superadmin-registration.conf`

---

**Response**

```json
{
  "session_id": "39ed1ecd-aa61-4401-bf35-ca0a14a39c8e",
  "status": "OK",
  "token": "eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiJmZmZmZmZmZi1mZmZmLWZmZmYtZmZmZi1mZmZmZmZmZmZmZmYiLCJzZXNzaW9uIjoiMzllZDFlY2QtYWE2MS00NDAxLWJmMzUtY2EwYTE0YTM5YzhlIn0.NEKj737AqG7T7SAfQ2RovhWSjBsXCWCLPmkLtr_O5i8q_42BFX7pSGZbIslRy1PEQ3HKrnXib6D06D1kZugvCw"
}
```

The token we receive can be used in subsequent requests as a Bearer token.

### Authenticate as Super Admin via API

To access all protected endpoints of the Enterprise API, we will use the token obtained from the response of the
previous request. This token should be included in the header of each subsequent request.

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/...' \
  -H 'Authorization: Bearer {tokenReceived}'
  -d '{
    ...
  }'
```

**Note:**

To learn more about the Super Admin Account in general,
click [here](https://docs.walt.id/enterprise-stack/administration/access-and-permissions/super-admin/overview.md).

## 3. Organization

With the super-admin account active and the auth session token in our Authorization header, we can create an
Organization.

The organization is at the top of the enterprise stack resource hierarchy, as shown in the diagram below. Under the
Organization you can group customers as tenants, sub-tenants, or create a tenant of your own. This way services and
their data can be kept virtually separate, enabling you to easily manage different customers or services of your own
under one roof. Also, this structure allows you to build and sell B2B2C products (e.g., you can resell to business
clients who offer consumer products).

![image of enterprise resource diagram](https://docs.walt.id/img/enterprise-stack/concepts/enterprise-resource-tree.png)

**Note:**

While the Enterprise Stack allows for multiple Organizations, **on-prem Enterprise deployments should always have only
one
Organization.**

### Create a new Organization

**Option: CURL**

**Endpoint:
** `/v1/admin/organizations` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Administration%20(Global)%20%2F%20Organizations/post_v1_admin_organizations)

**Example Request**

```bash
curl -X 'POST' \
  'http://enterprise.localhost:3000/v1/admin/organizations' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "_id": "waltid",
  "profile": {
    "name": "Test GmbH"
  },
  "billing": {
    "billingCountry": "AT",
    "billingAddress": "test 111/115, 1090 Vienna",
    "vatNr": "test"
  }
}'
```

**Body**

```json
{
  "_id": "string",
  "profile": {
    "name": "string"
  },
  "billing": {
    "billingCountry": "",
    "billingAddress": "",
    "vatNr": "",
    "iban": "",
    "swift": ""
  }
}
```

**Body Parameters**

- `_id`
    - `type`: _String_ - Unique identifier for the organization, e.g. `waltid`

- `profile`
    - `name`: _String_ - Human readable name for the organization.

- `billing`: Billing information

---

**Response Codes**

- `201` - Organization created successfully.

When we create a new organization, an admin role is automatically generated in the background. This role is named using
the format `[orgID].admin`. For example, if our organization ID is `waltid`, the admin role will be
called `waltid.admin`.

In the next step, we will use this role to create an API Key that grants admin rights exclusively for a specific
organization. This is a common pratice to not always use the super-admin to do regular day-to-day operations.

If you want to learn more about how permissions and roles work, please
go [here](https://docs.walt.id/enterprise-stack/administration/access-and-permissions/overview.md).

Also, each organization is given a unique subdomain, which is utilized for carrying out operations specific to that
organization. Operations that are not tied to any particular organization mainly involve the global `admin` endpoints,
as well as endpoints that do not require the `target` path parameter.

The structure of the subdomain for each new organization is as follows: {orgID}.{baseUrl}. For example, in our case,
this would be represented as http://waltid.enterprise.localhost:3000.

**Note:**

Learn more about the Organization in general [here](https://docs.walt.id/enterprise-stack/administration/organizations/overview.md).

## 4. API Keys - Auth

In this section, we will create an API for the organization and grant it admin rights by assigning the `waltid.admin`
role to the API key, which was automatically created along with the `waltid` organization in the last step.

**Error:**

Every operation from now on will be conducted within the scope of an organization, specifically `waltid`. Therefore, we
need to update the base URL of our API to include `waltid`. The new URL will
be `http://waltid.enterprise.localhost:3000`, in contrast to the previous URL, which
was `http://enterprise.localhost:3000`.

## Create API-Key

<br/>

**Option: CURL**

Endpoint:`/v1/{target}/apikeys-api/api-keys/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20API%20Keys/post_v1__target__apikeys_api_api_keys_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.myApiKey/apikeys-api/api-keys/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "My API Key",
  "expiration": "30d"
}'
```

**Body**

```json
{
  "name": "My API Key",
  "expiration": "30d"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization in which to create the new API Key and the
  API-Key's
  ID (`{organizationID}.[YourID]`), e.g. `waltid.myApiKey`

**Body Parameters**

- `name`: _String_ - Human readable name for API-Key.
- `expiration`: (optional) _String_ - Expiration time of the API-Key.
    - Set expiration times using the kotlinx.datetime Duration Syntax. Valid units are
      days (d), hours (h), minutes (m), and seconds (s), with finer granularity using milliseconds (ms), microseconds (
      us),
      and nanoseconds (ns). Examples include `5h`, `1d 12h`, and `1h 0m 30.340s`.

    - Alternatively, you can use a simplified ISO-8601 duration format (PThHmMs.fS), such as P1DT2H3M4.058S. In this
      format:
        - The largest non-time designator is days (D). Years (Y), weeks (W), and months (M) are not parsed. Instead, use
          365d for years, 7d for weeks, and 30d for months.
        - A day is always assumed to be 24 hours (24-hour clock time scale).
        - There is currently no alternative week-based representation like ["P"][number]["W"].

---

**Response**

```json
{
  "_id": "waltid.myApiKey",
  "name": "My API Key",
  "token": "eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiJhYjNhZjc0Zi0wNmNhLTRkY2EtYWJlZi1iNjA3MTJjOTM5YzEiLCJzZXNzaW9uIjoiYXBpLWFiM2FmNzRmLTA2Y2EtNGRjYS1hYmVmLWI2MDcxMmM5MzljMSJ9.FHEmayjhrfZMnOnEecNnOa6ADDwBm1jL_tue64PhxCTk1DZJeIdz-KPvuwWdSlLgw538fqAIoW8ulv6-B91ZAw"
}
```

The returned token can be used as a Bearer token in API requests.

**Note:**

  If you want to check the expiration time of the API-Key you can use the `/v1/{target}/apikeys-api/api-keys/view`
  endpoint.

By default, the API key we just created doesn't have any permissions. Therefore, we will assign the API Key
the admin role `waltid.admin` in the next step.

### Assigning Admin Role to API-Key

**Option: CURL**

Endpoint:`/v1/{target}/roles-api/roles/apikey/assign`

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.admin/roles-api/roles/apikey/assign' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '
  {
  "apikey": "waltid.myApiKey"
  }'
```

**Body**

```json
{
  "apikey": "waltid.myApiKey"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the ID of the role to assign to an API-Key. e.g. `waltid.admin`

**Body Parameters**

- `apikey`: _resourceIdentifier_ - Specifies the ID of the API-Key to assign the role to.

---

**Response Codes**

- `200` - Role assigned successfully.

## 3. Tenant

In this section, we will move further down the Enterprise Stack hirachy (shown below) and create our first tenant to
then be able to launch different types of services like Issuer, Verifier and others.

You can also create sub-tenants inside of tenants and sub-tenants. At this point, there is no limit to the level of
nested sub-tenants. Services and their data inside tenants and sub-tenants are kept separate.

![image of enterprise resource diagram](https://docs.walt.id/img/enterprise-stack/concepts/enterprise-resource-tree.png)

### Create a New Tenant

**Option: CURL**

Endpoint:`/v1/{target}/resource-api/tenants/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_tenants_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1/resource-api/tenants/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "My Tenant"
  }'
```

**Body**

```json
{
  "name": "My Tenant"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization in which to create the new tenant and the
  tenant's
  ID (`{organizationID}.[YourID]`), e.g. `waltid.tenant1`

**Body Parameters**

- `name`: _String_ - Human readable name for the tenant.

---

**Response Codes**

- `201` - Tenant created successfully.

## 4. Services

With the new tenant created, we will now establish various types of services within this tenant, progressing further
down the hierarchy illustrated in the diagram below.

![image of enterprise resource diagram](https://docs.walt.id/img/enterprise-stack/concepts/enterprise-resource-tree.png)

### Services To Be Created

- [KMS Service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) - Create and manage keys based on different
  algorithms.
- [DID Service](https://docs.walt.id/enterprise-stack/services/did-service/overview.md) - Create DID based on various methods (did:key, did:
  web, ...).
- [DID Store Service]() - Store and query DIDs & DID Documents.
- [Issuer Service](https://docs.walt.id/enterprise-stack/services/issuer-service/overview.md) - Sign & Issue various credentials (W3C, SD-JWT VC) via
  OID4VC.
- [Credential Status Service](https://docs.walt.id/enterprise-stack/services/credential-status-service/overview.md) - Create, update, and manage
  status credentials.
- [Verifier Service](https://docs.walt.id/enterprise-stack/services/verifier-service/overview.md) - Request & verify various types of digital
  credentials via OID4VP.
- [Wallet Service](https://docs.walt.id/enterprise-stack/services/wallet-service/overview.md) - Run identity wallets for individuals or organizations.
- [Credential Store Service]() - Store and query different types of credentials (e.g. W3C, SD-JWT VC, mDL).

### Create A KMS Service

First, we will set up a Key Management Service (KMS) to create and store the keys necessary for signing the verifiable
credential and the status credential. In this tutorial, we will use the Enterprise Stack database to store these keys.
However, for production scenarios, it is recommended to store the keys in an external KMS that the Enterprise Stack can
access through integrations. For more information about the supported KMS providers, please
go [here](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md).

### Setup Key Service

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.kms1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "kms"
}'
```

**Body**

```json
{
  "type": "kms"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new KMS service
  and the service's
  ID (`{organizationID}.{tenantID}.[NewKmsServiceID]`), e.g. `waltid.tenant1.kms1`

**Body Parameters**

- `type`: _serviceType_ - Specifies the type of service to create. In our case `kms`

---

**Response Codes**

- `201` - Service created successfully.

### Create Key

**Option: CURL**

Endpoint: `/v1/{target}/kms-service-api/keys/generate` | [API Reference](http://waltid.enterprise.localhost:8000/swagger/index.html#/Service%20%2F%20Key%20Management/post_v1__target__kms_service_api_keys_generate)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.kms1.key1/kms-service-api/keys/generate' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "backend": "jwk",
  "keyType": "Ed25519"
}'
```

**Body**

```json
{
  "backend": "jwk",
  "keyType": "Ed25519"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + kmsService in which to create the
  new key and the key's ID (`{organizationID}.{tenantID}.{kmsServiceID}.[newKeyID]`), e.g. `waltid.tenant1.kms1.key1`

**Body Parameters**

- `backend`: _String_ - Specifies the storage type of key. `jwk` means the local storage option is used and the key
  is stored in the Enterprise Stack backend.
- `keyType`: _String_ - the algorithm used to generate the key. For local, it can be ed25519, secp256k1, secp256r1, or
  RSA.

---

**Response**

`201` - Key created successfully.

```json
{
  "_id": "waltid.tenant1.kms1.key1",
  "key": {
    "type": "jwk",
    "jwk": {
      "kty": "OKP",
      "d": "ywmoRVTD9fexMtGW0lKE3o9_0ulfzGXr9xHGL0lPhhA",
      "crv": "Ed25519",
      "kid": "IQO7DILxtagpTLXkuHkRkJURb2GqcUIwXYZAcGwW1AU",
      "x": "JOsiIE7ME9UZ8y2H-P5RSuYAUiIfs1ywtdBjMGN7I5s"
    }
  },
  "parent": "waltid.tenant1.kms1"
}
```

Now, we created one key that can be used for both the issuer and the credential status service in this tutorial. In
practice, however, different keys should be created for different purposes. You can also use the example above to create
another key if desired.

In the next step, we will create a DID service and create a did:key for our key.

### Create DID Service

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.did-service-1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "did"
}'
```

**Body**

```json
{
  "type": "did"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new DID service
  and the service's
  ID (`{organizationID}.{tenantID}.[NewDIDServiceID]`), e.g. `waltid.tenant1.did1`

**Body Parameters**

- `type`: _serviceType_ - Specifies the type of service to create. In our case `did`

---

**Response Codes**

- `201` - Service created successfully.

### Create DID Store (for Issuer DID)

We will create a DID Store for persisting the issuer's DID and DID Document and link it to the DID Service so that any newly created DID is stored automatically.

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.did-store-issuer-1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "did-store"
}'
```

**Body**

```json
{
  "type": "did-store"
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named `test`, your default Base URL will be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new DID store and the service's ID (`{organizationID}.{tenantID}.[NewDidStoreServiceID]`), e.g. `waltid.tenant1.did-store-issuer-1`

---

**Response Codes**

- `201` - Service created successfully.

### Link DID Store to DID Service

Now link the DID Store to the DID Service so that newly created DIDs are stored automatically.

**Option: CURL**

Endpoint: `/v1/{target}/did-service-api/dids/dependencies/add` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/DID%20Service/post_v1__target__did_service_api_dids_dependencies_add)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.did-service-1/did-service-api/dids/dependencies/add' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d 'waltid.tenant1.did-store-issuer-1'
```

**Body**

```
waltid.tenant1.did-store-issuer-1
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named `test`, your default Base URL will be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + DID service to which to add an existing DID Store (`{organizationID}.{tenantID}.{didServiceID}`), e.g. `waltid.tenant1.did-service-1`

---

**Response Codes**

- `201` - Unit attached.

Before creating a DID from a key, run the same dependency call again with the KMS ID:

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.did-service-1/did-service-api/dids/dependencies/add' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d 'waltid.tenant1.kms1'
```

### Create did:key

**Option: CURL**

Endpoint: `/v1/{target}/did-service-api/dids/create/key` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/DID%20Service/post_v1__target__did_service_api_dids_create_key)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.did-service-1/did-service-api/dids/create/key' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "keyId": "waltid.tenant1.kms1.key1",
  "useJwkJcsPub": false
}'
```

**Body**

```json
{
  "keyId": "waltid.tenant1.kms1.key1",
  "useJwkJcsPub": false
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + DID service in which to execute the
  DID creation (`{organizationID}.{tenantID}.{didServiceID}`), e.g. `waltid.tenant1.did1`

**Body Parameters**

- `keyId`: _resourceIdentifier_ - Specifies the key for which to generate a DID + DID Document. Please make sure that
  the key is stored in a KMS service under the same tenant as the DID service.
- `useJwkJcsPub`: _boolean_ - If set to `true` it generates an EBSI compliant DID:key + DID Document. This is only important if you are operating within the EBSI ecosystem.

**Note:**

  Because we linked a DID Store to the DID Service, the new DID and DID Document will be stored automatically in `waltid.tenant1.did-store-issuer-1`.

---

**Response**

- `201` - DID created successfully.

```json
{
  "did": "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt",
  "document": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/suites/jws-2020/v1"
    ],
    "id": "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt",
    "verificationMethod": [
      {
        "id": "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt",
        "type": "JsonWebKey2020",
        "controller": "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt",
        "publicKeyJwk": {
          "kty": "EC",
          "crv": "P-256",
          "kid": "zY9AzWFTMKveeXIdHWSsvX16Cso1JXMEVKGFUuw_LkQ",
          "x": "PMzrrJU6Gh5JZK_6aIpiWWHcGoWymGFkYptM10a1sec",
          "y": "6-hp5Y7Hpb9nFfovyeycXSPubEJ7LWdaGNoCcKZCIyA"
        }
      }
    ],
    "assertionMethod": [
      "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt"
    ],
    "authentication": [
      "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt"
    ],
    "capabilityInvocation": [
      "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt"
    ],
    "capabilityDelegation": [
      "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt"
    ],
    "keyAgreement": [
      "did:key:z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt#z2dmzD81cgPx8Vki7JbuuMmFYrWPgYoytykUZ3eyqht1j9KbptHxPSZ7khwjrFU8X6aCeeqW3jTNdoAMWZCHMFmVeZYDYbeCZgy5mYuY2a3X3GrAKGkSW31bxMSV5n2okQJd9UckKn7mEdqnDSv6xFfejCekE2oSEE1hUX62Ww2pUn39zt"
    ]
  }
}
```

**Note:**

Please make sure to save the generated DID (Decentralized Identifier) along with the key ID for future reference. This
information will be necessary, when issuing credentials through the Issuer Service. We are working
on a solution to have this more easily referenced from the issuer service.

### Create Wallet Service

We’ll create a Wallet Service for the holder, along with its own KMS and DID Service, plus a DID Store and Credential Store. The DID Service will generate a did:key for this wallet. We’ll use a helper endpoint to set up the wallet and all its dependencies in one step, so there’s no need to manually link the KMS, DID Service, or the DID and Credential Stores to the wallet service. The dependency services will play the following roles: 

- [KMS Service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) - Will store and manage the wallet's keys.
- [DID Service](https://docs.walt.id/enterprise-stack/services/did-service/overview.md) - Will help with the creation of DIDs based on keys managed via the KMS service.
- [DID Store](https://docs.walt.id/enterprise-stack/services/did-store-service/overview.md) - Will store the DIDs & DID Documents created by the DID service.
- [Credential Store](https://docs.walt.id/enterprise-stack/services/credential-store-service/overview.md) - Will store the credentials received via the wallet service.

**Note:**

To dive deeper into the Wallet Service and its API, see the [Wallet Service docs](https://docs.walt.id/enterprise-stack/services/wallet-service/setup.md).

</br>

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/init-wallet` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Wallet%20Service/post_v1__target__wallet_service_api_init_wallet)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.wallet1/wallet-service-api/init-wallet' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "createKms": true,
  "kmsName": "wallet-kms-1",
  "createKeyInKms": { "backend": "jwk", "keyType": "Ed25519" },
  "createDidService": true,
  "didServiceName": "wallet-did-service-1",
  "createDidWithDidService": "key",
  "createDidStore": true,
  "didStoreName": "wallet-did-store-1",
  "createCredentialStore": true,
  "credentialStoreName": "wallet-credential-store-1"
}'
```

**Body**

```json
{
  "createKms": true,
  "kmsName": "wallet-kms-1",
  "createKeyInKms": { "backend": "jwk", "keyType": "Ed25519" },
  "createDidService": true,
  "didServiceName": "wallet-did-service-1",
  "createDidWithDidService": "key",
  "createDidStore": true,
  "didStoreName": "wallet-did-store-1",
  "createCredentialStore": true,
  "credentialStoreName": "wallet-credential-store-1"
}
```

**Notes**

- This creates a new dedicated KMS (`waltid.tenant1.wallet-kms-1`) and DID Service (`waltid.tenant1.wallet-did-service-1`) for the wallet and generates a key for it.
- Set `createDidWithDidService` to "key" to provision a did:key for the wallet.
- This also creates and links a DID Store (`waltid.tenant1.wallet-did-store-1`) and a Credential Store (`waltid.tenant1.wallet-credential-store-1`). The generated DID 
is stored in the created DID Store.

#### (Optional) Find the Wallet DID reference in the DID Store

Use the DID Store to list stored DID IDs and compose the DID reference as `waltid.tenant1.did-store-1.{didId}`.

**Option: CURL**

Endpoint: `/v1/{target}/did-store-service-api/dids/list-did-ids`

```bash
curl -X 'GET' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.wallet-did-store-1/did-store-service-api/dids/list-did-ids' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}'
```

This returns an array like `["wallet_did"]`. Combine it as `waltid.tenant1.wallet-did-store-1.wallet_did` when a DID reference is needed below.

### Create Credential Status Service (optional)

In this section, we will set up a credential status service and create a configuration for it. To proceed
with this section, you need to
have an account with one of the following cloud providers: AWS, Azure, or Google Cloud. This is necessary because the
credential status must be hosted publicly, and currently, we only support these three providers for hosting.

**Note:**

If you prefer not to create a cloud account (AWS, Azure, or Google Cloud) which is required for this step or wish to
skip the credential status setup altogether, you can move
directly to the example for creating an issuer.

#### Credential Status Service Setup

The Credential Status service enables users to create, update, and manage status credentials. Status credentials
can have different purposes depending on the use-case. The most common purpose is revocation.

Currently, status credentials can be stored and made available via three types of external services:

1. [AWS S3 Bucket](https://aws.amazon.com/s3/)
2. [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs)
3. [Google Cloud Storage](https://cloud.google.com/storage)

**Option: AWS**

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.credential-status-service-1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "aws",
      "bucketName": "bucket-name",
      "region": "region",
      "accessKeyId": "s3-access-key-id",
      "secretKey": "s3-secret-key"
    },
    "bucketUrl": "https://bucket-name.s3.amazonaws.com"
  }
}'
```

**Body**

```json
{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "aws",
      "bucketName": "bucket-name",
      "region": "region",
      "accessKeyId": "s3-access-key-id",
      "secretKey": "s3-secret-key"
    },
    "bucketUrl": "https://bucket-name.s3.amazonaws.com"
  }
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new credential
  status service and the service's
  ID (`{organizationID}.{tenantID}.[NewCredentialStatusServiceID]`), e.g. `waltid.tenant1.credential-status-service-id`

**Body Parameters**

- `type`: _credential-status_ - Specifies the type of service to create. In this case, it is `credential-status`.
- `config`: _object_ - Storage configurations for status credential service.
- `registry`: _object_ - Defines registry & access credentials for chosen registry.
    - `type`: _aws_ - Indicates the type of registry, which is `aws` in this context.
    - `bucketName`: _string_ - The name of the AWS S3 bucket.
    - `region`: _string_ - The AWS region where the bucket is located.
    - `accessKeyId`: _string_ - The access key ID for accessing the AWS S3 bucket.
    - `secretKey`: _string_ - The secret access key for accessing the AWS S3 bucket.
- `bucketUrl`: _string_ - The URL of the chosen registry bucket, e.g. "https://bucket-name.s3.amazonaws.com" for AWS.

---

**Response Codes**

- `201` - Service created successfully.
- `401` - Invalid authentication.

**Option: Azure**

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.credential-status-service-1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "azure",
      "bucketName": "bucket-name",
      "connectionString": "connection-string"
    },
    "bucketUrl": "https://storage-name.blob.core.windows.net/bucket-name"
  }
}'
```

**Body**

```json
{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "azure",
      "bucketName": "bucket-name",
      "connectionString": "connection-string"
    },
    "bucketUrl": "https://storage-name.blob.core.windows.net/bucket-name"
  }
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new credential
  status service and the service's
  ID (`{organizationID}.{tenantID}.[NewCredentialStatusServiceID]`), e.g. `waltid.tenant1.credential-status-service-id`

**Body Parameters**

- `type`: _credential-status_ - Specifies the type of service to create. In this case, it is `credential-status`.
- `config`: _object_ - Storage configurations for status credential service.
- `registry`: _object_ - Holds the details for the Azure registry configuration.
    - `type`: _azure_ - Indicates the type of registry, which is `azure` in this context.
    - `bucketName`: _string_ - The name of the Azure storage bucket.
    - `connectionString`: _string_ - The connection string used to access the Azure storage account.
- `bucketUrl`: _string_ - The URL of the Azure storage bucket, specified
  as `https://storage-name.blob.core.windows.net/bucket-name`.

---

**Response Codes**

- `201` - Service created successfully.
- `401` - Invalid authentication.

**Option: Google**

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.credential-status-service-1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "gcp",
      "bucketName": "bucket-name",
      "projectId": "project-id",
      "serviceAccountKeyJson": {
        "type": "service_account",
        "project_id": "YOUR_PROJECT_ID",
        "private_key_id": "YOUR_PRIVATE_KEY_ID",
        "private_key": "-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY
-----END PRIVATE KEY-----
",
        "client_email": "YOUR_SERVICE_ACCOUNT_EMAIL",
        "client_id": "YOUR_CLIENT_ID",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/YOUR_SERVICE_ACCOUNT_EMAIL",
        "universe_domain": "googleapis.com"
      }
    },
    "bucketUrl": "https://storage.cloud.google.com/bucket-name"
  }
}'
```

**Body**

```json
{
  "type": "credential-status",
  "config": {
    "registry": {
      "type": "gcp",
      "bucketName": "bucket-name",
      "projectId": "project-id",
      "serviceAccountKeyJson": {
        "type": "service_account",
        "project_id": "YOUR_PROJECT_ID",
        "private_key_id": "YOUR_PRIVATE_KEY_ID",
        "private_key": "-----BEGIN PRIVATE KEY-----
YOUR_PRIVATE_KEY
-----END PRIVATE KEY-----
",
        "client_email": "YOUR_SERVICE_ACCOUNT_EMAIL",
        "client_id": "YOUR_CLIENT_ID",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/YOUR_SERVICE_ACCOUNT_EMAIL",
        "universe_domain": "googleapis.com"
      }
    },
    "bucketUrl": "https://storage.cloud.google.com/bucket-name"
  }
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new credential
  status service and the service's
  ID (`{organizationID}.{tenantID}.[NewCredentialStatusServiceID]`), e.g. `waltid.tenant1.credential-status-service-id`

**Body Parameters**

- `type`: _credential-status_ - Specifies the type of service to create. In this case, it is `credential-status`.
- `config`: _object_ - Storage configurations for status credential service.
- `registry`: _object_ - Holds the details for the GCP registry configuration.
    - `type`: _gcp_ - Indicates the type of registry, which is `gcp` in this context.
    - `bucketName`: _string_ - The name of the GCP storage bucket.
    - `projectId`: _string_ - The ID of the GCP project.
    - `serviceAccountKeyJson`: _object_ - Contains the service account key details for accessing GCP.
        - `type`: _service_account_ - Specifies the type of account
        - `project_id`: _string_ - The project ID for the service account.
        - `private_key_id`: _string_ - The ID of the private key.
        - `private_key`: _string_ - The private key for the service account, specified in a PEM format.
        - `client_email`: _string_ - The email associated with the service account.
        - `client_id`: _string_ - The client ID for the service account.
        - `auth_uri`: _string_ - The URI for authentication.
        - `token_uri`: _string_ - The URI for token issuance.
        - `auth_provider_x509_cert_url`: _string_ - The URL for the authentication provider's certificate.
        - `client_x509_cert_url`: _string_ - The URL for the client certificate.
        - `universe_domain`: _string_ - The domain for the universe of the API.
- `bucketUrl`: _string_ - The URL of the GCP storage bucket, specified
  as `https://storage.cloud.google.com/bucket-name`.

---

**Response Codes**

- `201` - Service created successfully.
- `401` - Invalid authentication.

#### Create A Status List Credential Configuration

Before we can create a status for a specific credential, we first need to establish a status credential configuration.
This configuration serves as the blueprint for creating a status credential. The status credential itself is responsible
for holding the status entries of one or more credentials. Each time we issue a new status for a credential that we want
to provide to a holder, the status credential get updated, re-issued, and made publicly available through the
configured registry.

When defining the configuration, we specify which key will sign the status credential, the Decentralized Identifier (
DID) of the issuer, and the configuration details of the status itself. This configuration includes the `purpose` of the
status (for example, revocation), the `statusSize`, and additional parameters.

In the example below, we will create a configuration specifically for a revocation status credential.

**Note:**

One StatusListCredential can host 32.000 status list entries.

<br>

**Option: CURL**

Endpoint: `/v1/{target}/credential-status-service-api/status-credential/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Credential%20Status%20Service/post_v1__target__credential_status_service_api_status_credential_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.credential-status-service-1.config1/credential-status-service-api/status-credential/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "kid": "waltid.tenant1.kms1.key1",
  "did": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5Iiwia2lkIjoiMW1rQnBEYWZqVk9ONm9XVmlIZGREZXNEYXpKaXk1R0NTYko3VDU4QkJ3cyIsIngiOiJzZ1BiZWRPQjl1WEMtVG54LUVhV1IxRmg1Y25JLUxRLU43NUV1UE8wV2VFIn0",
  "config": {
    "purpose": "revocation",
    "type": "StatusList2021",
    "statusSize": 1,
    "statuses": [
      {
        "status": "0x0",
        "message": "unset"
      },
      {
        "status": "0x1",
        "message": "set"
      }
    ]
  }
}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + credential status service in which
  to execute the status credential creation (`{organizationID}.{tenantID}.{credentialStatusServiceID}`),
  e.g. `waltid.tenant1.status-service1`

**Body**

```json
{
  "kid": "waltid.tenant1.kms1.key1",
  "did": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5Iiwia2lkIjoiMW1rQnBEYWZqVk9ONm9XVmlIZGREZXNEYXpKaXk1R0NTYko3VDU4QkJ3cyIsIngiOiJzZ1BiZWRPQjl1WEMtVG54LUVhV1IxRmg1Y25JLUxRLU43NUV1UE8wV2VFIn0",
  "config": {
    "purpose": "revocation",
    "type": "StatusList2021",
    "statusSize": 1,
    "statuses": [
      {
        "status": "0x0",
        "message": "unset"
      },
      {
        "status": "0x1",
        "message": "set"
      }
    ]
  }
}
```

**Body Parameters**

- `kid`: _resourceIdentifier_ - Specifies a key used for singing the status credential. The key must come from a KMS
  service
  that lives under the same tenant as the credential status service.
- `did`: _String_ - Specifies that DID related to the `kid`.
- `config`: _Object_ - Status credential configuration.
    - `purpose`: _String_ - Describes the type of status e.g. `revocation`, `suspension` or any other custom type.
    - `type`: _String_ - Describes the status credential standard. It should be `StatusList2021`.
    - `statusSize`: _String_ - Describes the size of each status entry in bits. The default value is 1, meaning
      each status is represented by a single bit. If a value greater than 1 is used, it allows for more complex status
      messages, and the number of possible status messages must equal the number of possible values (e.g.,
      2^statusSize).
    - `statuses`: _Array_ - An array of objects, each representing a possible status value and its associated message.
      Each object contains:
        - `status`: A string representing the hexadecimal value of the status, prefixed with 0x.
        - `message`: A descriptive string used by developers for debugging purposes, indicating what the status value
          represents. It is not intended for end-user display.

---

**Response**

- `201` - Credential Status config created successfully.

### Create Issuer Service

In this section, we will create an issuer service to issue credentials via OID4VCI. We will configure the issuer
service to support the issuance of W3C `UniversityDegree` type credentials using JWT signatures. You can learn more
about how to configure other and custom
credentials [here](https://docs.walt.id/enterprise-stack/services/issuer-service/configurations/overview.md).

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.issuer1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "issuer",
  "baseUrl": "http://waltid.enterprise.localhost:3000",
  "kms": "waltid.tenant1.kms1",
  "tokenKeyId": "waltid.tenant1.kms1.key1",
  "supportedCredentialTypes": {
    "UniversityDegree_jwt_vc_json": {
      "format": "jwt_vc_json",
      "cryptographic_binding_methods_supported": [
        "did"
      ],
      "credential_signing_alg_values_supported": [
        "ES256"
      ],
      "credential_definition": {
        "type": [
          "VerifiableCredential",
          "UniversityDegree"
        ]
      }
    }
  }
}'
```

**Body**

```json
{
  "type": "issuer",
  "baseUrl": "http://waltid.enterprise.localhost:3000",
  "kms": "waltid.tenant1.kms1",
  "tokenKeyId": "waltid.tenant1.kms1.key1",
  "supportedCredentialTypes": {
    "UniversityDegree_jwt_vc_json": {
      "format": "jwt_vc_json",
      "cryptographic_binding_methods_supported": [
        "did"
      ],
      "credential_signing_alg_values_supported": [
        "ES256"
      ],
      "credential_definition": {
        "type": [
          "VerifiableCredential",
          "UniversityDegree"
        ]
      }
    }
  }
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new Issuer
  service
  and the service's
  ID (`{organizationID}.{tenantID}.[NewIssuerServiceID]`), e.g. `waltid.tenant1.issuer1`

**Body Parameters**

- `type`: _serviceType_ - Specifies the type of service to create. In our case `issuer`
- `baseUrl`: _String_ - This URL will be included in the generated OIDC4VC offer, allowing the wallet to know how to
  reach the issuer. It should reflect your organization's base URL. The general format for this URL
  is `https://{orgID}.yourEnterpriseStackUrl.com`.
  For example, if your organization is named **myorg** and the Enterprise Stack is hosted at the domain
  **enterprise-stack.com**, your base URL would be:
  https://myorg.enterprise-stack.com.
- `kms`: - _resourceIdentifier_ - A [KMS service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) you want to connect with the to be
  created Issuer service. It should be setup under
  the same tenant.
- `tokenKeyId`: - _resourceIdentifier_ - A key in the connected [KMS service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) used
  to
  sign the access token, which is used to get the credential from the credential endpoint
- `supportedCredentialTypes`: _Object_ - A map of credentials the issuer supports. This list will be used
  to generate
  the [issuer metadata](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata).
  This list of supported credentials can be updated also after the initial setup.
  <br/>
  <br/>
  <details><summary>Expand For W3C JWT & SD-JWT Credentials</summary>
  <br/>
  To specify the support of a W3C credential the object will look as follows:

  <br/>
  <br/>

  ```json
  "OpenBadgeCredential_jwt_vc_json": {
      "format": "jwt_vc_json",
      "cryptographic_binding_methods_supported": [
        "did"
      ],
      "credential_signing_alg_values_supported": [
        "ES256"
      ],
      "credential_definition": {
        "type": [
          "VerifiableCredential",
          "OpenBadgeCredential"
        ]
      }
    }
  ```

  The key will have the following structure: `[CustomCredentialType]_jwt_vc_json`,
  e.g. `OpenBadgeCredential_jwt_vc_json`

  Inside the object:

    - `format` - will be `jwt_vc_json` for W3C JWT & SD-JWT credentials
    - `cryptographic_binding_methods_supported` - will be `did`
    - `credential_signing_alg_values_supported` - will be `ES256`
    - `credential_definition`
        - `type` - specifies a list of credential types. E.g. `[VerifiableCredential, MyCustomCredential]`
            1. First Entry: Your list must always start with `VerifiableCredential`.
            2. Subsequent Entries: After `VerifiableCredential`, you have two options:

            - You can add your custom type, such as `CustomCredential`.
            - If your credential is based on another credential (for example, `VerifiableAttestation`), first list all
              the
              credentials it builds upon, and then add your custom type at the end.

    </details>

    <br/>
    <br/>
    <details><summary>Expand For SD-JWT VC Credentials</summary>
    <br/>
  To specify the support of a SD-JWT VC credential the object will look as follows:

  <br/>
  <br/>

  ```json
  "identity_credential_vc+sd-jwt": {
      "format": "vc+sd-jwt",
      "vct": "{vctBaseURL}/identity_credential",
      "cryptographic_binding_methods_supported": [
        "jwk"
      ],
      "credential_signing_alg_values_supported": [
        "ES256"
      ],
      "sdJwtVcTypeMetadata": {
        "name": "Identity Credential",
        "description": "The Identity Verifiable Credential",
        "vct": "{vctBaseURL}/identity_credential"
      }
    }
  ```

  The key will have the following structure: `[custom_credential_type]_vc+sd-jwt`,
  e.g. `identity_credential_vc+sd-jwt`

  Inside the object:

    - `format` - will be `vc+sd-jwt` for SD-JWT VC credentials.
    - `vct` - will follow the structure `{vctBaseURL}/[custom_credential_type]`,
      e.g. `{vctBaseURL}/custom_credential_type`.
      The vctBaseURL will be replaced during issuance by the issuer API.
    - `cryptographic_binding_methods_supported` - will be `jwk`
    - `credential_signing_alg_values_supported` - will be `ES256`
    - `sdJwtVcTypeMetadata`
        - `name` - Name of the credential
        - `description` - Description of the credential
        - `vct` - Holding the same value as the `vct` above.

      </details>

- `displayConfigurations` (optional) - an optional list of objects, where each object contains specific display
  information for different languages. Including the local option is not mandatory; you can simply provide one object if
  localization is not required. To learn more about the display config in general
  go [here](./3.configurations/2.openid-metadata/0.display.md), for object property details
  expand below.

  <br/>
  <br/>
  <details><summary>Expand to learn more about the display config object properties</summary>

  **Display Config Object**

    ```json
    {
      "name": "walt.id Enterprise Issuer Service",
      "locale": "en-US",
      "logo": {
        "uri": "http://cdn.walt.id/issuer/logo.png",
        "alt_text": "Logo of walt.id Enterprise Issuer Service"
      }
    }
    ```

    - `name` (optional) _String_: String value of a display name for the Credential Issuer.
        - `locale` (optional) _String_: String value that identifies the language of this object represented as a
          language tag
          taken from values defined in
          BCP47 [RFC5646](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#RFC5646). There MUST
          be only
          one object for each language identifier. Example values are: `en-US`, `de-DE`, or `fr-FR`.
        - `logo` (optional) _Object_: Object with information about the logo of the Credential Issuer.
            - `uri` _String_: String value that contains a URI where the Wallet can obtain the logo of the Credential
              Issuer.
            - `alt_text` (optional) _String_: String value of the alternative text for the logo image.
    </details>

---

**Response Codes**

- `201` - Service created successfully.

### Create Verifier Service

In this section, we will create a verifier service to verify credentials via OID4VCP.

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.verifier1/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "verifier",
  "baseUrl": "http://waltid.enterprise.localhost:3000"
}'
```

**Body**

```json
{
  "type": "verifier",
  "baseUrl": "http://waltid.enterprise.localhost:3000",
  "metadataConfig": {
    "name": "walt.id Enterprise Verifier",
    "logoUri": "https://cdn.walt.id/verifier/logo.png"
  }
}
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant in which to create the new Verifier
  service
  and the service's
  ID (`{organizationID}.{tenantID}.[NewVerifierServiceID]`), e.g. `waltid.tenant1.verifier1`

**Body Parameters**

- `type`: _serviceType_ - Specifies the type of service to create. In our case `verifier`
- `baseUrl`: _String_ - This URL will be included in the generated OIDC4VC offer, allowing the wallet to know how to
  reach the verifier. It should reflect your organization's base URL. The general format for this URL
  is `https://{orgID}.yourEnterpriseStackUrl.com`.
  For example, if your organization is named **myorg** and the Enterprise Stack is hosted at the domain
  **enterprise-stack.com**, your base URL would be:
  https://myorg.enterprise-stack.com.
- `metadataConfig`: _Object_ - Verifier metadata config. Can be used to edit e.g. externally exposed human-readable
  verifier
  name and logo. Learn more in general [here](4.configurations/1.openid-metadata.md) or expand below to see object
  property options.

  <br/>
  <br/>

   <details><summary>Expand to learn more about metadata config object properties</summary>

  **Metadata Config Object**

   ```json
    "metadataConfig": {
      "name": "walt.id Enterprise Verifier",
      "logoUri": "https://cdn.walt.id/verifier/logo.png"
    }
   ```

    - `name` (optional) _String_: Human-readable string name of the verifier.
    - `logoUri` (optional) _String_: URL string that references a logo for the verifier.
   </details>

---

**Response Codes**

- `201` - Service created successfully.

### Issue Credential

Now, we'll issue a verifiable credential using the key and DID created earlier. You can choose to
either issue the W3C credential without or with a status (revocation). To issue the credential with a status, 
you must have completed the [optional setup of a Credential Status Service](#create-credential-status-service-optional).

To facilitate the issuance of the credential from us (the issuer) to the holder, we will utilise the OID4VCI protocol.
In
particular, we will be generating an OID4VC offer URL that can be accepted by any OID compliant wallet to receive
credential(s).

**Note:**

The credential offer URL specifies the credentials to be issued. This includes details such as
the URL of the issuer, the authorisation and token endpoints, and information about the credential's format, type, and
scope.

<br />

After calling the endpoint, an OID4VCI offer URL is generated. Initially, this URL does not include the actual signed
credentials; instead, it contains a list of credentials that we are offering for the wallet to claim. Once the wallet
processes this offer and chooses to accept the credential, it will request those credentials through a series of
exchanges between the issuer and the wallet. Only at this point, when the wallet requests the credential, will the
issuer sign it. Additionally, just before the signing occurs, the
provided [data functions](https://docs.walt.id/enterprise-stack/services/issuer-service/data-functions.md) are executed.

**Option: Without Revocation Status**

[API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Issuer%20Service/post_v1__target__issuer_service_api_credentials_issue)

**Option: CURL**

Endpoint: `/v1/{target}/issuer-service-api/credentials/issue` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Issuer%20Service/post_v1__target__issuer_service_api_credentials_issue)

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.issuer1/issuer-service-api/credentials/issue' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'statusCallbackUri: https://example.com/$id' \
  -H 'Content-Type: application/json' \
  -d '{
  "issuerKeyId": "waltid.tenant1.kms1.key1", 
  "issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
  "authenticationMethod": "PRE_AUTHORIZED",
  "credentialConfigurationId": "UniversityDegree_jwt_vc_json",
  "credentialData": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
    ],
    "id": "http://example.gov/credentials/3732",
    "type": [
      "VerifiableCredential",
      "UniversityDegree"
    ],
    "issuer": {
      "id": "did:web:vc.transmute.world"
    },
    "issuanceDate": "2020-03-10T04:24:12.164Z",
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "degree": {
        "type": "BachelorDegree",
        "name": "Bachelor of Science and Arts"
      }
    }
  },
  "mapping": {
    "id": "<uuid>",
    "issuer": {
      "id": "<issuerDid>"
    },
    "credentialSubject": {
      "id": "<subjectDid>"
    },
    "issuanceDate": "<timestamp>",
    "expirationDate": "<timestamp-in:365d>"
  }
}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + issuer service with which to execute
  the credential issuance (`{organizationID}.{tenantID}.{issuerServiceID}`), e.g. `waltid.tenant1.issuer1`

**Header Parameters**

- `statusCallbackUri`: _URL_ - Receive updates on the created issuance process, e.g. when a credential was successfully
  claimed. The parameter expects a URL which can accept a JSON POST request. The URL can also hold a `$id`, which will
  be
  replaced by the issuance session id. For example: `https://myurl.com/$id`, `https://myurl.com`
  or `https://myurl.com/test/$id`
  <br/>
  <br />
  <details><summary>Expand To Learn More</summary>

  <br /> 

  **Body**

  The data send to the provided URL will contain a JSON body:
    - `id` : _String_ - the issuance session id
    - `type`: _String_ - the event type
    - `data`: _JsonObject_ - the data for the event

  **Event Types**

  Possible events (event types) and their data are:
    - `resolved_credential_offer` with the credential offer as JSON (in our Web Wallet: called when the issuance offer
      is
      entered into the wallet, but not processing / accepted yet)
    - `requested_token` with the issuance request for the token as json object (called for the token required to receive
      the
      credentials)

  Credential issuance (called for every credential that's issued (= requested from wallet))
    - `jwt_issue` with `jwt` being the issued jwt
    - `sdjwt_issue` with `sdjwt` being the issued sdjwt
    - `batch_jwt_issue` with `jwt` being the issued jwt
    - `batch_sdjwt_issue` with `sdjwt` being the issued sdjwt
    - `generated_mdoc` with `mdoc` being the CBOR (HEX) of the signed mdoc

  To allow for secure business logic flows, if a callback URL is set, and it cannot be reached, the issuance will not
  commence further (after that point). If no callback URL is set, the issuance logic does not change in any way.

  </details>

**Body**

```json
{
  "issuerKeyId": "waltid.tenant1.kms1.key1",
  "issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
  "authenticationMethod": "PRE_AUTHORIZED",
  "credentialConfigurationId": "UniversityDegree_jwt_vc_json",
  "credentialData": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
    ],
    "id": "http://example.gov/credentials/3732",
    "type": [
      "VerifiableCredential",
      "UniversityDegree"
    ],
    "issuer": {
      "id": "did:web:vc.transmute.world"
    },
    "issuanceDate": "2020-03-10T04:24:12.164Z",
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "degree": {
        "type": "BachelorDegree",
        "name": "Bachelor of Science and Arts"
      }
    }
  },
  "mapping": {
    "id": "<uuid>",
    "issuer": {
      "id": "<issuerDid>"
    },
    "credentialSubject": {
      "id": "<subjectDid>"
    },
    "issuanceDate": "<timestamp>",
    "expirationDate": "<timestamp-in:365d>"
  }
}
```

**Body Parameters**

- `issuerKeyId`: _resourceIdentifier_ - The keyID of a key stored in
  a [KMS service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) under the same tenant.
  E.g. `waltid.tenant1.kms1.key1`
- `issuerDid`: _String_ - The DID related to the provided key.
- `credentialConfigurationId`: _String_ - Reference to a specific credential configuration the issuer supports.
  Configured
  during [issuer service setup](https://docs.walt.id/enterprise-stack/setup.md).
- `credentialData`: _JSON_ - A credential data structure to sign (W3C compliant). A list of predefined valid structures
  can be
  found [here](https://credentials.walt.id/).
- `mapping` (optional): _JSON_ - The mapping object that allows for **dynamic value insertion via data functions**,
  executed at the time when the credentials is claimed. This feature enables personalized credentials based on real-time
  data. Learn more about it and see a list of supported data functions [here](../data-functions).
- `authenticationMethod`: (optional) _String_ - Defines which OIDC4VC exchange flow is used (pre-auth or full-auth). If
  no value is
  provided, it will default to pre-auth flow indicated as `PRE_AUTHORIZED`. The parameter options are:

<details><summary>Expand To Learn More About The Options</summary>

- `PWD` - used for authorization code flow with username/password authentication with external auth server
- `ID_TOKEN` - used for authorization code flow with id_token authentication. When this method is used an authorization
  request is sent to the wallet, which generates and issues the ID_TOKEN using its DID (
  Decentralized Identifier). The issuer then verifies the ID_TOKEN to confirm the holder's identity and DID.
- `VP_TOKEN` - used for authorization code flow with vp_token(OIDC4VP). With this method, the receiver of the
  credential must be authenticated by presenting the requested credential. The credential which must be presented can
  be configured using the `vpRequestedValue` as explained below. The policies which are applied to the presented
  credential
  are 'signature,' 'expired,' and 'not-before.' Learn more about
  policies [here](https://docs.walt.id/enterprise-stack/services/verifier-service/policies/overview.md).
- `NONE` - used for authorization code flow with none authentication method
- `PRE_AUTHORIZED` - used for pre-authorizated code flow

**Additional parameters required for selected auth method:**

**For "ID_TOKEN" and "VP_TOKEN":**

- `useJar`: (Optional) _Boolean_ - used for using JAR OAuth specification in the id/vp_token requests. If omitted, the
  default value is true.

**For VP_TOKEN:**

- `vpRequestedValue`: _String_ - Specifies the requested credential type value for the VP token. E.g. "VerifiableId"
- `vpProfile`: (Optional) _String_ - Specifies the profile of the VP request. Available Profiles: DEFAULT: For W3C
  OpenID4VP,
  ISO_18013_7_MDOC: For MDOC OpenID4VP, EBSIV3: For EBSI V3 Compliant VP. If omitted, the default value is DEFAULT

</details>

---

**Example Response**

The issuer endpoint will respond with Credential Offer URL.

**Plain Response**

```
openid-credential-offer://issuer.portal.walt.id/?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.portal.walt.id%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegree%22%5D%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegree%22%5D%7D%7D%5D%2C%22grants%22%3A%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%220431b78c-cd94-4f50-bfdf-e24d436c0cf6%22%7D%2C%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIwNDMxYjc4Yy1jZDk0LTRmNTAtYmZkZi1lMjRkNDM2YzBjZjYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5wb3J0YWwud2FsdC5pZCIsImF1ZCI6IlRPS0VOIn0.NorG7GtjmA-HXMJfUzU9vfnshcIgFY0oYQb8qJjDfORPoNxuurgySSOIDKFi7Z4XJmC-oJZnM0Nbb0NUd57cDA%22%2C%22user_pin_required%22%3Afalse%7D%7D%7D
```

**Decoded**

```
openid-credential-offer://issuer.portal.walt.id/?
credential_offer=
{
  "credential_issuer": "https://issuer.demo.walt.id",
  "credentials": [
    {
      "format": "jwt_vc_json",
      "types": [
        "VerifiableCredential", 
        "UniversityDegree"
      ],
      "credential_definition": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1", 
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "types": [
          "VerifiableCredential", 
          "UniversityDegree"
        ]
      }
    }
  ],
  "grants": {
    "authorization_code": {
      "issuer_state": "0431b78c-cd94-4f50-bfdf-e24d436c0cf6"
    },
    "urn:ietf:params:oauth:grant-type:pre-authorized_code": {
      "pre-authorized_code": "eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIwNDMxYjc4Yy1jZDk0LTRmNTAtYmZkZi1lMjRkNDM2YzBjZjYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5wb3J0YWwud2FsdC5pZCIsImF1ZCI6IlRPS0VOIn0.NorG7GtjmA-HXMJfUzU9vfnshcIgFY0oYQb8qJjDfORPoNxuurgySSOIDKFi7Z4XJmC-oJZnM0Nbb0NUd57cDA",
      "user_pin_required": false
    }
  }
}

```

**Option: With Revocation Status**

[API Reference](https://issuer.demo.walt.id/swagger/index.html#/Credential%20Issuance/post_openid4vc_sdjwt_issue)

**Option: CURL**

Endpoint: `/v1/{target}/issuer-service-api/credentials/issue` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%2F%20Issuer%20Service/post_v1__target__issuer_service_api_credentials_issue)
**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.issuer1/issuer-service-api/credentials/issue' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'statusCallbackUri: https://example.com/$id' \
  -H 'Content-Type: application/json' \
  -d '{
  "issuerKeyId": "waltid.tenant1.kms1.key1",
  "issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
  "credentialConfigurationId": "UniversityDegree_jwt_vc_json",
  "credentialData": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
    ],
    "id": "http://example.gov/credentials/3732",
    "type": [
      "VerifiableCredential",
      "UniversityDegree"
    ],
    "issuer": {
      "id": "did:web:vc.transmute.world"
    },
    "issuanceDate": "2020-03-10T04:24:12.164Z",
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "degree": {
        "type": "BachelorDegree",
        "name": "Bachelor of Science and Arts"
      }
    }
  },
  "status": {
    "statusCredentialConfig": "waltid.tenant1.credential-status-service-1.config1",
    "initialStatus": "0x0"
  },
  "mapping": {
    "id": "<uuid>",
    "issuer": {
      "id": "<issuerDid>"
    },
    "credentialSubject": {
      "id": "<subjectDid>"
    },
    "issuanceDate": "<timestamp>",
    "expirationDate": "<timestamp-in:365d>"
  },
  "authenticationMethod": "PRE_AUTHORIZED"
}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + issuer service with which to execute
  the credential issuance (`{organizationID}.{tenantID}.{issuerServiceID}`), e.g. `waltid.tenant1.issuer1`

**Header Parameters**

- `statusCallbackUri`: _URL_ - Receive updates on the created issuance process, e.g. when a credential was successfully
  claimed. The parameter expects a URL which can accept a JSON POST request. The URL can also hold a `$id`, which will
  be
  replaced by the issuance session id. For example: `https://myurl.com/$id`, `https://myurl.com`
  or `https://myurl.com/test/$id`
  <br/>
  <br />
  <details><summary>Expand To Learn More</summary>

  <br /> 

  **Body**

  The data send to the provided URL will contain a JSON body:
    - `id` : _String_ - the issuance session id
    - `type`: _String_ - the event type
    - `data`: _JsonObject_ - the data for the event

  **Event Types**

  Possible events (event types) and their data are:
    - `resolved_credential_offer` with the credential offer as JSON (in our Web Wallet: called when the issuance offer
      is
      entered into the wallet, but not processing / accepted yet)
    - `requested_token` with the issuance request for the token as json object (called for the token required to receive
      the
      credentials)

  Credential issuance (called for every credential that's issued (= requested from wallet))
    - `jwt_issue` with `jwt` being the issued jwt
    - `sdjwt_issue` with `sdjwt` being the issued sdjwt
    - `batch_jwt_issue` with `jwt` being the issued jwt
    - `batch_sdjwt_issue` with `sdjwt` being the issued sdjwt
    - `generated_mdoc` with `mdoc` being the CBOR (HEX) of the signed mdoc

  To allow for secure business logic flows, if a callback URL is set, and it cannot be reached, the issuance will not
  commence further (after that point). If no callback URL is set, the issuance logic does not change in any way.

  </details>

**Body**

```json
{
  "issuerKeyId": "waltid.tenant1.kms1.key1",
  "issuerDid": "did:key:z6MkjoRhq1jSNJdLiruSXrFFxagqrztZaXHqHGUTKJbcNywp",
  "credentialConfigurationId": "UniversityDegree_jwt_vc_json",
  "credentialData": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
    ],
    "id": "http://example.gov/credentials/3732",
    "type": [
      "VerifiableCredential",
      "UniversityDegree"
    ],
    "issuer": {
      "id": "did:web:vc.transmute.world"
    },
    "issuanceDate": "2020-03-10T04:24:12.164Z",
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "degree": {
        "type": "BachelorDegree",
        "name": "Bachelor of Science and Arts"
      }
    }
  },
  "status": {
    "statusCredentialConfig": "waltid.tenant1.credential-status-service-1.config1",
    "initialStatus": "0x0"
  },
  "mapping": {
    "id": "<uuid>",
    "issuer": {
      "id": "<issuerDid>"
    },
    "credentialSubject": {
      "id": "<subjectDid>"
    },
    "issuanceDate": "<timestamp>",
    "expirationDate": "<timestamp-in:365d>"
  },
  "authenticationMethod": "PRE_AUTHORIZED"
}
```

**Body Parameters**

- `issuerKeyId`: _resourceIdentifier_ - The keyID of a key stored in
  a [KMS service](https://docs.walt.id/enterprise-stack/services/key-management-service/overview.md) under the same tenant.
  E.g. `waltid.tenant1.kms1.key1`
- `issuerDid`: _String_ - The DID related to the provided key.
- `credentialConfigurationId`: _String_ - Reference to a specific credential configuration the issuer supports. As our
  issuer currently supports W3C JWT & SD-JWT credentials and SD-JWT VCs (IETF). The structure of the
  credentialConfigurationId is the following: "
  credentialType_jwt_vc_json" for W3C JWT & SD-JWT credentials
  and "credentialType_vc+sd-jwt" for SD-JWT VCs (IETF). E.g. "UniversityDegree_jwt_vc_json" or "
  UniversityDegree_vc+sd-jwt".
  You can also view
  the credentialConfigurationIds by visiting the `/.well-known/openid-credential-issuer` endpoint of your issuer.
  The metadata of our deployed issuer for testing can be
  seen [here](https://issuer.demo.walt.id/swagger/index.html#/oidc/get__well_known_openid_credential_issuer).
- `credentialData`: _JSON_ - A credential data structure to sign (W3C compliant). A list of predefined valid structures
  can be
  found [here](https://credentials.walt.id/).
- `mapping` (optional): _JSON_ - The mapping object that allows for **dynamic value insertion via data functions**,
  executed at the time when the credentials is claimed. This feature enables personalized credentials based on real-time
  data. Learn more about it and see a list of supported data functions [here](../data-functions.md).
- `authenticationMethod`: (optional) _String_ - Defines which OIDC4VC exchange flow is used (pre-auth or full-auth). If
  no value is
  provided, it will default to pre-auth flow indicated as `PRE_AUTHORIZED`. The parameter options are:

<details><summary>Expand To Learn More About The Options</summary>

- `PWD` - used for authorization code flow with username/password authentication with external auth server
- `ID_TOKEN` - used for authorization code flow with id_token authentication. When this method is used an authorization
  request is sent to the wallet, which generates and issues the ID_TOKEN using its DID (
  Decentralized Identifier). The issuer then verifies the ID_TOKEN to confirm the holder's identity and DID.
- `VP_TOKEN` - used for authorization code flow with vp_token(OIDC4VP). With this method, the receiver of the
  credential must be authenticated by presenting the requested credential. The credential which must be presented can
  be configured using the `vpRequestedValue` as explained below. The policies which are applied to the presented
  credential
  are 'signature,' 'expired,' and 'not-before.' Learn more about
  policies [here](https://docs.walt.id/enterprise-stack/services/verifier-service/policies/overview.md).
- `NONE` - used for authorization code flow with none authentication method
- `PRE_AUTHORIZED` - used for pre-authorizated code flow

**Additional parameters required for selected auth method:**

**For "ID_TOKEN" and "VP_TOKEN":**

- `useJar`: (Optional) _Boolean_ - used for using JAR OAuth specification in the id/vp_token requests. If omitted, the
  default value is true.

**For VP_TOKEN:**

- `vpRequestedValue`: _String_ - Specifies the requested credential type value for the VP token. E.g. "VerifiableId"
- `vpProfile`: (Optional) _String_ - Specifies the profile of the VP request. Available Profiles: DEFAULT: For W3C
  OpenID4VP,
  ISO_18013_7_MDOC: For MDOC OpenID4VP, EBSIV3: For EBSI V3 Compliant VP. If omitted, the default value is DEFAULT

</details>

**Example Response**

The issuer endpoint will respond with Credential Offer URL.

**Plain Response**

```
openid-credential-offer://issuer.portal.walt.id/?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fissuer.portal.walt.id%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22jwt_vc_json%22%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegree%22%5D%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegree%22%5D%7D%7D%5D%2C%22grants%22%3A%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%22280b7b66-b8ba-420e-91f1-f3bb684d3edf%22%7D%2C%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIyODBiN2I2Ni1iOGJhLTQyMGUtOTFmMS1mM2JiNjg0ZDNlZGYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5wb3J0YWwud2FsdC5pZCIsImF1ZCI6IlRPS0VOIn0.H0HUMNQ5jSzrNEkaVyKlwK4yDq8_sOzRZuQ-2nCwFKMsTrFzEXj95lsgo0Av5RhnOIrhBd98jGjZ0DDwEONwDg%22%2C%22user_pin_required%22%3Afalse%7D%7D%7D
```

**Decoded**

```
openid-credential-offer://issuer.portal.walt.id/?credential_offer={
  "credential_issuer": "https://issuer.demo.walt.id",
  "credentials": [
    {
      "format": "jwt_vc_json",
      "types": [
        "VerifiableCredential",
        "UniversityDegree"
      ],
      "credential_definition": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "types": [
          "VerifiableCredential",
          "UniversityDegree"
        ]
      }
    }
  ],
  "grants": {
    "authorization_code": {
      "issuer_state": "280b7b66-b8ba-420e-91f1-f3bb684d3edf"
    },
    "urn:ietf:params:oauth:grant-type:pre-authorized_code": {
      "pre-authorized_code": "eyJhbGciOiJFZERTQSJ9.eyJzdWIiOiIyODBiN2I2Ni1iOGJhLTQyMGUtOTFmMS1mM2JiNjg0ZDNlZGYiLCJpc3MiOiJodHRwczovL2lzc3Vlci5wb3J0YWwud2FsdC5pZCIsImF1ZCI6IlRPS0VOIn0.H0HUMNQ5jSzrNEkaVyKlwK4yDq8_sOzRZuQ-2nCwFKMsTrFzEXj95lsgo0Av5RhnOIrhBd98jGjZ0DDwEONwDg",
      "user_pin_required": false
    }
  }
}

```

When you receive the credential using our web wallet and make a presentation to a verifier, you will see that before
accepting the verification request, you will have the option to select which field(s) to share that were marked as
selectively disclosable.

**Note:**

If you want to dive deeper into the issuer service, you can go [here](https://docs.walt.id/enterprise-stack/services/issuer-service/overview.md).

#### Receive the Credential Offer

Use the Enterprise Wallet Service to receive and store the credential:

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/credentials/receive`

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.wallet1/wallet-service-api/credentials/receive' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "offerUrl": "<paste-offer-url-from-issuer-step>",
  "keyReference": "waltid.tenant1.wallet-kms-1.wallet_key",
  "didReference": "waltid.tenant1.wallet-did-store-1.wallet_did"
}'
```

This runs the full OID4VCI flow from the wallet-side and stores the received credential in the linked Credential Store.

Optional: You can also render the credential offer as a QR code for any OID4VCI-compliant wallet to scan.

### Verify A Credential

To request and verify the credential issued previously we will leverage the verifier service and make the following
request.

**Option: Without Credential Status**

**Option: CURL**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.verifier1/verifier-service-api/credentials/verify' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'authorizeBaseUrl: openid4vp://authorize' \
  -H 'responseMode: direct_post' \
  -H 'successRedirectUri: https://example.com/success/{id}' \
  -H 'errorRedirectUri: https://example.com/error/{id}' \
  -H 'statusCallbackUri: https://example.com/status_callback/{id}' \
  -H 'statusCallbackApiKey: myAPIKey' \
  -H 'stateId: myUniqueStateValue' \
  -H 'Content-Type: application/json' \
  -d '{
  "request_credentials": [
    { "type": "UniversityDegree", "format": "jwt_vc_json" }
  ]
}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + verifier service with which to
  execute
  the credential verification (`{organizationID}.{tenantID}.{verifierServiceID}`), e.g. `waltid.tenant1.verifier1`

**Header Parameters**

- **authorizeBaseUrl** - is used to modify the start of the OID4VC request URL. If you are using the
  cross-device
  flow, where you will display the URL as a QR code, you can leave the value as `openid4vp://authorize` or if you don't
  know the wallet the user will be using to claim the credential. If you are using the same device flow, where you
  already
  know the user's wallet and want the user to be able to go directly to it, you can use the wallet URL path that is able
  to
  receive an OIDC request as a query parameter. Our wallet for example can receive OID4VC requests here
  `https://wallet.demo.walt.id/wallet-api/wallet/{wallet}/exchange/useOfferRequest`.

- **responseMode** - should be `direct_post` as the other options are not yet supported.
- **successRedirectUri** (optional) - is used to redirect the user if verification is successful. You can use the `$id`
  placeholder
  to get access to the id of verification session in your application in order to retrieve the verification results.
  E.g. `/success?id=$id` will be replaced with `/success?id=1234567890`
- **errorRedirectUri** (optional) - is used to redirect the user if verification is unsuccessful. You can use the `$id`
  placeholder
  to get access to the id of verification session in your application in order to retrieve the verification results.
  E.g. `/error?id=$id` will be replaced with `/error?id=1234567890`
- **statusCallbackUri** (optional) - URL that should be called when the presentation request has been fulfilled by a
  wallet. The request
  sent will be a `POST` including the whole presentation
  result. [See Verification Status Policies Response](#verification-status-policies-response)
- **statusCallbackApiKey** (optional) - If the endpoint you provide via `statusCallbackUri` is protected, you can use
  the `statusCallbackApiKey` to authenticate.
  The provided key will be appended as Authorization Header to the request.
- **stateId** (optional) - overwrite the unique `state` value which gets created for each verification request with your
  own.
- **openId4VPProfile** (optional) - Define profile for VP (Verifiable Presentation) request. The default is W3C
  OpenID4VP, which can optionally provided as `DEFAULT`.
  Apart from that, you can choose from the following options:
    - `EBSIV3`: For EBSI V3 compliant VP. Learn more [here](https://docs.walt.id/community-stack/verifier/ecosystems/ebsi/overview.md).
    - `ISO_18013_7_MDOC`: For mdoc Openid4VP.

**Body**

```json
{
  "request_credentials": [
    { "type": "UniversityDegree", "format": "jwt_vc_json" }
  ]
}
```

**Body Parameters**

- **request_credentials** - An array of objects detailing the credentials to be requested from the user. Each object
  varies based on the type of credential being requested.
  <br/>
  <details><summary>Expand To Learn More</summary>

  Below are the possible credential types and their respective object structures:

    1. **W3C JWT Credential**

    - **type** Specifies the type of credential (e.g., `VerifiableID`, `VerifiableDiploma`). This maps to the `type`
      attribute in W3C credentials.
    - **format**: Describes the format of the credential. For W3C JWT credentials, this would
      be `jwt_vc_json`.
      ```json
      { "type": "ProofOfResidence", "format": "jwt_vc_json" }
      ```

    2. **SD-JWT VC Credential (IETF Standard)**

    - **vct**: Specifies the type of credential (e.g., https://issuer.com/identity_credential). This maps to
      the `vct`
      attribute in the SD-JWT VC credential.
    - **format**: Describes the format of the credential. For SD-JWT VC credentials, this would be
      vc+sd-jwt.: Describes the format of the credential. For SD-JWT VC credentials, this would be `vc+sd-jwt`.
     ```json
     { "vct": "test.com/identity_credential", "format": "vc+sd-jwt" }
     ```
    3. **mDL Credential (ISO/IEC 18013-5)**

    - **doc_type**: Specifies the type of credential (e.g., org.iso.18013.5.1.mDL). This maps to the doc_type
      attribute of
      the mdoc document.
    - **format**: Describes the format of the credential. For mDL credentials, this would be `mso_mdoc`.
      ```json
      { "doc_type": "org.iso.18013.5.1.mDL", "format": "mso_mdoc" }
      ```

  **Optional Parameters**
  <br />
  Next to describing the type and format of the credential, the objects also take an optional `policies` and `id`
  attribute

    - **policies**: An array of policies to apply to the specified credential. A list of all policies can be
      found [here](https://docs.walt.id/enterprise-stack/services/verifier-service/policies/overview.md).
    - **id**: Used to set a specific id for the
      generated [Presentation Definition](https://identity.foundation/presentation-exchange/spec/v1.0.0/#presentation-definition).
      If not set,
      the verifier API auto-assigns a generated one.

  </details>

**Option: With Credential Status**

**Option: CURL**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.verifier1/verifier-service-api/credentials/verify' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'authorizeBaseUrl: openid4vp://authorize' \
  -H 'responseMode: direct_post' \
  -H 'successRedirectUri: https://example.com/success/{id}' \
  -H 'errorRedirectUri: https://example.com/error/{id}' \
  -H 'statusCallbackUri: https://example.com/status_callback/{id}' \
  -H 'statusCallbackApiKey: myAPIKey' \
  -H 'stateId: myUniqueStateValue' \
  -H 'Content-Type: application/json' \
  -d '{
  "request_credentials": [
    {
      "type": "UniversityDegree",
      "format": "jwt_vc_json",
      "policies": [
        {
          "policy": "credential-status",
          "args": {
            "discriminator": "w3c",
            "value": 0,
            "purpose": "revocation",
            "type": "StatusList2021"
          }
        }
      ]
    }
  ]
}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + verifier service with which to
  execute
  the credential verification (`{organizationID}.{tenantID}.{verifierServiceID}`), e.g. `waltid.tenant1.verifier1`

**Header Parameters**

- **authorizeBaseUrl** - is used to modify the start of the OID4VC request URL. If you are using the
  cross-device
  flow, where you will display the URL as a QR code, you can leave the value as `openid4vp://authorize` or if you don't
  know the wallet the user will be using to claim the credential. If you are using the same device flow, where you
  already
  know the user's wallet and want the user to be able to go directly to it, you can use the wallet URL path that is able
  to
  receive an OIDC request as a query parameter. Our wallet for example can receive OID4VC requests here
  `https://wallet.demo.walt.id/wallet-api/wallet/{wallet}/exchange/useOfferRequest`.

- **responseMode** - should be `direct_post` as the other options are not yet supported.
- **successRedirectUri** (optional) - is used to redirect the user if verification is successful. You can use the `$id`
  placeholder
  to get access to the id of verification session in your application in order to retrieve the verification results.
  E.g. `/success?id=$id` will be replaced with `/success?id=1234567890`
- **errorRedirectUri** (optional) - is used to redirect the user if verification is unsuccessful. You can use the `$id`
  placeholder
  to get access to the id of verification session in your application in order to retrieve the verification results.
  E.g. `/error?id=$id` will be replaced with `/error?id=1234567890`
- **statusCallbackUri** (optional) - URL that should be called when the presentation request has been fulfilled by a
  wallet. The request
  sent will be a `POST` including the whole presentation
  result. [See Verification Status Policies Response](#verification-status-policies-response)
- **statusCallbackApiKey** (optional) - If the endpoint you provide via `statusCallbackUri` is protected, you can use
  the `statusCallbackApiKey` to authenticate.
  The provided key will be appended as Authorization Header to the request.
- **stateId** (optional) - overwrite the unique `state` value which gets created for each verification request with your
  own.
- **openId4VPProfile** (optional) - Define profile for VP (Verifiable Presentation) request. The default is W3C
  OpenID4VP, which can optionally provided as `DEFAULT`.
  Apart from that, you can choose from the following options:
    - `EBSIV3`: For EBSI V3 compliant VP. Learn more [here](https://docs.walt.id/community-stack/verifier/ecosystems/ebsi/overview.md).
    - `ISO_18013_7_MDOC`: For mdoc Openid4VP.

**Body**

```json
{
  "request_credentials": [
    {
      "type": "UniversityDegree",
      "format": "jwt_vc_json",
      "policies": [
        {
          "policy": "credential-status",
          "args": {
            "discriminator": "w3c",
            "value": 0,
            "purpose": "revocation",
            "type": "StatusList2021"
          }
        }
      ]
    }
  ]
}
```

**Body Parameters**

- **request_credentials** - An array of objects detailing the credentials to be requested from the user. Each object
  varies based on the type of credential being requested.
  <br/>
  <details><summary>Expand To Learn More</summary>

  Below are the possible credential types and their respective object structures:

    1. **W3C JWT Credential**

    - **type** Specifies the type of credential (e.g., `VerifiableID`, `VerifiableDiploma`). This maps to the `type`
      attribute in W3C credentials.
    - **format**: Describes the format of the credential. For W3C JWT credentials, this would
      be `jwt_vc_json`.
      ```json
      { "type": "ProofOfResidence", "format": "jwt_vc_json" }
      ```

    2. **SD-JWT VC Credential (IETF Standard)**

    - **vct**: Specifies the type of credential (e.g., https://issuer.com/identity_credential). This maps to
      the `vct`
      attribute in the SD-JWT VC credential.
    - **format**: Describes the format of the credential. For SD-JWT VC credentials, this would be
      vc+sd-jwt.: Describes the format of the credential. For SD-JWT VC credentials, this would be `vc+sd-jwt`.
     ```json
     { "vct": "test.com/identity_credential", "format": "vc+sd-jwt" }
     ```
    3. **mDL Credential (ISO/IEC 18013-5)**

    - **doc_type**: Specifies the type of credential (e.g., org.iso.18013.5.1.mDL). This maps to the doc_type
      attribute of
      the mdoc document.
    - **format**: Describes the format of the credential. For mDL credentials, this would be `mso_mdoc`.
      ```json
      { "doc_type": "org.iso.18013.5.1.mDL", "format": "mso_mdoc" }
      ```

  **Optional Parameters**
  <br />
  Next to describing the type and format of the credential, the objects also take an optional `policies` and `id`
  attribute

    - **policies**: An array of policies to apply to the specified credential. A list of all policies can be
      found [here](https://docs.walt.id/enterprise-stack/services/verifier-service/policies/overview.md).
    - **id**: Used to set a specific id for the
      generated [Presentation Definition](https://identity.foundation/presentation-exchange/spec/v1.0.0/#presentation-definition).
      If not set,
      the verifier API auto-assigns a generated one.

  </details>

#### Present the Credential

Use the Enterprise Wallet Service to present the stored credential in response to the verifier’s request URL.

#### Find Matching Credentials via Presentation Definition

Before presenting, use the wallet's linked credential store to find credentials matching the verifier's presentation definition. From the response, take the `_id` (e.g., `waltid.tenant1.wallet-credential-store-1.3d629d4b-...`) and use it in the next step.

**Option: CURL**

Endpoint: `/v1/{target}/credential-store-service-api/credentials/query/document/schema`

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.wallet-credential-store-1/credential-store-service-api/credentials/query/document/schema' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '[
  {
    "path": ["$.vc.type"],
    "filter": { "type": "string", "pattern": "UniversityDegree" }
  }
]'
```

**Path Parameters**

- **`orgID`**: - When performing operations within an organization, it is essential to use the organization's Base URL or another valid host alias. For example, if your organization is named `test`, your default Base URL will be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- **`target`**: resourceIdentifier - The target indicates the organization + tenant + credential store which should be used to query for credentials (`{organizationID}.{tenantID}.[credentialStoreID]`), e.g. `waltid.tenant1.credential-store1`

**Body**

```json
[
  {
    "path": ["$.vc.type"],
    "filter": { "type": "string", "pattern": "UniversityDegree" }
  }
]
```

**Body Parameters**

- **`Array of contraints.fields`** - In the body of the request, we provide an array containing the values for each `constraints.fields` entry in all `input_descriptors` objects of the presentation definition provided in the Authorization Request. For example, the presentation definition for the body provided above looks as follows:

```json
{
  "id": "ANREjIRDBnb",
  "input_descriptors": [
    {
      "id": "BankId",
      "format": {
        "jwt_vc_json": {
          "alg": [
            "EdDSA"
          ]
        }
      },
      "constraints": {
        "fields": [
          // ⬇️ what we provide in the body ⬇️
          {
            "path": [
              "$.vc.type"
            ],
            "filter": {
              "type": "string",
              "pattern": "BankId"
            }
          }
          // ⬆️ what we provide in the body ⬆️
        ]
      }
    }
  ],
  "format": {
    "jwt_vp_json": {
      "alg": [
        "ES256"
      ]
    }
  }
}
```

---

**Reponse Codes**
- `200` - Matching credentials

**Body**

```json
[
  {
    "_id": "waltid.tenant1.wallet-credential-store-1.b5db5ab5-03cb-4103-a0ff-0299edad15ee",
    "credential": {
      "type": "vc-w3c_1_1",
      "disclosables": {},
      "credentialData": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "id": "urn:uuid:4b776a85-dbc3-4c14-9c0f-2428a3e98b7b",
        "type": [
          "VerifiableCredential",
          "UniversityDegree"
        ],
        "issuer": {
          "id": "did:key:z6Mkkbug58H7h3fts2W8mqQUPGTeXX3wEa32fY3Jk15nJNYf"
        },
        "issuanceDate": "2025-08-18T12:35:53.055156800Z",
        "credentialSubject": {
          "id": "did:key:z6MkegzJFcs5txZwv4NrAx2JAkv38MYq9ydwjsFXsV3Sn1Ed",
          "degree": {
            "type": "BachelorDegree",
            "name": "Bachelor of Science and Arts"
          }
        },
        "credentialStatus": {
          "id": "https://83abcuyiuweiuoyiy8943ir732yjhghj23gdnshuy7623rjh23jhrg23g78hkkk.s3.amazonaws.com/waltid.tenant1.credential-status-service-1.config1#10561",
          "type": "StatusList2021Entry",
          "statusPurpose": "revocation",
          "statusListIndex": "10561",
          "statusSize": 1,
          "statusListCredential": "https://83abcuyiuweiuoyiy8943ir732yjhghj23gdnshuy7623rjh23jhrg23g78hkkk.s3.amazonaws.com/waltid.tenant1.credential-status-service-1.config1",
          "statusMessage": [
            {
              "status": "0x0",
              "message": "unset"
            },
            {
              "status": "0x1",
              "message": "set"
            }
          ]
        },
        "expirationDate": "2026-08-18T12:35:53.055397550Z"
      },
      "signature": {
        "type": "signature-jwt",
        "signature": "hsHnzRzN_-Tcq0TPiJYKxJnCIliIq63LcQpC7ctKSegc6Rb40dSx6puhgX9qIOFo1mOAGSsEcjMk8pTc8MwYBQ"
      },
      "signed": "eyJraWQiOiJkaWQ6a2V5Ono2TWtrYnVnNThIN2gzZnRzMlc4bXFRVVBHVGVYWDN3RWEzMmZZM0prMTVuSk5ZZiN6Nk1ra2J1ZzU4SDdoM2Z0czJXOG1xUVVQR1RlWFgzd0VhMzJmWTNKazE1bkpOWWYiLCJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtrYnVnNThIN2gzZnRzMlc4bXFRVVBHVGVYWDN3RWEzMmZZM0prMTVuSk5ZZiIsInN1YiI6ImRpZDprZXk6ejZNa2VnekpGY3M1dHhad3Y0TnJBeDJKQWt2MzhNWXE5eWR3anNGWHNWM1NuMUVkIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy9leGFtcGxlcy92MSJdLCJpZCI6InVybjp1dWlkOjRiNzc2YTg1LWRiYzMtNGMxNC05YzBmLTI0MjhhM2U5OGI3YiIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlIl0sImlzc3VlciI6eyJpZCI6ImRpZDprZXk6ejZNa2tidWc1OEg3aDNmdHMyVzhtcVFVUEdUZVhYM3dFYTMyZlkzSmsxNW5KTllmIn0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMDgtMThUMTI6MzU6NTMuMDU1MTU2ODAwWiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmtleTp6Nk1rZWd6SkZjczV0eFp3djROckF4MkpBa3YzOE1ZcTl5ZHdqc0ZYc1YzU24xRWQiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovLzgzYWJjdXlpdXdlaXVveWl5ODk0M2lyNzMyeWpoZ2hqMjNnZG5zaHV5NzYyM3JqaDIzamhyZzIzZzc4aGtray5zMy5hbWF6b25hd3MuY29tL3dhbHRpZC50ZW5hbnQxLmNyZWRlbnRpYWwtc3RhdHVzLXNlcnZpY2UtMS5jb25maWcxIzEwNTYxIiwidHlwZSI6IlN0YXR1c0xpc3QyMDIxRW50cnkiLCJzdGF0dXNQdXJwb3NlIjoicmV2b2NhdGlvbiIsInN0YXR1c0xpc3RJbmRleCI6IjEwNTYxIiwic3RhdHVzU2l6ZSI6MSwic3RhdHVzTGlzdENyZWRlbnRpYWwiOiJodHRwczovLzgzYWJjdXlpdXdlaXVveWl5ODk0M2lyNzMyeWpoZ2hqMjNnZG5zaHV5NzYyM3JqaDIzamhyZzIzZzc4aGtray5zMy5hbWF6b25hd3MuY29tL3dhbHRpZC50ZW5hbnQxLmNyZWRlbnRpYWwtc3RhdHVzLXNlcnZpY2UtMS5jb25maWcxIiwic3RhdHVzTWVzc2FnZSI6W3sic3RhdHVzIjoiMHgwIiwibWVzc2FnZSI6InVuc2V0In0seyJzdGF0dXMiOiIweDEiLCJtZXNzYWdlIjoic2V0In1dfSwiZXhwaXJhdGlvbkRhdGUiOiIyMDI2LTA4LTE4VDEyOjM1OjUzLjA1NTM5NzU1MFoifSwianRpIjoidXJuOnV1aWQ6NGI3NzZhODUtZGJjMy00YzE0LTljMGYtMjQyOGEzZTk4YjdiIiwiZXhwIjoxNzg3MDU2NTUzLCJpYXQiOjE3NTU1MjA1NTMsIm5iZiI6MTc1NTUyMDU1M30.hsHnzRzN_-Tcq0TPiJYKxJnCIliIq63LcQpC7ctKSegc6Rb40dSx6puhgX9qIOFo1mOAGSsEcjMk8pTc8MwYBQ"
    },
    "parent": "waltid.tenant1.wallet-credential-store-1"
  }
]
```

The returned array will include `_id` values like `waltid.tenant1.wallet-credential-store-1.<credentialId>` that you can pass directly in the `credentials` array when presenting.

**Present Credential via wallet**

**Option: CURL**

Endpoint: `/v1/{target}/wallet-service-api/credentials/present`

**Example Request**

```bash
curl -X 'POST' \
  'http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.wallet1/wallet-service-api/credentials/present' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "requestUrl": "<paste-verifier-request-url>",
  "keyReference": "waltid.tenant1.wallet-kms-1.wallet_key",
  "didReference": "waltid.tenant1.wallet-did-store-1.wallet_did",
  "credentials": [
    { "credential": "waltid.tenant1.wallet-credential-store-1.<credentialIdFromPreviousStep>" }
  ]
}'
```

You must provide at least one credential to present via the `credentials` array. Use the presentation-definition query step above to obtain a valid credential reference from the wallet's Credential Store.

#### (Optional) Selective disclosure

If your credential supports selectively disclosable fields, you can specify exactly which fields to share:

```json
{
  "credentials": [
    {
      "credential": "waltid.tenant1.wallet-credential-store-1.<credentialId>",
      "disclosures": [
        "$.name",
        "$.credentialSubject.achievement.description"
      ]
    }
  ]
}
```

**Note:**

Under the hood, the wallet wraps the credential(s) in a Verifiable Presentation and signs it with the holder’s key referenced by `keyReference`, proving possession to the verifier.

#### Inspect Verification Result

After the we've presented the credential(s), we can now verify the status by performing the following call with the
`state` value obtained from the URL query params we received from the verifier service previously.

**Option: CURL**

**Example**

```
openid4vp://authorize?...state=waltid.tenant1.verifier1.fb94470b-bcee-4ed7-93f5-906a4f5f585d...
```

Making the call to receive the verification result

```bash
curl -X 'GET' \
  'http://waltid.enterprise.localhost:3000/v1/{state}/verifier-service-api/credentials/sessions/view' \
  -H 'accept: */*'
  -H 'Authorization: Bearer {yourToken}'
```

**Path Parameters**

- `orgID`: - When performing operations within an organization, it is essential to use the organization's Base URL or
  another valid host alias. For example, if your organization is named `test`, your default Base URL will
  be `test.enterprise-sandbox.walt.dev` when using the sandbox environment.
- `target`: _resourceIdentifier_ - The target indicates the organization + tenant + verifier service + sessionID to request
  (`{organizationID}.{tenantID}.{verifierServiceID}.{sessionID}`),
  e.g. `waltid.tenant1.verifier1.fb94470b-bcee-4ed7-93f5-906a4f5f585d`
  In this flow, the `state` value from the OID4VP request URL already contains this full target, so it can be used as is.

##### Verification Status Policies Response

The response of the verification status call will contain the status of the verification policies applied to the
credential(s) presented by the user. The policy results will be in the following format:

```json
{
  "verificationResult": true,
  "policyResults": {
    "results": [
      {
        "credential": "VerifiableDiploma",
        "policies": [
          {
            "policy": "signature",
            "is_success": true
          }
        ]
      }
    ]
  }
}
```

The `verificationResult` field will be `true` if all policies were successful, otherwise it will be `false`.

The `policyResults` field will contain the results of the policies applied to each credential. The `credential` field
will contain the name of the credential, and the `policies` field will contain the results of the policies applied to
the credential. The `policy` field will contain the name of the policy, and the `is_success` field will contain the
result of the policy.

**Note:**

  Want to learn more about the verifier service in detail? Please
  go [here](https://docs.walt.id/enterprise-stack/services/verifier-service/overview.md).

## 5. Bonus
With this we went through a whole credential issuance and verification flow using different services of the walt.id 
Enterprise Stack. If you want, you can now (when you issued a credential with status), revoke the issued credential and 
run through the verification another time. This time it should fail. For guidence on how to revoke the credential, please go [here](https://docs.walt.id/enterprise-stack/services/credential-status-service/manage.md#update-a-credential-status).

## 6. Next Steps

1. Explore administrative features (e.g. Access & Permissions, Events & Metrics) [here](https://docs.walt.id/enterprise-stack/administration.md).
2. Explore the different services (e.g KMS, issuer, verifier, wallet) [here](https://docs.walt.id/enterprise-stack/services.md).
