Skip to main content

Receiving Webhooks

This page defines the HTTP delivery contract and the two top-level payload shapes. Step-specific fields are documented separately in Webhook Payload.

Delivery contract

PropertyValue
MethodPOST
Content typeapplication/json
Signature headerX-Signature when a webhook secret is configured
Successful acknowledgement200 OK
Delivery attemptsUp to four total attempts when delivery fails

Your endpoint should:

  1. Capture the unmodified request body.
  2. Verify X-Signature before trusting the body.
  3. Parse the JSON only after verification.
  4. Store or enqueue the event using idempotent application logic.
  5. Return 200 OK promptly.

See Webhook Signature for the exact HMAC input and header format.

Standard result envelope

Verification-result webhooks use this envelope:

{
"resultId": "936f35a8-4921-430e-b016-15be48968886",
"event": "COMPLETED",
"data": {
"dv": {
"id": "d65fa9a0-596e-4d7e-afd1-59a23bfb5a74",
"status": "PASSED"
}
},
"custom": {},
"flowStatus": "COMPLETED"
}
FieldMeaning
resultIdIdentifier of the overall flow result.
eventThe event for this delivery. Common verification values include COMPLETED, FAILED, REVIEW, and REJECTED. AML updates use PRODUCED, REFRESHED, or MODERATED.
dataThe typed result object. The primary key identifies the result type.
customFlow-level custom data used to reconcile the result with your system.
flowStatusCurrent status of the overall flow, which may differ from the individual step status.

The primary data keys are dv, poa, form, spid, phone, wallet, kyb, aml, and geolocation. Extended DV webhooks also include additionalData; organizations using legacy compatibility may also receive kyc beside dv.

Notification envelope

Lifecycle notifications have a different shape. They use top-level eventData and intentionally omit data and flowStatus:

{
"resultId": "936f35a8-4921-430e-b016-15be48968886",
"event": "NOTIFICATION",
"eventData": {
"version": 0,
"type": "DOCUMENT_EXPIRED",
"flowResultId": "936f35a8-4921-430e-b016-15be48968886"
},
"custom": {}
}

Route notifications by eventData.type. Current notification types are:

  • DOCUMENT_EXPIRED
  • KYC_RESULT_EXPIRED
  • FLOW_RISK_REEVALUATED

Their fields are listed under Notification Events.

Dispatching events

Use the envelope before inspecting step-specific fields:

if (payload.event === 'NOTIFICATION') {
handleNotification(payload.eventData.type, payload.eventData)
} else if (payload.data.aml) {
handleAmlUpdate(payload.event, payload.data.aml)
} else {
const resultTypes = ['dv', 'poa', 'form', 'spid', 'phone', 'wallet', 'kyb', 'geolocation']
const resultType = resultTypes.find((key) => payload.data[key] != null)
handleVerificationResult(resultType, payload)
}

Do not assume that resultId uniquely identifies one delivery: a flow can produce multiple step results and later updates. Choose an idempotency key that includes the result type and its result identifier or update kind.