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:
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
| Parameter | Type | Description |
|---|---|---|
profileId | String | The ID of the credential profile to use |
authMethod | String | Authentication 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 offerBY_VALUE– Full credential offer embedded in URL
issuerStateMode: String – Whether to include issuer state (default:OMIT)OMIT– No issuer stateINCLUDE– Include issuer state for session correlation for usage with authorization servers.
expiresInSeconds: Integer – Offer validity duration in seconds (default: 300). Set to-1for no expiration.txCode: Object – Transaction code (PIN) configuration for pre-authorized flowtxCodeValue: 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
| Field | Description |
|---|---|
issuerDid | Override the issuer DID |
issuerKeyId | Override the signing key |
x5Chain | Override the X.509 certificate chain |
subjectId | Set the credential subject ID |
credentialData | Override the credential data |
mapping | Override the data mapping |
idTokenClaimsMapping | Override ID token claims mapping |
mDocNameSpacesDataMappingConfig | Override mDoc data mapping |
credentialStatus | Override credential status configuration |
notifications | Override notification settings |
w3cVersion | Override the vc data model version |
Transaction Code Configuration
The txCode object configures PIN requirements:
| Property | Type | Description |
|---|---|---|
inputMode | String | Input type: numeric or text |
length | Integer | Length of the PIN |
description | String | Description shown to the user |
Response Fields
| Field | Description |
|---|---|
offerId | Unique identifier for this offer |
profileId | The profile used to create this offer |
authMethod | The authentication method |
issuerStateMode | The issuer state mode (for authorized flow) |
expiresAt | Unix timestamp when the offer expires |
txCodeValue | The PIN value (only for pre-authorized flow with txCode) |
credentialOffer | The OID4VCI credential offer URL |
Using the Credential Offer URL
The credentialOffer URL can be:
- Displayed as QR Code – User scans with their wallet app
- Sent as Deep Link – User clicks link on mobile device
- 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
- Notifications – Configure webhook notifications
- Data Functions – Populate credentials with dynamic data
