Webhooks
Webhooks deliver real-time notifications to your system when verification events occur. Instead of polling for results, configure a webhook endpoint and Zenoo will POST event payloads as they happen.Events
| Event | Trigger | Typical Action |
|---|---|---|
verification.completed | Person/Company Verification journey finishes with results | Process results, update customer record |
screening.completed | PEP/sanctions screening finishes | Review matches, update risk profile |
journey.abandoned | User closes the verification UI without finishing | Send reminder, create new journey |
journey.expired | Verification URL expires (24h default) | Generate new journey, notify user |
check.failed | A check fails after all retries are exhausted | Alert compliance team, investigate manually |
Setup
Provide your endpoint URL
During onboarding, give Zenoo the HTTPS URL where you want to receive events:
Receive your webhook secret
Zenoo generates an HMAC secret for signature verification. Store it securely (environment variable, secrets manager).
Implement signature verification
Every webhook includes an
X-Zenoo-Signature header. Verify it before processing any payload:server.js
Payload Structure
All webhook events share this envelope:| Field | Description |
|---|---|
event_type | The event name (e.g., verification.completed) |
timestamp | ISO 8601 timestamp of when the event occurred |
journey_id | Unique identifier for the verification journey |
callback_reference | The external_reference you provided when initiating the verification |
status | Current journey status |
data | Event-specific payload (varies by event type) |
callback_reference echoes back the value you set when initiating the verification. Use it to correlate webhook events with records in your system.
Event Payloads
verification.completed
Fires when a Person or Company Verification journey completes. Thedata field contains the full verification results, identical to the pull endpoint response.
screening.completed
Fires when standalone screening completes.journey.abandoned
Fires when a user closes the verification UI or navigates away without completing it.journey.expired
Fires when the 24-hour verification URL expires before the user completes the flow.check.failed
Fires when a check fails after all automatic retry attempts are exhausted. This is a terminal state.Retry Logic
If your endpoint does not return200-299 within 30 seconds, Zenoo retries with increasing delays:
| Attempt | Delay After Failure |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 1 hour |
| 5th through 168th | Every 1 hour for 7 days |
Idempotency
Your webhook handler must be idempotent. Zenoo may deliver the same event more than once in edge cases (network timeouts, retry storms).server.js
200 for duplicate events. Returning an error causes unnecessary retries.
Error Handling
How Zenoo responds to your endpoint’s status codes:| Your Response | Zenoo Behavior |
|---|---|
200-299 | Delivery confirmed, no retry |
3xx | Follows redirect (up to 3 hops) |
400-499 | Retries with backoff (may be transient) |
500-599 | Retries with backoff |
| Timeout (>30s) | Retries with backoff |
| Connection refused | Retries with backoff |
Testing
Staging Webhooks
Configure your staging webhook endpoint during onboarding. All verification flows in the staging environment trigger the same webhook events as production, using mock provider data.Local Development
Use a tunneling tool to expose your local server:Webhook Replay
Contact Zenoo support to replay specific webhook events. This is useful for:- Debugging payload parsing issues
- Testing idempotency handling
- Recovering from endpoint downtime
Security Checklist
- Verify
X-Zenoo-Signatureon every incoming webhook - Use HTTPS for your webhook endpoint (no plain HTTP)
- Respond with
200within 30 seconds - Handle duplicate deliveries (idempotent processing)
- Log failed signature verifications as security events
- Process event payloads asynchronously (queue + worker)
- Allowlist Zenoo IP ranges in production firewalls
Signature Verification
Zenoo signs all outbound webhook payloads using HMAC-SHA256. Every webhook request includes a signature in theX-Zenoo-Signature header. Verify this signature before processing the payload.
Signature format
sha256= prefix followed by the hex-encoded HMAC-SHA256 digest of the raw request body, computed with your webhook secret.
Verification steps
Code examples
Constant-time comparison
| Language | Function |
|---|---|
| Node.js | crypto.timingSafeEqual() |
| Python | hmac.compare_digest() |
| Java | MessageDigest.isEqual() |
| Go | hmac.Equal() |
| Ruby | Rack::Utils.secure_compare() |
JWT-encoded webhooks
Some webhook configurations deliver payloads as JWT tokens instead of raw JSON. Zenoo auto-detects the format:
- If the request body starts with
eyJand contains exactly 3 dot-separated segments, it is treated as a JWT. - The JWT payload is decoded and verified against your webhook secret.
- Your verification logic does not need to change. Zenoo handles the decoding transparently.
Handling verification failures
Next Steps
Error Handling
Handle API failures and retries
Result Delivery
Compare push, pull, and ping+pull models
Idempotency
Prevent duplicate verifications
Testing & Sandbox
Test webhook delivery in staging