Isolated Flow

The full-flow endpoint (credentials/present) matches, signs, and submits in one call. The isolated flow lets you drive each step yourself when you need to:

  • Preview which credentials (and claims) will be shared, and show a consent screen
  • Let the user choose between multiple matching credentials
  • Present credentials that aren't stored in the wallet (supplied inline)
  • Inspect intermediate results

All endpoints live under /v2/{target}/wallet-service-api/.

Flow Overview

1. Resolve VP Request     →  parse request URL → authorizationRequest, nonce, clientId, responseUri, dcqlQuery
2. Match Credentials      →  DCQL match (from store or inline) → matched credential IDs
   ── show user consent screen ──
3. Build VP Token         →  sign selected stored credentials → vpToken
4. Send Response          →  submit vpToken → WalletPresentResult

Step 1 — Resolve VP Request

Parse the verifier's authorization request to extract its metadata.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/resolve-request

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/resolve-request' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "requestUrl": "openid4vp://authorize?client_id=did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0&request_uri=https://verifier.example.org/request/abc123"
}'

Body Parameters

  • requestUrl String — The OID4VP authorization request URL.

Example Response

{
  "authorizationRequest": {
    "nonce": "n-0S6_WzA2Mj",
    "client_id": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0",
    "response_uri": "https://verifier.example.org/response",
    "dcql_query": {
      "credentials": [
        {
          "id": "identity_credential",
          "format": "dc+sd-jwt"
        }
      ]
    }
  },
  "nonce": "n-0S6_WzA2Mj",
  "clientId": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0",
  "responseUri": "https://verifier.example.org/response",
  "hasRequestUri": true,
  "dcqlQuery": {
    "credentials": [
      {
        "id": "identity_credential",
        "format": "dc+sd-jwt"
      }
    ]
  }
}
  • authorizationRequest — Complete resolved authorization request. Pass it to Step 3 — Build VP Token and Step 4 — Send Response.
  • nonce — The verifier's nonce for replay protection.
  • clientId — The verifier's client identifier (typically a DID).
  • responseUri — The URL the presentation is submitted to.
  • hasRequestUri — Whether the request was fetched from a request_uri.
  • dcqlQuery — The verifier's DCQL query. Pass this to Step 2a or Step 2b.

Response Codes

  • 200 — Request resolved.
  • 400 — The request URL/object is malformed and cannot be parsed.
  • 500 — The request_uri could not be fetched (e.g. the verifier's request endpoint returned 404).

Step 2a — Match Credentials from Store

DCQL-match the dcqlQuery returned by Step 1 against the wallet's own stored credentials. This is the recommended matching step when credentials live in the wallet's Credential Store.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/match-credentials-from-store

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/match-credentials-from-store' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "dcqlQuery": {
    "credentials": [
      {
        "id": "identity_credential",
        "format": "dc+sd-jwt",
        "meta": { "vct_values": ["https://issuer.example.org/identity_credential"] },
        "claims": [
          { "path": ["given_name"] },
          { "path": ["family_name"] }
        ]
      }
    ]
  }
}'

Body Parameters

  • dcqlQuery Object — The DCQL query returned by Step 1.

Example Response

{
  "matchedQueryIds": ["identity_credential"],
  "matchCount": 1,
  "matchedCredentialIds": {
    "identity_credential": ["550e8400-e29b-41d4-a716-446655440000"]
  }
}
  • matchedQueryIds — DCQL query IDs for which at least one credential matched.
  • matchCount — Total number of matches across all query IDs.
  • matchedCredentialIds — For each matched query ID, the wallet-assigned credential IDs. Use these IDs in Step 3.

Response Codes

  • 200 — Matching completed.
  • 400 — Invalid DCQL query.

Step 2b — Match Inline Credentials

DCQL-match against credentials you supply inline — useful to preview matches for credentials that aren't stored in the wallet.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/match-credentials

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/match-credentials' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "dcqlQuery": {
    "credentials": [
      {
        "id": "identity_credential",
        "format": "dc+sd-jwt",
        "meta": { "vct_values": ["https://issuer.example.org/identity_credential"] },
        "claims": [ { "path": ["given_name"] } ]
      }
    ]
  },
  "credentials": [
    {
      "id": "cred-1",
      "credential": {
        "type": "vc-sd_jwt",
        "format": "dc+sd-jwt",
        "credentialData": {
          "given_name": "John",
          "family_name": "Doe",
          "vct": "https://issuer.example.org/identity_credential",
          "cnf": { "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "…" } }
        },
        "disclosures": [
          { "salt": "…", "name": "birthdate", "value": "1990-01-15", "location": ["birthdate"], "encoded": "…" }
        ],
        "signed": "eyJraWQiOiJHMzdKaUdyM3B0bEQ…",
        "signature": { "type": "signature-sd_jwt", "jwtHeader": { "typ": "dc+sd-jwt", "alg": "EdDSA" } }
      }
    }
  ]
}'

