Skip to main content
Register an HTTPS endpoint and we POST a signed event to it the moment a KYC/KYB or AML event happens — no polling required. Every payload is signed (HMAC-SHA256), carries a unique event id, and is retried with backoff until your endpoint acknowledges it.
Webhooks are configured in Settings → Developers → Webhooks. The signing secret is shown once at creation — store it immediately.

Events

See Event payloads for the envelope and per-event fields. New event types may be added over time — switch on type and ignore any you don’t recognise.

Guarantees

  • HMAC-SHA256 signature on every payload, in the IC-Signature header, over IC-Timestamp + the raw request body. Verify it before trusting a payload — see Verifying signatures.
  • Replay protection. An IC-Event-Id header uniquely identifies each event; the same id on a redelivery means the same event, so you can dedupe. Reject events whose IC-Timestamp is more than 5 minutes old.
  • At-least-once delivery. We retry non-2xx responses with exponential backoff for up to 24 hours. Because delivery is at-least-once, make your handler idempotent (key on IC-Event-Id).
  • Auto-disable. An endpoint that fails continuously is disabled and flagged in the dashboard so a dead URL doesn’t retry forever.

Responding

Return any 2xx status to acknowledge receipt. Respond fast (within a few seconds) — do the real work asynchronously after acknowledging, because we time out slow endpoints and treat a timeout as a failure to retry. Any non-2xx (or a redirect) is treated as a failure.

What we deliberately don’t send

  • No raw AML hit data, document images, or full PII. You receive ids + status — the same safe shape as GET /v1/customers. Fetch the full DTO from the API if you need more.
  • No unsigned mode. Every endpoint must be HTTPS and every payload is signed.
  • No delivery to private or internal hosts — endpoint URLs are validated and re-checked (with DNS resolution) before each send.

Migrating from polling

The payload’s data.customer mirrors the DTO you already parse from polling, so the switch is drop-in: point your existing upsert at the webhook handler and keep polling as a periodic backstop if you like.