KYC Decisions
Emitted when identity verification reaches a new decision: approved, rejected or additional information required.
Event Types
| Event | When Emitted |
|---|---|
kyc.result.updated | Identity verification has a result or requires supplementary documents |
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
}
}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.