Developers — webhooks
Twenty-eight events, one signature scheme, no polling
Every state change in a session, case, screening record, transaction, or Travel Rule exchange is pushed to your endpoint and signed.
{
"id": "evt_01HZYB7QK9",
"type": "verification.referred",
"created_at": "2026-08-25T09:19:44Z",
"livemode": true,
"data": {
"id": "ver_01HZY8QK3M4T",
"subject_reference": "cust_10241",
"journey": "uae_vara_retail_individual",
"status": "referred",
"reason_codes": ["adverse_media_possible_match"],
"risk": { "score": 61, "band": "medium" },
"case_id": "case_01HZYB80AA"
}
}Event catalog
What we send, grouped by surface
Subscribe per event type and per environment. Sandbox events carry livemode false.
Sessions
A session was created and is waiting on the subject.
The subject opened the flow and began capture.
Capture complete, checks are running.
Terminal decision reached, with risk score and reason codes.
A signal requires human review; the case is queued.
A terminal check or rule declined the subject.
The subject stopped before finishing.
The session lifetime elapsed without completion.
Extracted fields were corrected under review.
A session and its media were deleted under retention policy.
Screening and monitoring
A new sanctions, PEP, or adverse-media match on a monitored subject.
An analyst confirmed or discounted a match, with rationale attached.
A subject entered ongoing screening.
A subject left ongoing screening.
Business verification
Registry data confirmed and the entity record created.
Ownership chain resolved to natural persons.
A registry update changed the ownership structure.
The entity failed a terminal check.
Transactions and wallets
A transaction was scored, with the rules that fired.
A rule crossed threshold and created an alert.
A monitored wallet's exposure profile changed.
A counterparty VASP sent originator or beneficiary data.
Counterparty exchange could not be completed.
Cases and platform
A case was routed to a reviewer or queue.
A reviewer escalated for second-line approval.
A case reached a final outcome with sign-off recorded.
An evidence bundle or period report finished generating.
A new journey version went live.
Handling
Five rules for a handler that survives production
- 1
Register a destination
Add an HTTPS endpoint per environment in the console or through the management API, and copy the signing secret.
- 2
Verify before you parse
Compute the HMAC over the raw request body, reject on mismatch or on a timestamp older than five minutes, and only then deserialize.
- 3
Acknowledge fast, work later
Return 2xx within a few seconds and hand the event to a queue. Slow handlers cause retries, not lost events.
- 4
Deduplicate by event id
At-least-once delivery means the same event id can arrive twice. Treat the id as your idempotency key.
- 5
Reconcile on read
Webhooks are a notification, not the source of truth. On receipt, read the session or case back from the API before acting.
import crypto from "node:crypto";
// Reject anything you cannot verify. Compare in constant time.
export function isValidSignature(rawBody: string, header: string, secret: string) {
const [tsPart, sigPart] = header.split(",");
const timestamp = tsPart.replace("t=", "");
const signature = sigPart.replace("v1=", "");
// Reject replays older than five minutes.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}Details
Delivery guarantees
Retries
Ordering
Replay
Payload contents
IP allowlisting
Test webhooks before you write the handler
Sandbox lets you fire any event above at your endpoint on demand, including failure and replay cases.

