iGrant.io OID4VC API - Webhook group
When to use
Use this skill when you:
- register an external IT system to receive OWS events;
- must know the exact event type strings to subscribe to;
- verify the
X-IGrant-Signatureheader on an incoming delivery; - debug a receiver that gets no events, or reads a delivery record.
Base URL for demo: https://demo-api.igrant.io.
Auth header: Authorization: ApiKey <key> (note the trailing space in the
prefix). A bearer access token also works.
The webhook operations carry only the Webhook tag. They serve every
building block, not the OID4VC wallet alone.
Endpoint reference
| Method | Path | Purpose | Docs |
|---|---|---|---|
| POST | /v2/config/webhook |
Create a webhook | config-create-webhook |
| GET | /v2/config/webhook/{webhookId} |
Read 1 webhook | config-read-webhook |
| PUT | /v2/config/webhook/{webhookId} |
Replace a webhook (full update) | config-update-webhook |
| DELETE | /v2/config/webhook/{webhookId} |
Delete a webhook | config-delete-webhook |
| GET | /v2/config/webhooks |
List webhooks, newest first, with the last delivery result | config-list-webhooks |
| POST | /v2/config/webhook/{webhookId}/ping |
Ping the payload URL to test that it answers | config-ping-webhook |
| GET | /v2/config/webhooks/{webhookId}/deliveries |
List recent deliveries of 1 webhook | config-list-all-recent-webhook-deliveries |
| GET | /v2/config/webhooks/{webhookId}/delivery/{deliveryId} |
Read 1 delivery record | config-read-recent-webhook-delivery |
| GET | /v2/config/webhooks/event-types |
List every subscribable event type | config-read-webhook-event-types |
| GET | /v2/config/webhooks/payload/content-types |
List the payload content types | get-webhook-payload-content-types |
GET /v2/config/webhooks and GET /v2/config/webhooks/{webhookId}/deliveries
take the offset and limit query parameters.
Key fields
Create and update (webhook wrapper)
Both operations wrap the body in a webhook object:
{
"webhook": {
"payloadUrl": "https://example.com/hooks/igrant",
"contentType": "application/json",
"subscribedEvents": {
"digitalWalletWebhook": ["openid.presentation.presentation_acked.v3"]
},
"disabled": false,
"secretKey": "<shared-secret>",
"skipSslVerification": false
}
}
- Required:
payloadUrl,contentType,subscribedEvents,secretKey. Optional:disabled,skipSslVerification. payloadUrlmust start withhttp://orhttps://, and it must be unique in the organisation.subscribedEventsholds 3 arrays:consentManagementWebhook,digitalWalletWebhookanddataMarketplaceWebhook. Subscribe to a minimum of 1 event type.contentTypeisapplication/jsonorapplication/x-www-form-urlencoded.PUTis a full replacement, not a partial update. Send every field on every call. The service keepsid,orgId,sandboxOrgIdandtimestamp;timestampstays the creation time.- Create answers with
200, not201. - The response of create, read, update, delete and list holds
secretKeyin clear text. Protect it as you protect the secret.
The response webhook object adds id, orgId, an optional sandboxOrgId
and timestamp to the fields above. Each item of the list operation also
carries isLastDeliverySuccess (boolean).
Delete disables the webhook and marks it as deleted. The response holds the webhook in its final state. After the delete, the other webhook endpoints do not find it, and the list operation does not show it.
The delivery envelope your receiver gets
The service sends each event as an HTTP POST to the payload URL. The body
holds 5 fields: deliveryID, webhookID, timestamp, type and data.
type holds 1 of the subscribed event types. data holds the event object;
for an OID4VC event it holds organisationId, an optional sandboxOrgId, and
the credential record or the presentation record.
The service makes 1 delivery attempt for each event. There is no automatic retry.
The HMAC signature
The service signs each real delivery with the X-IGrant-Signature header:
X-IGrant-Signature: t=<timestamp>,sig=<hex>
<hex> is the lowercase hexadecimal HMAC-SHA256 of <timestamp>.<json-payload>
with the secret key. The service always signs the JSON payload, also when
the content type is application/x-www-form-urlencoded. For that content type
the service makes a string of the payload and posts it as a form under the
payload key, so URL decode payload before you check the signature.
Ping (POST …/ping)
A ping sends a POST with an empty body to the payload URL. A ping carries
no X-IGrant-Signature header, so the receiver cannot check its
authenticity. The service does not record a ping as a webhook delivery.
The ping response is a flat object. There is no wrapper field:
{
"responseStatusCode": 200,
"responseStatusStr": "200 OK",
"executionStartTimestamp": "…",
"executionEndTimestamp": "…",
"status": "completed",
"statusDescription": "…"
}
All 6 members are always present. status is completed or failed. The
service answers 200 for a reachable payload URL and for an unreachable one.
Read status to tell the two apart, not the HTTP code.
Deliveries
GET …/deliveries answers with pagination and a webhookDeliveries array.
Each item holds id, webhookId, responseStatusCode, responseStatusStr,
timestamp, status (completed or failed) and statusDescription.
GET …/delivery/{deliveryId} sends the same delivery object as the whole
response body. There is no wrapper field.
The service does not send the request headers, the request payload, the response headers or the response body of a delivery. It keeps them, but no endpoint gives them back. So a delivery record tells you the outcome, not the content.
Event types and content types (the enum sources)
GET /v2/config/webhooks/event-types is the source of truth for the values
you may put in subscribedEvents. It answers with 3 arrays:
consentManagementWebhookEventTypes, digitalWalletWebhookEventTypes and
dataMarketplaceWebhookEventTypes. The list is the same for all
organisations. Read it instead of hard-coding a list.
The OID4VC event types you use most:
openid.credential.offer_sent, openid.credential.offer_received,
openid.credential.credential_issued, openid.credential.credential_acked,
openid.credential.credential_accepted, openid.credential.credential_deleted,
openid.credential.issuance_denied, openid.credential.token_issued,
openid.holder.credential.credential_pending,
openid.holder.credential.credential_acked,
openid.holder.credential.credential_accepted,
openid.presentation.request_sent.v3, openid.presentation.request_received.v3,
openid.presentation.presentation_acked.v3,
openid.presentation.presentation_pending.v3.
GET /v2/config/webhooks/payload/content-types answers with a single array
field. Note the capital C in ContentTypes.
The order of the values in these arrays changes between calls. Do not depend on the order.
Sandbox call style
POST /v2/config/webhook, GET, PUT and DELETE /v2/config/webhook/{webhookId},
GET /v2/config/webhooks and POST /v2/config/webhook/{webhookId}/ping take
the optional X-SandboxOrgId header. With that header the service runs the
operation against the wallet of the named sandbox organisation and not against
the main wallet of the organisation.
The service reads X-SandboxOrgId only when you authenticate with a bearer
access token. With API-key auth the service takes the sandbox organisation
from the key and ignores the header. To run an API-key call in a sandbox
organisation, bind the key with
PUT /v2/config/admin/apikey/{apiKeyId}/sandbox-org instead.
X-SubwalletId is the deprecated name of the header. The service still accepts
it, but X-SandboxOrgId wins if you send both.
The 4 remaining operations - deliveries list, single delivery read, event-types and content-types - take no sandbox header.
See igrantio-api-sandboxes for creating and deploying a sandbox organisation.
Documentation is the source of truth
If this skill and the linked documentation disagree, the documentation wins. Fetch the linked page, or the raw specification at https://docs.igrant.io/openapispecifications/oid4vc.yaml, to check for updates before you build. Report the drift so the skill can be corrected.
Cross-references
igrantio-ows-overview- architecture, glossary, exchange-id correlation.igrantio-backend-webhooks- a runnable receiver with HMAC verification.igrantio-api-sandboxes- sandbox organisations and the API-key binding.