Webhooks allow your application to receive real-time notifications about changes to verification sessions, business sessions, users, businesses, activities, and transactions. Here’s how you can configure and handle these notifications securely.Documentation Index
Fetch the complete documentation index at: https://docs.didit.me/llms.txt
Use this file to discover all available pages before exploring further.
Note for Cloudflare Users: If you are using Cloudflare, you must whitelist our IP address to receive webhooks. To whitelist an IP address in Cloudflare, navigate to the “Security” section, then “WAF”, then “Tools” and “IP Access Rules”. Add the IP address
18.203.201.92, select “Allow”, and choose the website the rule applies to.Configuring the Webhook Endpoint
Complete the Quick Start Guide
Refer to the Quick Start Guide to set up your team and application if you haven’t already.

Signature Verification Methods
We provide three signature headers to accommodate different integration scenarios. Choose the method that best fits your infrastructure:| Header | Method | Best For | Middleware-Safe |
|---|---|---|---|
X-Signature | Raw body HMAC | Direct access to raw request bytes | ❌ No |
X-Signature-V2 | ASCII-escaped JSON HMAC | Recommended - Works with most middleware | ✅ Yes |
X-Signature-Simple | Field-based HMAC | Fallback when other methods fail | ✅ Yes |
Why Multiple Signatures?
Some web frameworks and middleware (e.g., Express.js body parsers, Django middleware, API gateways) automatically parse and re-stringify JSON payloads. When special characters like accents (José, Müller, 日本) are present, the re-encoded JSON may differ from the original:
- Original:
"name":"José" - Re-encoded:
"name":"Jos\u00e9"(Unicode escaped)
X-Signature verification to fail even though the data is identical. The X-Signature-V2 and X-Signature-Simple methods solve this problem.
Recommendation
- Try
X-Signature-V2first (recommended) - Works even if your middleware re-encodes the JSON - Fall back to
X-Signature-Simpleif V2 fails - Verifies core fields only - Use
X-Signatureonly if you have direct access to the raw request bytes
Signature Details
X-Signature (Original)
- Signs the exact raw JSON bytes sent in the request body
- Uses Python’s default ASCII-escaped encoding (
José→Jos\u00e9) - Requires access to raw request body before any parsing/re-encoding
- May fail if middleware re-encodes Unicode characters differently
X-Signature-V2 (Recommended)
- Signs unescaped Unicode JSON (
Joséstays asJosé) - Parse the JSON, then re-encode with
sort_keys=Trueand Unicode preserved - Matches what most middleware (Node.js, PHP, etc.) produces when re-stringifying
- This is the recommended method as it survives most middleware re-encoding
X-Signature-Simple (Fallback)
- Signs only core fields:
"{timestamp}:{session_id}:{status}:{webhook_type}" - Completely independent of JSON encoding
- Note: Does not verify integrity of
decisionor other fields
Webhook Event Types
Use these exact event names in a webhook destination’ssubscribed_events array. Didit sends a webhook to a destination only when the payload’s webhook_type matches one of that destination’s subscribed events.
| Event | Resource | When it fires |
|---|---|---|
status.updated | User Verification (KYC) or Business Verification (KYB) session | A session status changes. KYB payloads include session_kind: "business" and business_session_id. |
data.updated | User Verification (KYC) or Business Verification (KYB) session | Session verification data is corrected or updated after creation, such as reviewer edits to KYC, Proof of Address, or KYB data. |
user.status.updated | User entity | A User entity status changes, for example ACTIVE, FLAGGED, or BLOCKED. |
user.data.updated | User entity | A User entity profile, counters, metadata, documents, or aggregate verification fields change. |
business.status.updated | Business entity | A Business entity status changes, for example after manual review, KYB results, or a blocklist action. |
business.data.updated | Business entity | A Business entity profile, counters, metadata, registration fields, or aggregate verification fields change. |
activity.created | Activity timeline | A timeline activity is recorded for a User, Business, external counterparty, session, or transaction. |
transaction.created | Transaction Monitoring | A transaction is created and its initial rule evaluation is complete. |
transaction.status.updated | Transaction Monitoring | A transaction changes status after rules, analyst review, remediation, provider updates, or API/console actions. |
subscribed_events must contain at least one event. There is no wildcard value, so include every event family your endpoint should receive. You can also create multiple destinations if you want to route session, entity, and transaction events to different URLs.
For regular user verification session events, if the session status is Approved, Declined, In Review, or Abandoned, the webhook also includes a decision field containing detailed verification results. The session_id is always included. The vendor_data, workflow_id, and metadata fields are included only if they exist on the session.
For business-session events, the payload includes session_kind: "business" and business_session_id in addition to the generic session_id.
Transaction webhook payloads
Transaction monitoring events use the application-level webhook fan-out and include the transaction identifier in the payload:APPROVED by default. If a matching rule or workflow explicitly changes the status during creation, the initial transaction.created payload reflects that final status.
Use transaction.created when a transaction is first recorded, and transaction.status.updated whenever a rule, analyst action, remediation flow, or blocklist action changes the transaction status after creation.
Retry Policy
If delivering a webhook fails (i.e., your endpoint returns a5xx status code or a 404), we will automatically retry the delivery. To provide you with a clear history of delivery attempts, each retry is logged as a new, separate event in your dashboard.
Retries are performed with an exponential backoff schedule to avoid overwhelming your server. We will attempt to redeliver the webhook up to 2 times over a period of minutes:
- 1st Retry: Approximately 1 minute after the initial failure.
- 2nd Retry: Approximately 4 minutes after the first retry failure.
Code Examples
To ensure the security of your webhook endpoint, verify the authenticity of incoming requests using yourWebhook Secret Key.
Node.js / Express (Recommended: X-Signature-V2)
Node.js / Express (Original: X-Signature with Raw Body)
If you have direct access to the raw request bytes and prefer the original method:Python / FastAPI (Recommended: X-Signature-V2)
Python / FastAPI (Original: X-Signature with Raw Body)
If you have direct access to the raw request bytes:PHP / Laravel (Recommended: X-Signature-V2)
PHP / Laravel (Original: X-Signature with Raw Body)
If you have direct access to the raw request bytes:Webhook Body Object Examples
The webhook payload varies depending on the status of the verification session. When the status isApproved or Declined, the body includes the decision field. For all other statuses, the decision field is not present.
Example without decision Field
Example with decision Field (V3 API Structure)
The V3 API uses plural arrays for each feature type, allowing multiple instances per feature. Each feature object includes a node_id for unique identification.
V3 API Field Name Changes
| V2 Field (singular) | V3 Field (plural array) |
|---|---|
id_verification | id_verifications |
nfc | nfc_verifications |
liveness | liveness_checks |
face_match | face_matches |
poa | poa_verifications |
phone | phone_verifications |
email | email_verifications |
aml | aml_screenings |
ip_analysis | ip_analyses |
database_validation | database_validations |
For a complete list of possible properties and their values for the
decision field, please refer to our API Reference.V2 API Webhooks
Differences from V3
| Feature | V2 | V3 |
|---|---|---|
| Signature header | X-Signature only | X-Signature, X-Signature-V2, X-Signature-Simple |
| Signature method | Raw body HMAC-SHA256 | Multiple methods (see above) |
| Decision field names | Singular objects (id_verification, liveness, face_match, etc.) | Plural arrays (id_verifications, liveness_checks, face_matches, etc.) |
| Multiple feature instances | Not supported | Supported via arrays with node_id |
V2 Signature Verification
V2 webhooks only include theX-Signature header, which is an HMAC-SHA256 of the raw request body.
- Node.js
- Python
V2 Webhook Body Example with Decision
In v2, the decision object uses singular field names (e.g.,id_verification instead of id_verifications):