---
title: "Verifying Verifiable Credentials via Digital Credentials API"
description: "Request and verify Verifiable Credentials (W3C) via Digital Credentials API (DC API) using the walt.id Enterprise Stack Verifier2 API."
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/services/verifier2-service/credential-verification/dc-api
generated: 2026-07-20
---
# Verifying Verifiable Credentials via Digital Credentials API

This guide shows you how to verify credentials using the browser-native Digital Credentials API (DC API). The DC API enables secure, native credential sharing directly through the user's browser or operating system, providing a seamless user experience without redirects or QR codes.

We recommend checking out our [Digital Credential Button project](https://github.com/walt-id/waltid-identity/tree/main/waltid-applications/waltid-digital-credentials), which provides a reference for how to invoke the Browser-based DC API. It contains up to date tutorials for setting up an end to end demo utilizing the DC API. This guide will just focus on how to configure the Verifier API for this use case.

## Prerequisites
Before you begin, ensure you have:
- **Verifier2 Service setup** — Follow the [Setup](https://docs.walt.id/enterprise-stack/services/verifier2-service/setup.md) guide
- **DC API-compatible browser** — Chrome 121+, Safari 18+, or Edge 121+ (desktop or mobile)
- **HTTPS enabled** — The DC API only works over secure connections (required for production; localhost is allowed for development)
- **Test wallet** — Use a DC API-compatible wallet for testing
- **X.509 certificate and key** (for signed requests) — Required for HAIP profile and ISO 18013-7 Annex C flows
- **Authentication token** — Bearer token from your Enterprise Stack authentication flow

## Understanding DC API Protocols
The Verifier2 API supports two DC API protocols:

- Over ISO 18013-7 (Annex C) [using flow_type = "dc_api-annex-c"]
- Over OpenID4VP 1.0 (Annex D) [using flow_type = "dc_api"]

For each of these, we support both same device and cross device flows. You can find many examples in the Digital Credential Button project as well as the swagger documentation for the Verifier API.

### Step 1: Preparing the Verification Session

This example requests an mDL credential using the ISO 18013-7 Annex C protocol with signed requests.

**Option: CURL**

**Endpoint:** `POST /v1/{target}/verifier2-service-api/verification-session/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Verifier2%20Service%20-%20Verification%20Sessions/post_v1__target__verifier2_service_api_verification_session_create)

##### Example Request

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/verifier2-service-api/verification-session/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "flow_type": "dc_api",
  "core": {
    "dcql_query": {
      "credentials": [
        {
          "id": "my_mdl",
          "format": "mso_mdoc",
          "meta": {
            "doctype_value": "org.iso.18013.5.1.mDL"
          },
          "claims": [
            {
              "path": ["org.iso.18013.5.1", "family_name"]
            },
            {
              "path": ["org.iso.18013.5.1", "given_name"]
            },
            {
              "path": ["org.iso.18013.5.1", "age_over_21"]
            }
          ]
        }
      ]
    },
    "signed_request": true,
    "encrypted_response": true,
    "clientId": "x509_hash:abc-xyz-base64url-sha256-hash-of-der-x509-leaf",
    "key": {
      "type": "jwk",
      "jwk": {
        "kty": "EC",
        "d": "AEb4k1BeTR9xt2NxYZggdzkFLLUkhyyWvyUOq3qSiwA",
        "crv": "P-256",
        "kid": "_nd-T2YRYLSmuKkJZlRI641zrCIJLTpiHeqMwXuvdug",
        "x": "G_TgBc0BkmMipiQ_6gkamIn3mmp7hcTrZuyrLTmknP0",
        "y": "VkRMZdXYXSMff5AJLrnHiN0x5MV6u_8vrAcytGUe4z4"
      }
    }
  },
  "expectedOrigins": ["https://{orgID}.enterprise-sandbox.waltid.dev"]
}'
```

**Path Parameters**

- **orgID**: _String_ - Your organization ID (e.g., `test` for `test.enterprise-sandbox.waltid.dev`)
- **target**: _String_ - The verifier service target path (e.g., `waltid.verifier1`)

**Header Parameters**

- **Authorization**: _String_ - Bearer token obtained from your Enterprise Stack authentication flow. Format: `Bearer {token}`.

**Body Parameters**

- **flow_type**: _String_ (required) - Specifies how the credential request will be delivered to the holder's wallet. Options:
  - `"cross_device"` — User scans a QR code on a different device (e.g. desktop browser → phone wallet)
  - `"same_device"` — User clicks a deep link on the same device (e.g. phone browser → wallet app on same phone)
  - `"dc_api"` — Browser/OS-native Digital Credentials API (Chrome, Safari, iOS/Android native) over OpenID4VP 1.0 (Annex D).
  - `"dc_api-annex-c"` — Browser/OS-native Digital Credentials API (Chrome, Safari, iOS/Android native) over 18013-7 (Annex C).
- **core**: _Object_ (required) - Defines what credentials to request and which policies to apply. Contains:
  - **dcql_query**: _Object_ (required) - Specifies the credential type, format, and claims to request using the [DCQL query language](https://docs.walt.id/concepts/data-exchange-protocols/dcql.md). You can also use the DCQL builder [here](https://dcql.walt.id/).
    - **credentials**: _Array_ - List of credential queries. Each credential query contains:
      - **id**: _String_ - Unique identifier for this credential in the request (used in policy results)
      - **format**: _String_ - Credential format. For mDL, use `"mso_mdoc"` (mobile security object document).
      - **meta.doctype_value**: _String_ - The ISO mDL document type. For mobile driver's licenses, use `"org.iso.18013.5.1.mDL"`.
      - **claims**: _Array_ (optional) - Specific claims to request from the credential. Each claim has a `path` array with namespace and claim name (e.g. `["org.iso.18013.5.1", "family_name"]`). If omitted, all claims that are non-selectively disclosable are provided by the wallet.
  - **policies**: _Object_ (optional) - Validation rules applied to the received credential. Defaults to signature verification only if omitted.
    - **vc_policies**: _Array_ - Policies applied to individual credentials. Each policy has a `policy` field specifying the policy name. Available policies: `signature`, `expired`, `not-before`, `revoked-status-list`, `schema`, and more. See [Policies](https://docs.walt.id/enterprise-stack/services/verifier2-service/policies/overview.md) for the complete list.
    - **vp_policies**: _Array_ (optional) - Policies applied to the entire presentation (not shown in this example)
  - **expiration_duration**: _String_ (optional) - ISO-8601 duration specifying how long the verification session remains valid. Defaults to 10 minutes (`PT10M`). Example: `"PT1H"` for 1 hour, `"PT30M"` for 30 minutes.
  - **expiration_date**: _String_ (optional) - ISO-8601 datetime specifying the exact time when the session expires. Takes precedence over `expiration_duration` if both are set. Example: `"2026-05-21T15:00:00Z"`. Session expires if left unused (no presentation pushed). Once a presentation is received, the session is no longer eligible for expiry.
- **expectedOrigins**: _Array<String>_ (required for dc_api) - Expected origins for the DC API verification

**Note:**

  Many parameters have defaults configured in the verifier service. Request-level parameters override these defaults for that specific session only.  

---

##### Example Response

```json
{
  "sessionId": "ff4f0c86-56ce-4e4a-a137-dd5569049ff3",
  "bootstrapAuthorizationRequestUrl": "openid4vp://authorize?client_id=...",
  "fullAuthorizationRequestUrl": "openid4vp://authorize?response_type=vp_token&client_id=...",
  "creationTarget": "org.tenant.verifier.ff4f0c86-56ce-4e4a-a137-dd5569049ff3"
}
```

- **sessionId**: _String_ - The unique ID of this verification session
- **bootstrapAuthorizationRequestUrl**: _String_ - Shortened URL using `request_uri` by reference
- **fullAuthorizationRequestUrl**: _String_ - Complete URL with all parameters embedded
- **creationTarget**: _String_ - The target path for this verification session in the Enterprise Stack

### Step 2: Generating the DC API Request

Take the sessionId from Step 1 and make the following request to get the DC API request URL.

**Option: CURL**

**Endpoint:** `GET /v1/{target}/verifier2-service-api/verification-session/{sessionId}/request`

##### Example Request

```bash
curl -X 'GET' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/verifier2-service-api/verification-session/{sessionId}/request' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}'
```

**Path Parameters**

- **orgID**: _String_ - Your organization ID (e.g., `test` for `test.enterprise-sandbox.waltid.dev`)
- **target**: _String_ - The verifier service target path (e.g., `waltid.tenant1.verifier1`)
- **sessionId**: _String_ - The unique ID of the verification session returned from Step 1

**Header Parameters**

- **Authorization**: _String_ - Bearer token obtained from your Enterprise Stack authentication flow. Format: `Bearer {token}`.

---

##### Example Response

This returns the DC API request URL which can be used with the Browser API.

```json
{
  "digital": {
    "requests": [
      {
        "protocol": "openid4vp-v1-signed",
        "data": {
          "request": "eyJ0eXAiOiJvYXV0aC1hdXRoei1yZXErand0IiwiaWF0IjoxNzc5MjkwNjc0LCJhbGciOiJFUzI1NiIsImtpZCI6Il9uZC1UMllSWUxTbXVLa0pabFJJNjQxenJDSUpMVHBpSGVxTXdYdXZkdWcifQ.eyJyZXNwb25zZV90eXBlIjoidnBfdG9rZW4iLCJjbGllbnRfaWQiOiJ4NTA5X2hhc2g6YWJjLXh5ei1iYXNlNjR1cmwtc2hhMjU2LWhhc2gtb2YtZGVyLXg1MDktbGVhZiIsInJlc3BvbnNlX21vZGUiOiJkY19hcGkuand0Iiwibm9uY2UiOiI1MjU1NTE2NS0xMTE5LTQzYjQtOGQ4Zi02ZjNiZmJlNDVmMmIiLCJkY3FsX3F1ZXJ5Ijp7ImNyZWRlbnRpYWxzIjpbeyJpZCI6Im15X21kbCIsImZvcm1hdCI6Im1zb19tZG9jIiwibWV0YSI6eyJkb2N0eXBlX3ZhbHVlIjoib3JnLmlzby4xODAxMy41LjEubURMIn0sImNsYWltcyI6W3sicGF0aCI6WyJvcmcuaXNvLjE4MDEzLjUuMSIsImZhbWlseV9uYW1lIl19LHsicGF0aCI6WyJvcmcuaXNvLjE4MDEzLjUuMSIsImdpdmVuX25hbWUiXX0seyJwYXRoIjpbIm9yZy5pc28uMTgwMTMuNS4xIiwiYWdlX292ZXJfMjEiXX1dfV19LCJjbGllbnRfbWV0YWRhdGEiOnsiandrcyI6eyJrZXlzIjpbeyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoibFpWUGNWWkdQTnpZSXNlNEZXd19JWGo0dDRwWTNwYjNmakpzUEQ3VTNldyIsIngiOiJBQ090dXFXRUVXN0RHLWNsX3o0RGVNTTNia2FUUWlBUC1KcHJrOVRMOXVNIiwieSI6IkhDbjA5ZERMRUZXQXdMZUF3UTBFR2FNaTJCU0I2TEhFTzZNS0Zlb1VPcWciLCJhbGciOiJFQ0RILUVTIiwidXNlIjoiZW5jIn1dfSwidnBfZm9ybWF0c19zdXBwb3J0ZWQiOnsibXNvX21kb2MiOnt9fSwiZW5jcnlwdGVkX3Jlc3BvbnNlX2VuY192YWx1ZXNfc3VwcG9ydGVkIjpbIkExMjhHQ00iXSwiY2xpZW50X25hbWUiOiJWZXJpZmllciJ9LCJleHBlY3RlZF9vcmlnaW5zIjpbImh0dHBzOi8ve29yZ0lEfS5lbnRlcnByaXNlLXNhbmRib3gud2FsdGlkLmRldiJdfQ.oHHikcmtwWZ-V7thIl2p0bclsrQDyNHZBmeLmC8Y_8L9wxIbFJu513Zq97xQUIJjYgy76MZ2qveuTENJCwg3Ew"
        }
      }
    ]
  }
}
```

### Step 3: Handling the Response

Once the wallet presents the credential via the DC API, you'll receive a response containing the verifiable presentation. Pass this to the verifier endpoint to verify the credential and run configured policies.

**Option: CURL**

**Endpoint:** `POST /v1/{target}/verifier2-service-api/verification-session/{sessionId}/response`

##### Example Request

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/verifier2-service-api/verification-session/{sessionId}/response' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "protocol": "openid4vp-v1-signed",
  "data": {
    "vp_token": {
      "my_mdl": ["o2d2ZXJzaW9uYzEuMGlkb2N1bWVudH..."]
    }
  }
}'
```

## Validating the Verification Session

You can query the verification session to check if the user has presented their credential and whether validation succeeded.

**Option: CURL**

**Endpoint:** `GET /v1/{target}/verifier2-service-api/verification-session/{sessionId}/info`

##### Example Request

```bash
curl -X 'GET' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/verifier2-service-api/verification-session/{sessionId}/info' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}'
```

**Path Parameters**

- **orgID**: _String_ - Your organization ID
- **target**: _String_ - The verification session service target path (includes the session ID)
- **sessionId**: _String_ - The unique ID of the verification session

---

##### Example Response

The response contains complete session information including setup, status, policy results, and presented credentials.

**Note:**

Instead of polling the session status, you can use **callbacks** or **Server Sent Events (SSE)** to be notified when the verification completes. See [Callbacks & SSE](https://docs.walt.id/enterprise-stack/services/verifier2-service/configurations/callback-and-sse) for details.

## Additional Resources

You can find more information on how to configure different DC API request flows and how to interact with the Browser-based DC API in our [Digital Credential Button project](https://github.com/walt-id/waltid-identity/tree/main/waltid-applications/waltid-digital-credentials).

## Next Steps

- **Apply custom policies** — See [Policies](https://docs.walt.id/enterprise-stack/services/verifier2-service/policies/overview.md) for validation rules beyond signature verification
- **Set up notifications** — Use [Callbacks & SSE](https://docs.walt.id/enterprise-stack/services/verifier2-service/configurations/callback-and-sse) instead of polling for session status
- **Verify other credential types** — Try [W3C VC](https://docs.walt.id/enterprise-stack/services/verifier2-service/credential-verification/vc-oid4vp.md) or [SD-JWT VC](https://docs.walt.id/enterprise-stack/services/verifier2-service/credential-verification/sd-jwt-vc-oid4vp.md)
