Document Verification, AML Screening, and KYC Sessions emit webhook events as processing progresses. Instead of polling, configure a webhook destination and your endpoint will receive a POST request the moment an event fires.
Setting Up Webhooks
In the Developer Console of your Dossiers Dashboard:
- Navigate to the Webhooks section
- Click Create Destination
- Enter a publicly reachable HTTPS URL that accepts
POSTrequests - Select the events you want to subscribe to
- Save — a signing secret is generated automatically
Store the signing secret securely. You'll use it to verify that incoming payloads genuinely come from Dossiers.
Registering from code
A deployment that should register its own endpoint — on every start, without creating duplicates — can call PUT /webhook-destinations with an API key that has the Webhooks permission (WEBHOOKS_MANAGE):
Code
The destination is identified by its url within your organization. The first call creates it; later calls with the same url update its events, name, description, apiVersion and installationId, leaving out nothing you omit. The response always includes the signing secret — generated on create, kept on update — and created: true when the call created the destination. A destination you disable in the Developer Console stays disabled.
With the SDK:
Code
A key without the Webhooks permission gets 403; invalid URLs, event types or API versions get 400.
Payload Format
Every webhook delivery is a POST request with a JSON body:
Code
| Field | Description |
|---|---|
id | Unique event ID |
type | Event type string (e.g. documentVerification.instance.updated) |
organizationId | Your organization ID |
apiVersion | The API version this delivery is shaped for — the destination's |
eventTriggeredAt | ISO 8601 timestamp of when the event was triggered |
data | Event-specific payload (varies by event type) |
Each destination receives deliveries in its own API version (2026-10-01 unless you choose another). Within a version, payloads only gain fields and new event types may appear: ignore fields and event types you don't recognise, and answer unknown event types with a 2xx.
Verifying Signatures
Every delivery includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your destination secret.
Always verify the signature before trusting the payload. Use the raw (unparsed) request body for the HMAC computation — parsing JSON first will break the digest.
Node.js
Code
Python
Code
Delivery Headers
Each delivery includes these headers:
| Header | Description |
|---|---|
X-Webhook-Signature | HMAC-SHA256 hex digest of the payload |
X-Webhook-Event-Type | Event type string (e.g. documentVerification.instance.updated) |
X-Webhook-Event-Id | Unique event ID (same as the id field in the payload) |
X-Webhook-Retry-Count | Number of previous failed delivery attempts (0 on first attempt) |
Dossiers-Api-Version | The API version the payload is shaped for (same as apiVersion in the payload) |
Delivery and Retries
- Your endpoint must return a
2xxresponse within 10 seconds - Failed deliveries (non-2xx or timeout) are retried with exponential back-off starting at 5 seconds, up to 3 total attempts
- Delivery history and per-event logs are available in the Developer Console under Webhook Logs
Event Reference
Document Verification Events
| Event Type | Description |
|---|---|
documentVerification.instance.created | A new processing instance has been created |
documentVerification.instance.updated | The instance status or result has changed (fires after each pipeline stage completes, and again on final completion or failure) |
documentVerification.instance.completed | The instance has completed processing |
documentVerification.instance.deleted | An instance was deleted |
Subscribe to documentVerification.instance.completed to be notified when processing finishes. You can also subscribe to documentVerification.instance.updated and check the status field to track in-progress updates.
Instance Statuses
| Status | Meaning |
|---|---|
pending | Queued, processing has not started |
running | Pipeline is actively executing |
completed | All stages finished successfully |
failed | A document-level issue was detected (wrong document type, unreadable, validation failure) |
error | An internal infrastructure issue prevented processing (timeout, service crash) |
instance.updated Payload
Every updated event includes a stageProgress array that tracks each pipeline stage. This lets you render a progress stepper or determine exactly where processing is at — or where it failed.
Code
| Field | Description |
|---|---|
status | Instance-level status (pending, running, completed, failed, error) |
statusLabel | Short human-readable label describing the current activity or failure (e.g. "Extracting data", "Extraction failed") |
stageProgress | Array of all pipeline stages with their current status (pending, running, success, failed) |
error | Error message when status is failed or error, otherwise null |
On failure, the stageProgress array shows exactly which stage failed:
Code
instance.created Payload
Code
instance.deleted Payload
Code
KYC Session Events
| Event Type | Description |
|---|---|
kycSessions.session.created | A new KYC session was created |
kycSessions.session.updated | The session's status, checkpoint, or progress changed |
kycSessions.session.completed | The customer finished the verification flow |
kycSessions.session.checksCompleted | The post-completion check run finished — the normalized verification object is now final |
kycSessions.session.reviewed | An admin made a review decision (approve/reject) on the session |
kycSessions.session.deleted | A session was deleted |
kycSessions.session.purged | A session's data was destroyed — by your deletion, its ephemeral retention policy, or your organization's data retention window |
kycSessions.step.completed | A workflow step submission completed successfully |
kycSessions.step.failed | A workflow step submission failed |
kycSessions.session.commentAdded | Comment added to a session |
kycSessions.session.commentUpdated | Comment on a session was edited |
kycSessions.session.commentDeleted | Comment removed from a session |
Session event payload
Session lifecycle events (created, updated, completed, reviewed) carry:
Code
session.completed additionally includes outcome, and session.reviewed includes review ({ decision, externalReason, decidedAt }).
Step event payload
step.completed / step.failed carry kycSessionId, stepId, stepType, status, attemptId, processorInstanceId (when the step is backed by document processing), error, startedAt, and completedAt.
checksCompleted payload
kycSessions.session.checksCompleted fires when the relational check run over all collected evidence finishes:
Code
Wait for this event before treating the session's verification.checkRun verdicts as final.
A session can produce multiple runs — evidence arriving late (an async
document pipeline reconciling, a resubmission) triggers a new run whose higher
version supersedes every lower one; always act on the highest version you
have seen. outcome is the outcome the read APIs now report for the session,
checks included. blockingReasons lists the normalized categories of every
blocking failure (empty when nothing blocks), and partial: true means at
least one evaluator could not produce a verdict — those checks read
NOT_EXECUTED and the run re-triggers automatically. Payloads are PII-free,
like every KYC webhook: fetch detail via GET /kyc-sessions/{id}.
session.purged payload
kycSessions.session.purged fires once a session's data has been destroyed —
media, document-pipeline artifacts, exported reports, check runs, comments and
the session row itself. After it, every read of that session returns 404.
Code
trigger says what caused it:
| Trigger | Meaning |
|---|---|
verdict | An ephemeral session reached its final verdict |
review | An ephemeral session that required manual review was decided |
sweep | The periodic sweep caught an ephemeral session its trigger missed |
expired | The session expired without ever completing |
retention | Your organization's data retention window elapsed (see Data retention) |
deleted | You deleted the session through the API or the dashboard |
counts is what was removed, not what remains. The payload is PII-free, like
every KYC webhook — by design there is nothing left to fetch.
AML Screening Events
| Event Type | Description |
|---|---|
amlScreening.screeningRequest.created | New screening request submitted |
amlScreening.screeningRequest.completed | Screening processing finished |
amlScreening.screeningAlert.triggered | New high-risk match found |
amlScreening.screeningAlert.statusChanged | Alert status updated (e.g. confirmed, dismissed) |
amlScreening.screeningAlert.commentAdded | Comment added to an alert |
amlScreening.screeningAlert.commentUpdated | Comment on an alert was edited |
amlScreening.screeningAlert.commentDeleted | Comment removed from an alert |
amlScreening.screeningAlert.deleted | Alert deleted |
System Events
These events fire regardless of which products are enabled:
| Event Type | Description |
|---|---|
system.testEvent | Test event for verifying webhook connectivity |
system.product.accessGranted | A product has been enabled for your organization |
system.product.accessRevoked | A product has been disabled for your organization |
system.apiKey.created | A new API key was created |
system.apiKey.invalidated | An API key was revoked |
system.usage.limitReached | Your organization has hit its credit usage limit |
system.usage.limitWarning | Your organization is approaching its credit usage limit |
Managing Destinations
From the Developer Console you can:
- Update a destination's URL or subscribed events
- Enable/disable a destination without deleting it
- Regenerate the signing secret (rotates the secret; old deliveries will still use the previous secret)
- Send a test event to verify connectivity
- Delete a destination entirely
Best Practices
- Always verify signatures — Never trust a payload without checking the HMAC signature
- Respond quickly — Return a
2xxwithin 10 seconds. If you need to do heavy processing, acknowledge the webhook and handle the work asynchronously - Handle duplicates — Use the event
idto deduplicate, as retries may deliver the same event more than once - Tolerate what's new — Acknowledge event types you don't handle with a
2xx, and ignore payload fields you don't recognise; both are added without a new API version - Use HTTPS — Webhook destinations must use HTTPS to protect payloads in transit
- Monitor delivery logs — Check the Developer Console for failed deliveries and investigate any persistent errors

