Webhooks let your backend react to things that happen inside your IntelliAuth tenant — without polling. The tenant emits an event (a user signed in, an MFA factor was enrolled, an application was created); the platform sends an HTTP POST to your registered receiver URL with the event payload; your backend processes it.
The shape is standard:
POST https://api.banking.cymmetri.com/webhooks/intelliauth HTTP/1.1
Content-Type: application/json
X-IntelliAuth-Event-Id: evt_01HZX...
X-IntelliAuth-Event-Type: user.signed_in
X-IntelliAuth-Signature: <HMAC-SHA256>
X-IntelliAuth-Timestamp: 2026-05-17T12:34:56Z
X-IntelliAuth-Delivery-Attempt: 1
{
"id": "evt_01HZX...",
"type": "user.signed_in",
"created": "2026-05-17T12:34:56Z",
"tenant_id": "tnt_01HZX...",
"data": {
"user_id": "usr_01HZX...",
"session_id": "ses_01HZX...",
"auth_level": "AAL2",
"connection": "google-oauth2"
}
}
What you get + what you guarantee
What the platform gives you:
At-least-once delivery. The platform retries failed deliveries with exponential backoff up to a budget (typically 24 hours).
HMAC signature. Every delivery is signed with a shared secret; your receiver verifies the signature before trusting the payload. See Verify webhook signatures.
Anti-replay window. Each delivery carries a timestamp; replays older than 5 minutes are flagged. Combined with idempotency keys, replay attacks are defeated.
Ordered per resource (best effort). The platform tries to deliver events about the same resource in order; cross-resource ordering isn't guaranteed.
SSRF protection. The platform won't deliver to internal-network or loopback addresses. Your receiver must be on the public internet.
What you're expected to guarantee:
Idempotent receivers. Same event id might arrive twice (network blip, your 200 not received). Track event ids; ignore duplicates.
Fast 2xx responses. Return 200 within 30 seconds. Do any heavy work asynchronously (push to a queue, return 200 immediately).
Signature verification. Reject deliveries with invalid signatures. The signature is your only proof that the event is real.
Stable receiver URL. If you change it, register the new URL in the tenant admin console; the platform doesn't auto-discover.
Event types
The platform emits events for every meaningful state change. A non-exhaustive list:
user.created,user.updated,user.deleteduser.signed_in,user.signed_outuser.mfa_enrolled,user.mfa_removed,user.mfa_challengeduser.password_changed,user.password_reset_requestedsession.created,session.revoked,session.expiredapplication.created,application.updated,application.deletedapplication.secret_rotatedapplication.scope_added,application.scope_removedrisk.threshold_triggered,risk.feed_hitaudit.compliance_export_requested
See Event reference for the full catalogue with payload shapes.
When to use webhooks vs pipelines
Pipelines run during an event and can change its outcome (deny a sign-in, add claims to the token).
Webhooks fire after an event has happened and can react but not change it.
If you want to deny a sign-in based on your business logic, that's an Action inside a pipeline. If you want to record the sign-in in your CRM, that's a webhook.
The two compose nicely: a pipeline emits the event, the webhook fans it out to your downstream systems.
When NOT to use webhooks
Two anti-patterns:
As an audit log replacement. The IntelliAuth audit log is the source of truth for who-did-what. Webhooks are a delivery channel, not a record. If your webhook receiver loses an event, the audit log still has it.
For real-time, low-latency reactions. Webhooks are eventually-consistent (best-effort within seconds). If you need synchronous "react during the sign-in", that's a pipeline Action, not a webhook.
Local development
For testing webhooks against a localhost receiver, use a tunnel:
# Using ngrok
ngrok http 3000
# → register the ngrok URL as your webhook receiver in the tenant admin
Or use the platform's webhook-replay feature (when available) — the admin console can re-deliver a recent event to a different URL for testing.