Create a Credential Offer

This guide walks you through creating a credential offer from an existing profile. The offer generates an OID4VCI credential offer URL that can be claimed by any compliant wallet.

Prerequisites

Before creating an offer, ensure you have:

  1. Issuer2 API running
  2. Credential Profile configured

Create an Offer

Endpoint: POST /issuer2/credential-offers

Basic Pre-Authorized Offer

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED"
  }'

Response

{
  "offerId": "abc123-def456-ghi789",
  "profileId": "university-degree",
  "authMethod": "PRE_AUTHORIZED",
  "expiresAt": 1704067500000,
  "credentialOffer": "openid-credential-offer://?credential_offer_uri=http%3A%2F%2Flocalhost%3A7002%2Fopenid4vci%2Fcredential-offer%3Fid%3Dabc123-def456-ghi789"
}

Request Parameters

Required Parameters

ParameterTypeDescription
profileIdStringThe ID of the credential profile to use
authMethodStringAuthentication method: PRE_AUTHORIZED or AUTHORIZED

Optional Parameters

  • valueMode: String – How the credential offer is delivered (default: BY_REFERENCE)
    • BY_REFERENCE – Offer URL contains a reference; wallet fetches full offer
    • BY_VALUE – Full credential offer embedded in URL
  • issuerStateMode: String – Whether to include issuer state (default: OMIT)
    • OMIT – No issuer state
    • INCLUDE – Include issuer state for session correlation for usage with authorization servers.
  • expiresInSeconds: Integer – Offer validity duration in seconds (default: 300). Set to -1 for no expiration.
  • txCode: Object – Transaction code (PIN) configuration for pre-authorized flow
  • txCodeValue: String – Specific PIN value (if not provided, one is generated)
  • runtimeOverrides: Object – Override profile values for this offer. See Runtime Overrides.
  • sessionId: String – Session ID for the offer. If not provided, a random session ID will be generated.

Examples

Pre-Authorized Flow with PIN

Require a PIN for additional security:

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED",
    "txCode": {
      "inputMode": "numeric",
      "length": 6,
      "description": "Please enter the PIN sent to your email"
    }
  }'

Response includes the PIN:

{
  "offerId": "abc123-def456-ghi789",
  "profileId": "university-degree",
  "authMethod": "PRE_AUTHORIZED",
  "expiresAt": 1704067500000,
  "txCodeValue": "123456",
  "credentialOffer": "openid-credential-offer://..."
}

Pre-Authorized Flow with Custom PIN

Specify your own PIN value:

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED",
    "txCode": {
      "inputMode": "numeric",
      "length": 4
    },
    "txCodeValue": "1234"
  }'

Authorization Code Flow

For user authentication via external IdP:

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "authenticated-credential",
    "authMethod": "AUTHORIZED",
    "issuerStateMode": "INCLUDE"
  }'

Note: The same issuer_state parameter from the offer is forwarded to the Authorization Service in the authorization request. Thus, the authorization request received by the authorization server looks like this, https://keycloak.demo.walt.id/realms/mynewrealm/protocol/openid-connect/auth?client_id=issuer_api&redirect_uri=http://integration-test.enterprise.localhost:33334/v2/integration-test.test-issuer2-keycloak-auth.issuer-2-keycloak/issuer-service-api/openid4vci/callback&scope=openid_profile&state=74b5206d7a15c9ec&response_type=code&*issuer_state=cadbeaf4-d412-4ce3-b8d4-e8d5c70d4a3f*

Offer by Value

Embed the full offer in the URL (useful for offline scenarios):

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED",
    "valueMode": "BY_VALUE"
  }'

Custom Expiration

Set a longer expiration time:

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED",
    "expiresInSeconds": 3600
  }'

Runtime Overrides

Override profile values for a specific offer:

curl -X POST 'http://localhost:7002/issuer2/credential-offers' \
  -H 'Content-Type: application/json' \
  -d '{
    "profileId": "university-degree",
    "authMethod": "PRE_AUTHORIZED",
    "runtimeOverrides": {
      "credentialData": {
        "@context": [
          "https://www.w3.org/2018/credentials/v1",
          "https://www.w3.org/2018/credentials/examples/v1"
        ],
        "type": ["VerifiableCredential", "UniversityDegree"],
        "credentialSubject": {
          "degree": {
            "type": "MasterDegree",
            "name": "Master of Computer Science"
          }
        }
      },
      "notifications": {
        "webhook": {
          "url": "https://my-server.com/webhook/special-offer"
        }
      }
    }
  }'

Available Override Fields

FieldDescription
issuerDidOverride the issuer DID
issuerKeyIdOverride the signing key
x5ChainOverride the X.509 certificate chain
subjectIdSet the credential subject ID
credentialDataOverride the credential data
mappingOverride the data mapping
idTokenClaimsMappingOverride ID token claims mapping
mDocNameSpacesDataMappingConfigOverride mDoc data mapping
credentialStatusOverride credential status configuration
notificationsOverride notification settings
w3cVersionOverride the vc data model version

Transaction Code Configuration

The txCode object configures PIN requirements:

PropertyTypeDescription
inputModeStringInput type: numeric or text
lengthIntegerLength of the PIN
descriptionStringDescription shown to the user

Response Fields

FieldDescription
offerIdUnique identifier for this offer
profileIdThe profile used to create this offer
authMethodThe authentication method
issuerStateModeThe issuer state mode (for authorized flow)
expiresAtUnix timestamp when the offer expires
txCodeValueThe PIN value (only for pre-authorized flow with txCode)
credentialOfferThe OID4VCI credential offer URL

Using the Credential Offer URL

The credentialOffer URL can be:

  1. Displayed as QR Code – User scans with their wallet app
  2. Sent as Deep Link – User clicks link on mobile device
  3. Embedded in Email/Message – User clicks to open in wallet

Example Decoded Offer URL

openid-credential-offer://?credential_offer_uri=http://localhost:7002/openid4vci/credential-offer?id=abc123-def456-ghi789

Next Steps

Last updated on June 16, 2026