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:
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 |
Verifier Webhooks
Verifier webhooks notify you about events related to presentation requests and verifications.
Current Version (v3)
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 |
Deprecated Version
Event Name | Description |
---|---|
openid.presentation.request_sent | Triggered when a presentation request is created and delivered using QR code |
openid.presentation.request_received | Triggered when a presentation request is accessed by the wallet unit (or holder) |
openid.presentation.presentation_acked | 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
- Send verification request response section for deprecated 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
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:
- 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