Practical guide
Sanctions monitoring webhooks: verify, store, and process events
Build a webhook receiver that checks signatures, handles duplicate deliveries, retrieves current evidence, and keeps human review separate.

On this page
Register the receiver and save the one-time secret
SanctionsKit webhooks tell your server that a monitoring event needs processing. First set up a retained monitor with the monitoring guide. Delivery supplements the inbox. It does not prove a match, a completed screening or a finished review.
Register a public HTTPS receiver under Webhooks in the dashboard, or use POST /api/v1/webhooks with webhooks:write and a body containing only url. Creation returns the endpoint ID and secret once. Store it securely; GET /api/v1/webhooks does not return it. Use the complete receiver sample for implementation.
Verify the signature before trusting the JSON
Keep the original request body bytes. Verify them with the configured secret before parsing or acting. SanctionsKit signs the event ID, timestamp and raw body together. The headers are `Webhook-Id`, `Webhook-Timestamp` and `Webhook-Signature`. Use the documented time tolerance and constant-time signature comparison.
Parsing JSON and writing it back out may change the signed bytes. Reject missing, malformed, stale or invalid signatures. Do not continue with a partly trusted payload simply because some of its fields look familiar.
Check time and store the event before acknowledging delivery
The signed timestamp uses Unix seconds. Reject a value more than 300 seconds from your server clock in either direction. Use the literal secret string as the signing key, not a Base64-decoded form. Trust the JSON only after checking the original bytes.
Save the verified event ID and minimal processing state in durable storage before acknowledging receipt. Enforce a unique event ID to avoid duplicate work. If a worker then fails, retry from that saved inbox. Work held only in memory can vanish after a successful delivery response.
Retrieve the event and current evidence
With a server-side results:read key, call GET /api/v1/monitoring/inbox/{id} using the documented event reference. Read monitorId, kind, screeningId, previousScreeningId, caseId and changes. A failed-screening event may have null result references because no new result exists.
Read referenced checks with GET /api/v1/results/{id} and the current case with GET /api/v1/investigations/{caseId}. Check status and evidence availability. An expired baseline is not an empty-match success. A delayed event must not overwrite newer state just because it arrived last.
Route review work and reconcile the full inbox
Send safe references and the next task to your authorized workflow. Reviewers inspect Monitoring and the linked case to compare changed facts, record decisions and finish approval. Keep full customer details and documents out of notification payloads and routine logs.
API keys can read GET /api/v1/monitoring/inbox with status, kind, monitorId, limit and cursor. Follow nextCursor through all pages. They cannot acknowledge human review. Dashboard acknowledgement clears unread state without closing the linked case.
Test delivery and worker recovery separately
Test invalid signatures, stale time, duplicate delivery, a restart after storage, delayed events, unavailable downstream services and expired results. None should approve a customer or fabricate no_match. Keep delivery state visible separately from investigation state.
Use documented delivery retries for a failed webhook request and your durable worker's retries for processing failures. Periodically compare your inbox with current product events and monitor health. The operations guide explains that check even when webhook delivery looks healthy.
Sources and references
SanctionsKit documentation
Frequently asked questions
Why must signature verification use the raw webhook body?
The signature covers the original bytes along with the event ID and timestamp. Parsing and reserializing JSON can change those bytes. Verify the raw request first, using the literal secret string and documented comparison method.
What timestamp tolerance should the receiver enforce?
Reject signed Unix timestamps more than 300 seconds from your server clock in either direction. Check clock accuracy and apply the signature contract from the webhook documentation. A valid-looking event body does not excuse a stale timestamp.
When should my receiver acknowledge successful delivery?
After verifying the request and durably storing its event ID and minimal processing state. Then downstream work can recover from a worker failure. Enforce unique IDs so a repeated delivery does not create duplicate actions.
Does a successful webhook response mean the case is reviewed?
No. It shows that the delivery was accepted by your receiver. Processing, evidence retrieval and human review are separate steps. Read the current case and retain its own completion state.