Webhooks
A webhook lets the API push events to your systems as they happen, so you do not have to poll for every change. You register a webhook endpoint, choose which events it should receive, and the API POSTs a small JSON message to that endpoint whenever a matching event occurs. This is the natural way to learn that a case has finished building, that a new AML match has appeared during ongoing monitoring, or that a document has been uploaded. For the concepts and the full contract, see the Guide and the API Reference.
Webhooks complement polling rather than replace it. Polling is still the simplest way to wait for a single case to become ready in a short-lived script (see Poll until ready); webhooks are the better fit when you run at scale, monitor many cases over time, or want events delivered without a polling loop.
The sandbox delivers real webhooks against the same contract as production, so you can build and verify your receiver end to end before you go live. The only difference is timing (see Delivery, retries, and failure).
The events
There are ten event types. Each webhook message names the event in its eventType field, and you subscribe a URL to whichever events you care about.
| eventType | Fires when | Notable extra fields |
|---|---|---|
CaseCreated | A new case is created. | |
CaseReady | A case finishes building and is ready to read. | |
CaseClosed | A case is closed with a decision. | caseDecision |
CaseReopened | A previously closed case is reopened. | |
CaseAssigned | A user is assigned to a case. | assignedUser, caseStatus |
AmlMatch | An AML match is found, including new matches raised during ongoing monitoring. | amlType |
IdFailure | Identity verification fails for a subject on the case. | |
DocumentUploaded | A document is uploaded to a case. | documentName, documentId |
DocumentsRequested | A document request is sent for a case. | request details |
CaseRequestSubmitted | An upload-portal journey is completed by the end user. | email, phone, uploadPortalLink, accessCode |
Three events (IdFailure, DocumentsRequested, and CaseRequestSubmitted) ride on flows that the sandbox only partially simulates. The sandbox fires these events with a representative payload so you can wire up and test your handler, but the surrounding journey is thinner than in production. Build your handler against the event and its payload; do not assume the sandbox reproduces every step of the underlying flow.
Payload
Every delivery is an HTTP POST with a JSON body of two top-level keys: the eventType and a body object.
{
"eventType": "CaseReady",
"body": {
"caseType": 1,
"caseCommonId": "CR-P-2481",
"caseName": "Cropwell Bishop Creamery Limited",
"caseUrl": "https://workspace.knowyourcustomer.dev/cases/CR-P-2481",
"message": "The case has finished building and is ready to read.",
"caseProperties": {}
}
}
The body is a reference to the case, not a full copy of it. It tells you what happened and to which case; you then call the API (or open the caseUrl) to read the full, current data. Common fields you can rely on:
caseTypeis1for a company or entity and2for an individual.caseCommonIdis the case identifier. Treat it as a string: it may be a plain number or a prefixed common id such asCR-P-2481.caseName,caseUrl, and a human-readablemessage.casePropertiesis an object of any custom properties on the case, and can be empty.- Event-specific extras as listed in the table above.
Field naming is not perfectly uniform across events: some events use camelCase, a few use PascalCase, and one event sends caseType as a string rather than a number. This mirrors production behaviour faithfully. Parse each event on its own terms and read fields defensively rather than assuming one fixed schema for all ten.
Registering a webhook
Each environment sends to a single webhook endpoint. In a regular Know Your Customer environment you set it in the admin console under Admin > Integrations (your environment URL followed by /app/Admin/Integrations): enter the URL that should receive events, and save. The sandbox additionally lets you manage the webhook from the Workspace or over its API, described below, so you can script your test setup.
Registering multiple webhook URLs on a single environment is not supported. If you need events delivered to several destinations (for example one per country or business unit), use a separate environment, each with its own API key and its own webhook URL, rather than fanning one environment out to many endpoints. That keeps each destination cleanly isolated and avoids leaking one destination’s case identifiers to the others.
In the Workspace (sandbox)
Open workspace.knowyourcustomer.dev, connect with your sandbox credentials, and go to Webhooks. Set your webhook URL, tick the events you want, and save. The same screen shows the delivery log (see Inspecting deliveries).
Over the API (sandbox)
Create a subscription by POSTing a URL and the list of events to /sandbox/webhooks/subscriptions with your bearer token. The request body uses event_types; each must be one of the ten names above.
curl -X POST https://api.knowyourcustomer.dev/sandbox/webhooks/subscriptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-endpoint.example.com/kyc-webhook",
"event_types": ["CaseReady", "AmlMatch", "CaseClosed"],
"active": true
}'
The response returns the created subscription, including its id and the eventTypes it is subscribed to. List with GET /sandbox/webhooks/subscriptions, update with PATCH /sandbox/webhooks/subscriptions/{id} (change the URL, the events, or set active to false to pause it), and remove with DELETE /sandbox/webhooks/subscriptions/{id}. Subscriptions belong to your tenant and are cleared when you reset the tenant, so a clean test run starts from an empty slate.
Delivery, retries, and failure
Each event is delivered as a JSON POST to your URL. Your endpoint should respond with any 2xx status to acknowledge receipt; the body of your response is ignored. If your endpoint returns a non-2xx status or cannot be reached, the delivery is retried.
- Retries: a failing delivery is retried up to ten times, with a growing backoff between attempts.
- Blocking: if all ten attempts fail, that URL is blocked for one hour to protect the delivery pipeline. Events that occur during the blocking window are dropped rather than queued, and delivery resumes for new events once the hour has passed.
- Acknowledge fast: respond
2xxas soon as you have safely received the message, then do your processing asynchronously. Do not hold the connection open for long-running work.
In production, webhooks fire immediately when the event occurs. The sandbox approximates this on a short cycle, so a sandbox delivery lands within about a minute of the event rather than instantly. This is an accepted evaluation-environment simplification, not a defect. Design your receiver to be driven by the event arriving, not by a precise arrival time.
Security
In the sandbox, deliveries are sent without an authentication header or signature, matching the standard product. Treat your webhook URL as a secret: use an https endpoint, keep the URL private, and do not encode anything sensitive in it. If you want to correlate a delivery to a case, use the caseCommonId in the payload and confirm against the API.
Production deployments with stricter requirements can arrange additional secured delivery (for example signed or encrypted payloads) as part of commercial onboarding. That is not part of the free sandbox.
Inspecting deliveries
Every attempt is recorded so you can debug your receiver without guesswork, which is something the raw production pipeline does not expose to you. The Workspace Webhooks screen shows each delivery with its event type, the exact JSON that was sent, the HTTP status your endpoint returned, and whether it was delivered, is retrying, is blocked, or was dropped. You can filter by subscription or by case.
The same log is available over the API at GET /sandbox/webhooks/deliveries, with optional subscription_id and case_common_id filters. Use it while you are wiring up a handler to confirm exactly what you received and, when something fails, to see why.
Try it in the sandbox
The quickest way to see webhooks working end to end:
- Stand up a receiver. For a quick test, a throwaway endpoint from a request-inspection service (for example webhook.site or a small local server behind a tunnel) is enough to see the payloads arrive.
- Register it for
CaseCreatedandCaseReady, either in the Workspace or with the curl above. - Create a case (see the Quickstart). You should receive
CaseCreatedshortly after, thenCaseReadyonce the case finishes building. Note thatCaseReadyarrives even if you never poll the case yourself. - Check your receiver, and cross-check the delivery log in the Workspace or at
/sandbox/webhooks/deliveries.
Build and test your webhook handler for free in the sandbox, then request access for commercial onboarding when you are ready for real customers. Questions: help@knowyourcustomer.com.
