A practical guide to consuming KYC and fraud webhooks on a marketplace: signatures, retries, idempotency and mapping decisions to seller states.
Getting a verification result back is easy. Doing the right thing with it, every time, across thousands of sellers, is where marketplace integrations get messy. A webhook arrives twice. Another never arrives. A seller sits in "review" for a week because nobody knew the queue existed.
This post is about the receiving end: how to accept webhooks safely, how to make your handler survive retries and outages, and how to turn a decision into a seller state your platform can act on.
Start with the boring part, because it causes real failures. A webhook subscription only works if the event names match exactly what the sender emits. There are no wildcards.
TrustVerify emits these events today:
| Event | When it fires |
|---|---|
verification.completed | A KYC verification was approved |
fraud.score.generated | A fraud score was produced for a transaction |
aml.hit | A monitored subject matched a sanctions, PEP or adverse-media entry they had not matched before |
aml.monitor.suspended | Re-screening stopped because the plan no longer covers the monitored subjects |
arbitration.resolved | An arbitration case reached a decision |
If you try to subscribe to a name that is not on the list, the API refuses the request and tells you which names are valid, rather than quietly creating a subscription that never fires. You manage endpoints through the /webhooks resource of the v1 API; listing works with a test key, while creating or changing endpoints needs a live key. The webhooks docs have the request format.
Note what is not in that table: there is no separate event for a KYC check that needs review or is rejected. verification.completed covers approvals. For everything else, read the check with GET /api/v1/checks/{checkId}. Design for that from day one.
Every delivery carries three headers:
X-TrustVerify-Event: the event nameX-TrustVerify-Signature: an HMAC-SHA256 of the request body, hex-encoded, using your endpoint's secretX-TrustVerify-Delivery-Id: a unique ID for this deliveryYour handler should compute the HMAC over the raw request body and compare it with the header before parsing or acting on anything. Three practical points:
crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python).Reject anything that fails the check with a 4xx and log the delivery ID, not the payload.
Webhooks are delivered at least once, not exactly once. If your endpoint is slow or returns an error, the delivery is retried. TrustVerify's default policy is exponential backoff with up to three retries, and a delivery that takes longer than ten seconds to answer counts as failed. Redirects are not followed, so the URL you register must be the one that answers.
That means your handler will sometimes see the same event twice. Two rules keep this safe:
Return a 2xx quickly. Put the event on your own queue and do the real work asynchronously. A handler that calls three other services before responding is a handler that times out.
A good pattern is to treat the webhook as a signal that something changed, then fetch the current state of the check by its ID before you act. It costs one extra API call, but it means your decision is always based on the latest record, it survives out-of-order delivery, and the same code path works for your reconciliation job.
Run that reconciliation job daily. Find sellers who have been pending longer than you expect and look up their checks directly. It catches the deliveries that failed every retry while your endpoint was down.
Different checks return different decision vocabularies, and your platform should not leak them into business logic. Map them once, in one place, onto your own states.
On the fraud score endpoint (POST /api/v1/fraud/score), the action field returns approve, review or block, alongside a 0 to 100 score where higher is safer and a list of signals. Many marketplaces add a fourth state of their own, step-up, for cases where they want more evidence before deciding. That state lives in your platform, not in the API response. KYC checks return a status, and KYB sanctions screening returns a risk level of clear, review or hit.
A workable mapping for a marketplace looks like this:
One detail worth knowing: when a fraud score is calculated without an IP reputation result (the scoreSource field reads heuristic), the API never returns approve. Your code should expect review more often in that case, not treat it as an error.
aml.hit is not part of onboarding. It fires later, when a seller you already verified and placed under ongoing monitoring matches a sanctions, PEP or adverse-media entry for the first time. That event should go to a person, not straight to an automatic block. Name matches need checking against the seller's other details before action. Route it to your compliance owner with a target response time.
Also subscribe to aml.monitor.suspended. It tells you re-screening has stopped because your plan no longer covers the monitored subjects. If nobody listens for it, monitoring can quietly stop with no one aware.
aml.hit and aml.monitor.suspended routed to a named person.Start from the quickstart and test with tv_test_sk_ keys in the sandbox before switching to live.
For what the checks themselves cover, see our KYC software for UK businesses and the guide to choosing KYC software in the UK.
If you are wiring verification results into your seller lifecycle, the webhooks guide is the place to start. Read the TrustVerify webhooks docs.
KYC, KYB, AML screening and fraud prevention in one place, with published pricing.
Developer
Using the TrustVerify Sandbox: Test Keys and Your First Check
A developer guide to the TrustVerify sandbox: test and live keys, deterministic synthetic results, magic test values and what the sandbox does not cover.
Developer
Rate Limits, Retries and Idempotency for Verification APIs
How verification API rate limits work, which errors to retry, how to back off properly and how to keep retries from creating duplicate checks.
Developer
Pulling Verification Reports via API
How to fetch KYC, KYB and AML screening reports by API, check they exist, download the PDF and assemble an evidence bundle for audit.