Body Parameters

  • dcqlQuery Object — The DCQL query from the verifier's authorization request.
  • credentials Array — Credentials to match against, each with an id (a caller-assigned label) and a credential object. The credential's shape depends on the credential format (its type field is vc-sd_jwt, vc-w3c_2, or vc_mdocs) — it is not a { format, rawCredential } pair. The easiest way to obtain it is to copy the credential field from the wallet's GET /v2/{target}/wallet-service-api/credentials/{credentialId} response (abbreviated with above).

Example Response

Same structure as Step 2a.

Response Codes

  • 200 — Matching completed.
  • 400 — Invalid DCQL query or credentials.

Step 3 — Build VP Token

After the user consents, build and sign a vp_token from the selected stored credentials. This step does not submit anything to the verifier.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/build-vp-token

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/build-vp-token' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "authorizationRequest": {
    "nonce": "n-0S6_WzA2Mj",
    "client_id": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0",
    "response_uri": "https://verifier.example.org/response",
    "dcql_query": {
      "credentials": [
        { "id": "identity_credential", "format": "dc+sd-jwt" }
      ]
    }
  },
  "selectedCredentialIds": {
    "identity_credential": ["550e8400-e29b-41d4-a716-446655440000"]
  }
}'

Body Parameters

  • authorizationRequest Object — The resolved authorization request returned by Step 1.
  • selectedCredentialIds Object — Map of DCQL query ID to wallet credential IDs selected by the user.
  • key (optional) Object — Inline key used to sign the VP token. Takes precedence over keyId.
  • keyId (optional) String — Key used to sign the VP token. Defaults to the first key in the wallet's linked KMS or the service's configured static key.
  • did (optional) String — DID for holder binding. Defaults to the first DID in the linked DID Store or the configured static DID.

Example Response

{
  "vpToken": "{\"identity_credential\":\"eyJhbGciOiJFUzI1NiIs...\"}",
  "idToken": null
}
  • vpToken — Serialized vp_token JSON string.
  • idToken (optional) — Self-issued ID token for SIOPv2 flows, when one is required.

Response Codes

  • 200 — VP token built.
  • 400 — Selected credentials do not satisfy the authorization request.

Step 4 — Send Response

Send the built VP token to the verifier according to the response mode in the resolved authorization request.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/send-response

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/send-response' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "authorizationRequest": {
    "nonce": "n-0S6_WzA2Mj",
    "client_id": "did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0",
    "response_uri": "https://verifier.example.org/response"
  },
  "vpToken": "{\"identity_credential\":\"eyJhbGciOiJFUzI1NiIs...\"}",
  "idToken": null
}'

Body Parameters

  • authorizationRequest Object — The resolved authorization request returned by Step 1.
  • vpToken String — The VP token returned by Step 3.
  • idToken (optional) String — The ID token returned by Step 3, when present.

Example Response

Returns the same WalletPresentResult shape as the full-flow response.

Response Codes

  • 200 — Authorization response transmitted.
  • 400 — The response could not be sent to the verifier.

Present Inline Credentials

Use the isolated endpoint below when the credentials are supplied inline rather than loaded from the wallet's stores.

CURL

Endpoint: POST /v2/{target}/wallet-service-api/credentials/present/isolated

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/present/isolated' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "requestUrl": "openid4vp://authorize?client_id=did:jwk:eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5In0&request_uri=https://verifier.example.org/request/abc123",
  "credentials": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "credential": {
        "type": "vc-sd_jwt",
        "format": "dc+sd-jwt",
        "credentialData": {
          "given_name": "John",
          "family_name": "Doe",
          "vct": "https://issuer.example.org/identity_credential",
          "cnf": { "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "…" } }
        },
        "disclosures": [
          { "salt": "…", "name": "birthdate", "value": "1990-01-15", "location": ["birthdate"], "encoded": "…" }
        ],
        "signed": "eyJraWQiOiJHMzdKaUdyM3B0bEQ…",
        "signature": { "type": "signature-sd_jwt", "jwtHeader": { "typ": "dc+sd-jwt", "alg": "EdDSA" } }
      }
    }
  ]
}'

Body Parameters

  • requestUrl String — The OID4VP authorization request URL.
  • credentials Array — The credentials to present, each with an id (a caller-assigned label) and a credential object. The credential's shape depends on the credential format (its type field is vc-sd_jwt, vc-w3c_2, or vc_mdocs) — it is not a { format, rawCredential } pair. Copy it from the credential field of the wallet's GET /v2/{target}/wallet-service-api/credentials/{credentialId} response (abbreviated with above).
  • keyId (optional) String — ID of the key to sign with. Defaults to the first key in the wallet's linked KMS (or the service's configured static key if the KMS has none).
  • did (optional) String — DID to present as. Defaults to the first DID in the wallet's linked DID Store (or the configured static DID).

Example Response

{
  "transmission_success": true,
  "verifier_response": {
    "status": "received",
    "message": "Presentation received and is being processed."
  }
}

WalletPresentResult fields are the same as the full-flow responsetransmission_success, verifier_response, and (only when the verifier redirects) redirect_to / get_url / form_post_html.

Response Codes

  • 200 — Presentation built and submitted. If no supplied credential satisfied the DCQL query, this still returns 200 with "transmission_success": false and the error in verifier_response.
  • 400 — The presentation request could not be resolved.

Next Steps

Last updated on July 27, 2026