Identity Platform · Webhooks
For the verification semantics (signing, retry, idempotency) see Webhooks (global) →. This page lists the events specific to Identity Platform.
Event catalog
| Event | When it fires | Payload data shape |
|---|---|---|
verification.created | Any new verification persisted (KTP, face, Dukcapil, NIK format, step-up) | { verificationId, customerId, method, status, score } |
customer.kyc_updated | KYC tier changed (up or down) | { customerId, kycLevel, kycLastVerifiedAt, kycExpiresAt } |
review.overridden | Analyst overrode a verification verdict from the dashboard | { verificationId, customerId, actorUserId, fromStatus, toStatus, reason } |
webhook.test | You clicked "Send test" or hit POST /webhooks/{id}/test | { source: "test" } |
Signature
Identity Platform currently signs with the X-Identity-Signature header (product-prefixed, legacy). It will migrate to X-Quantum-Signature in the next minor release; the old header will continue working for at least 12 months.
X-Identity-Signature: sha256=8b2c4d7e...
X-Identity-Delivery: whd_01HXY...
X-Identity-Event: verification.created
X-Sibling-Service: identityThe X-Sibling-Service header is set when the delivery is triggered by another Quantum Elixir product (e.g. Orchestration). Lets your receiver distinguish "real customer event" from "orchestrated event".
Example payloads
verification.created
{
"id": "evt_01HXY...",
"event": "verification.created",
"occurredAt": "2026-05-24T08:15:12.481Z",
"orgId": "org_01HXY...",
"data": {
"verificationId": "ver_01HXY...",
"customerId": "cus_01HXY...",
"method": "ktp_capture",
"status": "verified",
"score": 87
}
}customer.kyc_updated
{
"id": "evt_01HXZ...",
"event": "customer.kyc_updated",
"occurredAt": "2026-05-24T08:17:58.491Z",
"orgId": "org_01HXY...",
"data": {
"customerId": "cus_01HXY...",
"kycLevel": "premium",
"kycLastVerifiedAt": "2026-05-24T08:17:58.491Z",
"kycExpiresAt": "2027-05-24T08:17:58.491Z"
}
}review.overridden
{
"id": "evt_01HXA...",
"event": "review.overridden",
"occurredAt": "2026-05-24T11:42:08.122Z",
"orgId": "org_01HXY...",
"data": {
"verificationId": "ver_01HXY...",
"customerId": "cus_01HXY...",
"actorUserId": "usr_01HXY...",
"fromStatus": "requires_review",
"toStatus": "verified",
"reason": "Glare on hologram but all OCR fields self-consistent. Approved per supervisor."
}
}Register a subscription
/api/identity/webhooks{
"url": "https://your-app.example.com/webhooks/quantum-identity",
"events": ["verification.created", "customer.kyc_updated"],
"installedBy": "kyc-service@v0.1.0"
}Response includes the signing secret exactly once:
{
"id": "whk_01HXY...",
"url": "...",
"events": [...],
"secret": "qe_whsec_a8f3c92e...",
"active": true,
"createdAt": "..."
}List + manage
GET /api/identity/webhooks
PATCH /api/identity/webhooks/{id}
DELETE /api/identity/webhooks/{id}
POST /api/identity/webhooks/{id}/testGET includes per-subscription delivery health:
{
"rows": [{
"id": "whk_01HXY...",
"url": "...",
"events": ["verification.created"],
"active": true,
"deliveryCount": 1287,
"lastDelivery": {
"status": "sent",
"responseCode": 200,
"at": "2026-05-24T11:42:18.122Z"
}
}]
}Subscribe narrowly
You almost never want all events on one URL. Subscribe each receiver to only the events it actually handles — easier to reason about, easier to scale independently, and a per-receiver outage doesn't cause backpressure on unrelated traffic.