Skip to content
VerifiX — secured by ITSEC

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.

verification.referred
{
  "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

verification.created

A session was created and is waiting on the subject.

verification.started

The subject opened the flow and began capture.

verification.processing

Capture complete, checks are running.

verification.completed

Terminal decision reached, with risk score and reason codes.

verification.referred

A signal requires human review; the case is queued.

verification.declined

A terminal check or rule declined the subject.

verification.abandoned

The subject stopped before finishing.

verification.expired

The session lifetime elapsed without completion.

verification.data_updated

Extracted fields were corrected under review.

verification.deleted

A session and its media were deleted under retention policy.

Screening and monitoring

screening.match_found

A new sanctions, PEP, or adverse-media match on a monitored subject.

screening.match_resolved

An analyst confirmed or discounted a match, with rationale attached.

monitoring.subject_enrolled

A subject entered ongoing screening.

monitoring.subject_removed

A subject left ongoing screening.

Business verification

business.verified

Registry data confirmed and the entity record created.

business.ubo_resolved

Ownership chain resolved to natural persons.

business.ubo_changed

A registry update changed the ownership structure.

business.declined

The entity failed a terminal check.

Transactions and wallets

transaction.evaluated

A transaction was scored, with the rules that fired.

transaction.alert_raised

A rule crossed threshold and created an alert.

wallet.exposure_changed

A monitored wallet's exposure profile changed.

travel_rule.message_received

A counterparty VASP sent originator or beneficiary data.

travel_rule.message_failed

Counterparty exchange could not be completed.

Cases and platform

case.assigned

A case was routed to a reviewer or queue.

case.escalated

A reviewer escalated for second-line approval.

case.closed

A case reached a final outcome with sign-off recorded.

report.ready

An evidence bundle or period report finished generating.

journey.published

A new journey version went live.

Handling

Five rules for a handler that survives production

  1. 1

    Register a destination

    Add an HTTPS endpoint per environment in the console or through the management API, and copy the signing secret.

  2. 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. 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. 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. 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.

signature verification — node
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
Failed deliveries retry with exponential backoff over roughly 24 hours. Persistent failures disable the destination and raise an alert in the console.
Ordering
Events are not guaranteed to arrive in order. Use created_at and the session status you read back from the API, never the arrival order.
Replay
Any event within the retention window can be replayed from the console for a single destination, useful after an outage on your side.
Payload contents
Payloads carry identifiers, statuses, scores, and reason codes. Document images and biometric artifacts are never pushed; fetch them from the evidence endpoint over an authenticated call.
IP allowlisting
Outbound delivery ranges are published for firewall rules — shared on request for your firewall rules.

Test webhooks before you write the handler

Sandbox lets you fire any event above at your endpoint on demand, including failure and replay cases.