Skip to main content

Webhook Events

Organisation Wallet by iGrant.io provides webhooks to notify your application about important events in the OpenID4VC-based credential issuance and verification process. This document lists all available webhook events and their descriptions for the OpenID4VC implementation.

Webhook Management

Before receiving webhook events, you need to configure your webhook endpoints. The following APIs are available for managing webhooks:

APIDescriptionDocumentation
Create WebhookCreate a new webhook endpointCreate Webhook
Read WebhookGet details of a specific webhookRead Webhook
Update WebhookModify an existing webhook configurationUpdate Webhook
Delete WebhookRemove a webhook endpointDelete Webhook
List WebhooksGet all configured webhooksList Webhooks

Issuer Webhooks

Issuer webhooks notify you about events related to credential issuance and management.

Event NameDescription
openid.credential.offer_sentTriggered when a credential offer is created and delivered using QR code or credential offer endpoint
openid.credential.offer_receivedTriggered when a credential offer is accessed by the wallet unit (or holder)
openid.credential.token_issuedTriggered when a token is issued during the credential issuance process
openid.credential.credential_issuedTriggered when a credential is issued to the wallet unit (or holder) by the issuer
openid.credential.credential_ackedTriggered when a credential is received and acknowledged in the wallet unit (or holder)
openid.credential.credential_acceptedTriggered when the credential is accepted by the wallet unit (or holder) to store
openid.credential.credential_deletedTriggered when the credential is deleted by the wallet unit (or holder)
openid.credential.issuance_deniedTriggered when credential issuance is denied for various reasons such as: wallet unit attestation invalid or missing, proof of possession invalid, valid credential already exists (if credential uniqueness is enforced), or authorisation failed

Verifier Webhooks

Verifier webhooks notify you about events related to presentation requests and verifications.

Current Version (v3)

Event NameDescription
openid.presentation.request_sent.v3Triggered when a presentation request is created and delivered using QR code
openid.presentation.request_received.v3Triggered when a presentation request is accessed by the wallet unit (or holder)
openid.presentation.presentation_acked.v3Triggered when a presentation request is received, acknowledged, and verification is performed by the verifier

Deprecated Version

Event NameDescription
openid.presentation.request_sentTriggered when a presentation request is created and delivered using QR code
openid.presentation.request_receivedTriggered when a presentation request is accessed by the wallet unit (or holder)
openid.presentation.presentation_ackedTriggered when a presentation request is received, acknowledged, and verification is performed by the verifier

Webhook Payload

Each webhook event includes a JSON payload containing relevant information about the event. The payload structure follows a consistent format with common fields and event-specific data.

Common Payload Fields

FieldTypeDescription
deliveryIDstringUnique identifier for this webhook delivery
webhookIDstringIdentifier of the webhook configuration
timestampstringISO 8601 timestamp of when the event occurred
typestringThe type of event (e.g. "openid.credential.offer_sent")
dataobjectEvent-specific payload data that varies by event type

Payload Structure

All webhook events follow this consistent structure:

Issuance Webhook Example

{
"deliveryID": "67f770eec8426b0b55e30c2e",
"webhookID": "67f770936e45cf84e6880d25",
"timestamp": "2025-04-10T07:19:10Z",
"data": {
"credential": {
"CredentialExchangeId": "3e154218-88d5-4529-8143-bf1ccf0e08c0",
"credentialDefinitionId": "a79fb535-5e17-4571-928a-7b30011e4fa8",
"walletUnitAttestationVerified": false
// Additional credential history fields
},
"organisationId": "64ec561de2f6a8000142c671"
},
"type": "openid.credential.offer_sent"
}

Verification Webhook Example

{
"deliveryID": "67f77188c8426b0b55e30d08",
"webhookID": "67f770936e45cf84e6880d25",
"timestamp": "2025-04-10T07:21:44Z",
"data": {
"organisationId": "64ec561de2f6a8000142c671",
"presentation": {
"presentationExchangeId": "73315f05-089f-4548-b7ba-052ce828c7d7",
"presentationDefinitionId": "bd28cfc2-4938-4f47-b91a-77412676d107",
"walletUnitAttestationVerified": false
// Additional verification history fields
}
},
"type": "openid.presentation.request_received.v3"
}

For detailed field definitions, please refer to:

Delivery Guarantees

Webhook delivery follows an at-most-once guarantee. This means:

  • Delivery is attempted once
  • There is no built-in retry mechanism if the target endpoint is unreachable or errors out
  • It is recommended to implement appropriate error handling and logging on your webhook endpoint

For detailed information about the payload structure for each event type, please refer to the specific event documentation.

Webhook Security

Each webhook delivery includes an X-iGrant-Signature header that allows you to verify the authenticity of the webhook. The signature is generated using HMAC-SHA256 and includes a timestamp to prevent replay attacks.

Signature Format

The X-iGrant-Signature header follows this format:

X-iGrant-Signature: t=<timestamp>,sig=<signature>

Where:

  • timestamp: ISO 8601 timestamp in UTC (e.g., "2025-04-10T07:19:10Z")
  • signature: HMAC-SHA256 signature of the payload

Verifying the Signature

To verify a webhook signature:

  1. Extract the timestamp and signature from the header
  2. Get the raw request body
  3. Concatenate the timestamp and request body with a period (.)
  4. Compute HMAC-SHA256 using your webhook's secret key
  5. Compare the computed signature with the received signature

Example verification code in Go:

func verifyWebhookSignature(timestamp, signature, secretKey string, payload []byte) bool {
// Construct the signed payload
signedPayload := timestamp + "." + string(payload)

// Create HMAC-SHA256 hash
h := hmac.New(sha256.New, []byte(secretKey))
h.Write([]byte(signedPayload))

// Get the computed signature
computedSig := hex.EncodeToString(h.Sum(nil))

// Compare signatures
return hmac.Equal([]byte(computedSig), []byte(signature))
}

Security Best Practices

  1. Always verify the webhook signature before processing the payload
  2. Check that the timestamp is recent (e.g., within 5 minutes) to prevent replay attacks
  3. Keep your webhook secret key secure and never share it
  4. Use HTTPS endpoints for webhook delivery
  5. Consider implementing rate limiting to prevent abuse