Webhook Events
Organisation Wallet Suite 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:
| API | Description | Documentation |
|---|---|---|
| Create Webhook | Create a new webhook endpoint | Create Webhook |
| Read Webhook | Get details of a specific webhook | Read Webhook |
| Update Webhook | Modify an existing webhook configuration | Update Webhook |
| Delete Webhook | Remove a webhook endpoint | Delete Webhook |
| List Webhooks | Get all configured webhooks | List Webhooks |
Issuer Webhooks
Issuer webhooks notify you about events related to credential issuance and management.
| Event Name | Description |
|---|---|
openid.credential.offer_sent | Triggered when a credential offer is created and delivered using QR code or credential offer endpoint |
openid.credential.offer_received | Triggered when a credential offer is accessed by the wallet unit (or holder) |
openid.credential.token_issued | Triggered when a token is issued during the credential issuance process |
openid.credential.credential_issued | Triggered when a credential is issued to the wallet unit (or holder) by the issuer |
openid.credential.credential_acked | Triggered when a credential is received and acknowledged in the wallet unit (or holder) |
openid.credential.credential_accepted | Triggered when the credential is accepted by the wallet unit (or holder) to store |
openid.credential.credential_deleted | Triggered when the credential is deleted by the wallet unit (or holder) |
openid.credential.issuance_denied | Triggered 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 |
openid.credential.credential_revoked | Triggered when the issuer revokes an issued credential |
openid.credential.credential_suspended | Triggered when the issuer suspends an issued credential |
openid.credential.credential_reactivated | Triggered when the issuer reactivates a suspended credential |
Holder Webhooks
Holder webhooks notify you about events in the organisation wallet when it receives credentials and answers presentation requests.
| Event Name | Description |
|---|---|
openid.holder.credential.credential_pending | Triggered when the wallet waits for a deferred credential |
openid.holder.credential.credential_acked | Triggered when the wallet receives a credential |
openid.holder.credential.credential_accepted | Triggered when the wallet accepts and stores a credential |
openid.holder.credential.credential_revoked | Triggered when the wallet finds that the issuer revoked a held credential |
openid.holder.credential.credential_suspended | Triggered when the wallet finds that the issuer suspended a held credential |
openid.holder.credential.credential_reactivated | Triggered when the wallet finds that the issuer reactivated a held credential |
openid.holder.presentation.presentation_pending.v3 | Triggered when the wallet receives a presentation request |
openid.holder.presentation.presentation_acked.v3 | Triggered when the wallet sends the presentation to the verifier |
Verifier Webhooks
Verifier webhooks notify you about events related to presentation requests and verifications.
| Event Name | Description |
|---|---|
openid.presentation.request_sent.v3 | Triggered when a presentation request is created and delivered using QR code |
openid.presentation.request_received.v3 | Triggered when a presentation request is accessed by the wallet unit (or holder) |
openid.presentation.presentation_acked.v3 | Triggered 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
| Field | Type | Description |
|---|---|---|
deliveryID | string | Unique identifier for this webhook delivery |
webhookID | string | Identifier of the webhook configuration |
timestamp | string | ISO 8601 timestamp of when the event occurred |
type | string | The type of event (e.g. "openid.credential.offer_sent") |
data | object | Event-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:
- Issue credential response section for issuance webhooks
- Send verification request (v3) response section for current version verification webhooks
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
When the webhook has a secret key, each 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. A ping has no signature.
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, in lowercase hexadecimal
The service always signs the JSON payload. When the content type of the webhook is application/x-www-form-urlencoded, the JSON payload is in the payload form field: URL decode it before you check the signature.
Verifying the Signature
To verify a webhook signature:
- Extract the timestamp and signature from the header
- Get the raw request body
- Concatenate the timestamp and request body with a period (
.) - Compute HMAC-SHA256 using your webhook's secret key
- 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
- Always verify the webhook signature before processing the payload
- Check that the timestamp is recent (e.g., within 5 minutes) to prevent replay attacks
- Keep your webhook secret key secure and never share it
- Use HTTPS endpoints for webhook delivery
- Consider implementing rate limiting to prevent abuse