Webhooks
19 events, one envelope, a five-step retry schedule, and the endpoint routes — generated from the API's own catalogue.
The events
An endpoint subscribes to any of these 19 event types. GET /v1/developer/applications/{applicationId}/webhooks/events returns the same list from the running API.
Read from the API's webhook event catalogue, schema version 2.0
| Event | Category | Label |
|---|---|---|
sign_in.completed | human | Human signed in |
connection.created | human | Human connected for the first time |
oauth.authorization.completed | human | Human authorization completed |
consent.granted | human | Human consent granted |
consent.revoked | human | Human consent revoked |
identity.assurance.increased | human | Human assurance increased |
identity.assurance.decreased | human | Human assurance decreased |
privacy.correction.applied | human | Human information you hold was corrected |
identity.document.renewed | human | An identity document you hold was renewed |
identity.document.expired | human | An identity document you hold has expired |
identity.document.withdrawn | human | An identity document is no longer shared with you |
identity.document.verification_revoked | human | A document’s verification was revoked |
identity.claim.verification_revoked | human | A verified detail is no longer verified |
identity.claim.verified | human | A detail you hold has been verified again |
billing.budget.threshold_reached | billing | Budget threshold reached |
billing.budget.exhausted | billing | Budget exhausted |
billing.budget.reset | billing | Budget period reset |
billing.budget.action_applied | billing | Budget action applied |
webhook.test | system | Webhook test |
The human events are about a person and your application: a sign-in, a consent, a change to a document or claim you hold. The billing events are about your budget. webhook.test is what the test button sends.
The envelope
Every delivery body
id- The event id. Matches the
unifyid-event-idheader. Deduplicate on it: a retried delivery reuses it. type- One of the event types above.
version2.0- The envelope version.
occurred_at- ISO 8601.
environmentsandboxorproduction. Route sandbox events away from production handlers.application_id- Your application.
actor, subject- Who did it and who it is about, each
{ type, id }with the person named by your pairwisesub. correlation_id- Ties the event to the request that caused it:
correlation_and 43 base64url characters, keyed per application. Deliveries caused by one request share it within your application; another application told about the same request receives a different value. It used to be the same for every application a request reached. data- The event-specific payload. The consent events'
datais on Revocation and webhooks.
Every delivery's headers
unifyid-event-id- The event id.
unifyid-event-type- The event type.
unifyid-timestamp- Unix seconds.
unifyid-signaturet=<timestamp>,v1=<hex>: HMAC-SHA256 over<timestamp>.<raw body>keyed with the endpoint's signing secret. Verification code is on Revocation and webhooks.user-agentUnifyID-Webhooks/1.0.
How a delivery behaves
- Five seconds. A delivery that has not answered in five seconds is a failed attempt. Answer
2xxfirst and do the work afterwards. - Redirects are refused. Point the endpoint at its final URL.
- Five retries, then dead. After a failed attempt the next one waits 1 min, 5 min, 30 min, 2 h, 12 h — about 14.6 h in all — and then the delivery is marked failed.
- Most 4xx responses are permanent. A
4xxfrom you ends the delivery at once, except408,409,425and429, which retry on the schedule like a5xxor a timeout. - Your response body is never read. Only the status matters.
GET …/webhooks/deliveries/history lists deliveries, newest first, with ?endpointId= to narrow to one endpoint. Each carries a state — queued, retrying, delivered, failed or cancelled — its attempt count and one row per attempt with the status you returned, never the body. POST …/webhooks/deliveries/{deliveryId}/retry sends a failed one again.
Endpoints
An application may hold at most 10 endpoints. Creating one is a passkey-confirmed action in the console session.
POST …/webhooks
urlrequired- Up to 2048 characters.
httpsonly in production; a sandbox application outside production may usehttpand a loopback address, so you can test against a local server. The address is resolved and checked against the egress policy before it is kept. eventsrequired- An array of event types from the catalogue.
description- Up to 300 characters.
The answer carries signingSecret once. PATCH …/webhooks/{endpointId} changes url, events, description or status (active or disabled), optionally guarded with configurationVersion so two people editing the same endpoint do not overwrite each other. DELETE …/webhooks/{endpointId} removes it and cancels its pending deliveries.
POST …/webhooks/{endpointId}/rotate-secret returns a new signingSecret; POST …/webhooks/{endpointId}/test sends a webhook.test event — { applicationId, message } — through the real delivery path and answers with the delivery's result and the status you returned. A disabled endpoint refuses the test with WEBHOOK_ENDPOINT_DISABLED.
What this does not do
- Webhooks are not required to go live. No check on the go-live checklist asks for one.
- A delivery is a notification, not the truth. Your authoritative signal that a consent has ended is still the
401the next userinfo call returns. - The `billing` events are about budgets you may not have configured. They exist in the catalogue whether or not you set one.
Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.