Webhooks deliver real-time event notifications to your server when things happen in Verifa — sessions complete, screening finds matches, identities update, and more. This guide covers setup, security, event filtering, and best practices.
Store the secret securely — you need it to verify webhook signatures. The
whsec_* value is shown once at creation and again only when you rotate
it. You cannot retrieve it later. Each endpoint has its own per-endpoint
secret, so rotating one endpoint never affects another.
Per-endpoint signing secrets are mandatory for endpoints created on or after
2026-04-17. Endpoints created before that date may still fall back to the
deprecated org-level webhook secret; rotate those endpoints to mint a
dedicated whsec_* and stop relying on the org-wide value.
The X-Verifa-Signature header uses the Stripe-style format
t=<unix_ts>,v1=<hex_hmac>. The HMAC-SHA256 covers f"{t}.{raw_body}" and
receivers should reject any delivery whose t= is more than 5 minutes from
current time (replay protection). See the
Tutorial: Receiving Webhooks & Validating Signatures
for full code samples and a reference recipe.
Send a test event to verify your endpoint is working:
Subscribe to specific events or use "*" to receive all events:
All webhook payloads follow this structure:
The data object contents vary by event type. Session events include
session_id, external_ref, and status. Identity events include
identity_id and the changed fields.
Every webhook includes an X-Verifa-Signature header in the Stripe-style
format t=<unix_ts>,v1=<hex_hmac>:
t — Unix timestamp the signature was generated atv1 — hex-encoded HMAC-SHA256 of f"{t}.{raw_request_body}", signed with
your endpoint’s whsec_* secretAlways verify signatures to prevent spoofed events. Use the raw request
body bytes (not parsed JSON) for verification, use a constant-time comparison
function for the v1 value, and reject deliveries whose t= is more than
5 minutes from your current clock to prevent replay attacks. See the
Tutorial: Receiving Webhooks & Validating Signatures
for the full reference recipe and language-specific examples.
The verification helper at src/core/security.py:verify_webhook_signature
also accepts the legacy bare-hex HMAC over the raw body for in-flight
deliveries during the deprecation window. New outbound deliveries always use
the timestamped t=,v1= format, so build new receivers against that format.
Receivers should layer the following defenses:
t=,v1= recipe above — reject anything
that doesn’t validate.abs(now - t) > 300, drop the delivery
even if the HMAC checks out. This is the same 5-minute window enforced
by every Verifa client.idempotency_key. Verifa retries failed deliveries, and the
same event may arrive more than once with the same idempotency_key in
the payload body. Maintain a short-lived cache (Redis, DB row) keyed on
idempotency_key to skip duplicates rather than hashing payloads.If your endpoint returns a non-2xx status or doesn’t respond within 30 seconds, Verifa retries with exponential backoff:
After 5 failed retries, the delivery is marked as failed.
If an endpoint accumulates 10 consecutive failed deliveries (all retries exhausted), Verifa automatically disables the endpoint and sends an email notification to your organization’s admins. Re-enable it in the dashboard or via API after fixing the issue.
Returns the new whsec_* secret in the response body. This is the only other
time the secret is shown — store it immediately. The previous secret is
invalidated as soon as rotation completes, so deploy the new value to your
server before or immediately after rotating. Rotating one endpoint never
affects another endpoint’s secret.
Duplicate an endpoint with a new secret (useful for migration):
Control the casing of payload keys per endpoint:
Options: snake (default), camel, kebab.
Respond quickly. Return 200 immediately and process the event
asynchronously. If your handler takes too long, the delivery may time out and
trigger unnecessary retries.
Handle duplicates. Use the idempotency_key field on the payload body
to deduplicate — the same key arrives on every retry of the same delivery.
In rare cases (network issues, retries), you may receive the same event
more than once.
Verify signatures and timestamps. Parse t= and v1= from the
X-Verifa-Signature header, recompute the HMAC over f"{t}.{raw_body}",
and reject any delivery whose t= is more than 5 minutes from now. Never
process unverified events.
Exempt from CSRF. If your framework has CSRF protection, exempt your webhook endpoint path.
Use specific events. Subscribe only to the events you need rather than
"*". This reduces noise and makes your handler simpler.
Monitor delivery health. Check the delivery history in the dashboard regularly. If you see frequent failures, investigate timeouts or errors on your endpoint.