KYC Decisions
Emitted when identity verification reaches a new decision, or when a quick KYC binding is compensated after failure.
Event Types
| Event | When Emitted |
|---|---|
kyc.result.updated | Identity verification has a result or requires supplementary documents |
kyc.quick.compensated | A quick KYC binding has been compensated after failure and is no longer an active binding |
Delivery Contract
- We send a
POSTrequest withapplication/jsonto your configured endpoint, with a 10-second timeout. - Any 2xx response acknowledges receipt. Non-2xx responses and timeouts trigger retries with backoff.
- Four request headers:
content-type·z-signature·z-event-id·z-event-type。 - Deduplicate by
z-event-id— the same event may be delivered more than once.
There are no amounts, asset codes, card number fragments or risk-control reasons. This is a security boundary: the webhook endpoint is your service, whose transport and storage we cannot guarantee.
The GET /v1/<resource>/{id} endpoint applies API key, scope and on-behalf-of checks. Fetch details using data.id;
do not use webhook payloads as the source of amounts for your ledger.
Event Details
kyc.result.updated
Identity verification has a result or requires supplementary documentsTwo situations share this event: a review decision (status: updated) and a request for supplementary documents (status: supplement_required). ⚠ Approval and rejection both use status: updated. No field in the event body distinguishes them, a direct consequence of the IDs-and-statuses-only boundary. Retrieve GET /v1/kyc with x-on-behalf-of to learn the result; granting access based on status alone is incorrect. ⚠ data.id is the internal member ID, not a KYC application ID. This is intentional, not a defect: public KYC retrieval uses GET /v1/kyc + x-on-behalf-of, looks up a person, and has no KYC application ID parameter. L1 / L2 also use separate tables, with multiple rows per person. L1 and L2 do not have separate events; inspect the returned level when retrieving. ⚠ status_version is always 0, and the event can recur many times: L1 approval, L2 supplementary documents, L2 approval, resubmission after rejection, and so on. Order by created_at and retrieve once for every event: the event itself does not contain the decision.
{
"event_id": "evt_1a55e9c73b0d47f2ab6c8d19e4f05237",
"event_type": "kyc.result.updated",
"created_at": "2026-08-12T11:15:40Z",
"merchant_id": "acme",
"livemode": true,
"data": {
"object": "kyc",
"id": "4b7c1e02-9a3d-4f18-8c55-2d61ab0f9e77",
"external_member_id": "u_88123",
"status": "updated",
"status_version": 0
}
}kyc.quick.compensated
A quick KYC binding has been compensated after failure and is no longer an active bindingTwo situations share this event: an operator confirms failure compensation manually, or the first upstream application reaches terminal failure and compensation is applied automatically. By the time you receive it, the quick KYC binding has already moved from “currently active” to compensated: the data fee has been refunded, the binding no longer participates in subsequent card applications, and the underlying profile has returned to the pool for future reuse. data.id is the quick KYC binding ID and can remain your audit key. To see which quick KYC bindings are still active for the member, retrieve GET /v1/kyc/quick with x-on-behalf-of. That endpoint returns only bindings that are still active, so the ID in this event will typically no longer appear in the list. compensation_source indicates how compensation was triggered: admin for an operations-confirmed manual compensation, and auto for automatic compensation after the first upstream terminal failure. application_id is returned only when this compensation is tied to a card application. It uses the public application ID with the cap_ prefix, so you can correlate it directly with the original application.
{
"event_id": "evt_ad41781d3e763829951e2ce3ebf9ea46",
"event_type": "kyc.quick.compensated",
"created_at": "2026-09-30T16:21:00.157Z",
"merchant_id": "acme",
"livemode": true,
"data": {
"object": "quick_kyc_binding",
"id": "bcce5b6a-e48b-4527-9738-a12957084f92",
"external_member_id": "u_88123",
"status": "compensated",
"status_version": 1790785259185,
"compensation_source": "admin",
"application_id": "cap_e27e3409-4abb-4b52-8c45-9bc5729cf17f"
}
}Signature Verification
The signature verification procedure is the same for all events. See Webhook Overview; use the Signature Debugger to compare signing strings character by character.