Receiving SD-JWT VC Credentials via OID4VCI 1.0

This guide shows how to receive an IETF SD-JWT VC credential into an Enterprise wallet using the Wallet API v2. You take a credential offer — for example one created with Issuer2 — and claim it into the wallet in a single call, then confirm it was stored.

SD-JWT VC: An IETF credential format supporting selective disclosure, letting the holder reveal only specific claims when presenting.

This page follows the pre-authorized code flow. For the authorization-code grant and for driving each step yourself (custom UIs, deferred issuance), see Custom Flow.

Prerequisites

  • A wallet service with a linked KMS, DID Store, and Credential Store — see Setup. The wallet's default key and DID are used unless you override them.
  • The wallet's target{organization}.{tenant}.{wallet-id}, e.g. waltid.tenant1.wallet.
  • An SD-JWT VC credential offer (openid-credential-offer://…), for example from the Issuer2 service.

Receive the Credential

This single call resolves the offer, requests an access token, signs a proof of possession with the wallet's key, fetches the credential, and stores it in the linked Credential Store.

CURL

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

Example Request

curl -X POST \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials/receive' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "offerUrl": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.example.org%2Fcredential-offer%3Fid%3Dabc123"
}'

Path Parameters

  • orgID String — Organization host alias to call against, e.g. test.enterprise-sandbox.waltid.dev for organization test.
  • target resourceIdentifier — The wallet's resource path, {organization}.{tenant}.{wallet-id}, e.g. waltid.tenant1.wallet.

Body Parameters

  • Credential offer (required) — provide exactly one of:
    • offerUrl String — OID4VCI credential offer URL.
    • offerJson Object — Raw credential offer as a JSON object, instead of a URL.
  • keyId (optional) String — Full resource path of a key in a linked KMS ({org}.{tenant}.{kms}.{key}). Defaults to the first key in the wallet's linked KMS (or the service's configured static key if the KMS has none).
  • key (optional) Object — Inline serialized key ({ "type": "jwk", "jwk": { … } }). Takes precedence over keyId.
  • did (optional) String — Holder DID. Defaults to the first DID in the wallet's linked DID Store (or the configured static DID). If the issuer uses DID-based proof binding and you pass a custom keyId/key, also pass the did associated with that key — otherwise the wallet's default DID is used for binding instead.
  • txCode (optional) String — Transaction code (PIN), if the pre-authorized offer requires one.
  • clientId (optional) String — OAuth 2.0 client_id presented to the issuer's authorization server. Defaults to wallet-client.

Example Response

{
  "credentialIds": [
    "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
  ],
  "deferredTransactionIds": {}
}
  • credentialIds String — IDs of the credentials received and stored in the wallet's Credential Store.
  • deferredTransactionIds Object — Map of credential configuration ID → transaction_id, present only when the issuer defers issuance. See deferred credentials.

Response Codes

  • 200 — Credential(s) received and stored.
  • 400 — Invalid request (e.g. neither offerUrl nor offerJson provided, or the offer could not be resolved).
  • 401 — Invalid authentication.

🎉 You've received an SD-JWT VC into the wallet.


Confirm It Was Stored

List the wallet's credentials to see the one you just received. This returns metadata only.

CURL

Endpoint: GET /v2/{target}/wallet-service-api/credentials

Example Request

curl \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v2/{org}.{tenant}.{wallet-id}/wallet-service-api/credentials' \
  -H 'Authorization: Bearer {yourToken}'

Path Parameters

  • orgID String — Organization host alias.
  • target resourceIdentifier — The wallet's resource path, e.g. waltid.tenant1.wallet.

Example Response

[
  {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "format": "dc+sd-jwt",
    "issuer": "did:jwk:eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwi...",
    "addedAt": "2026-07-09T13:24:04.282744Z"
  }
]
  • id String — The stored credential's ID. Use it with the management endpoints to view or delete it.
  • format String — Credential format. For an SD-JWT VC this is dc+sd-jwt.
  • issuer / subject (optional) String — Issuer and holder identifiers, when present (subject is often absent for SD-JWT VC).
  • addedAt String — ISO-8601 timestamp of when the credential was stored.

Response Codes

  • 200 — Credential metadata returned.
  • 401 — Invalid authentication.

Doing It Step by Step

The full-flow call above is the fastest path. To show intermediate state in a wallet UI — resolve the offer, preview what's being issued, prompt for a PIN, handle deferred issuance — drive the isolated endpoints yourself:

resolve-offerrequest-tokensign-prooffetch-credential

Each step, its request/response shape, and the authorization-code variant are documented in Custom Flow.


Next Steps

Last updated on July 13, 2026