Receiving Credentials via OID4VCI

This guide shows you how to receive a verifiable credential into the walt.id Wallet SDK using OID4VCI 1.0. You hand the wallet a credential offer — typically an openid-credential-offer:// URL from Portal2 — and the wallet claims the credential and stores it.

OID4VCI: The protocol used to deliver credentials from an issuer to a wallet.

This page uses isolated session steps so you can show issuer, credential, and transaction-code metadata before the holder accepts. The same session APIs work for SD-JWT VC, W3C VC, and ISO 18013-5 mDL.

Prerequisites

Before you begin, ensure you have:

Always test receive through portal2.demo.walt.id.


How Issuance Works

Issuance is a session. Start it to resolve the offer and show issuer, credential, and transaction-code metadata. Continue it after the holder accepts — and after they enter a transaction code when the issuer requires one.

Loading diagram...

  1. Start the session with the offer URI (or inline JSON for the Digital Credentials API create flow).
  2. Show the typed issuer and credential metadata, and collect a transaction code only when the session requires one.
  3. Continue the matching grant, or cancel if the holder declines.

Pre-authorized Code

Use this path when the offer includes a pre-authorized code.

Kotlin
Swift
val session = wallet.startIssuance(
    MobileWalletIssuanceRequest(offer = MobileWalletCredentialOffer.Uri(offerUrl))
)
val transactionCode = session.offer.transactionCode?.let { requirement ->
    collectTransactionCode(
        inputMode = requirement.inputMode ?: "numeric",
        expectedLength = requirement.length,
        description = requirement.descriptionText,
    )
}
val outcome = wallet.continuePreAuthorizedIssuance(session.id, transactionCode)
val credentialIds = (outcome as? WalletIssuanceOutcome.Stored)?.credentialIds
    ?: error("Issuance did not store credentials: $outcome")

MobileWalletCredentialOffer.Uri is for QR and deep-link offers. Use MobileWalletCredentialOffer.InlineJson when the offer arrives through the Digital Credentials API create flow.

🎉 You've received a credential into the wallet.


Authorization Code

For an authorization-code offer, start the session, let the holder accept, then open the authorization URL and continue with the callback. beginAuthorizationIssuance creates browser state, PKCE, and the callback binding only after that explicit acceptance.

Kotlin
Swift
val authorization = wallet.beginAuthorizationIssuance(session.id)
openBrowser(authorization.url)
val outcome = wallet.continueAuthorizationIssuance(session.id, callbackUri)

If the holder closes the review without accepting, cancel the session instead of continuing:

wallet.cancelIssuance(session.id)

Deferred Issuance

When the issuer defers credential delivery, continuation returns WalletIssuanceOutcome.Deferred instead of Stored. Poll with resumeDeferredIssuance(deferredCredentialId) until the credential is stored.

Next Steps

Last updated on September 29, 2026