TrustVerify logoTrustVerify
Decorative footer background
TrustVerify logoTrustVerify

Identity and business verification for UK marketplaces. ID document and selfie checks, UK company and director checks, and a recorded decision on every check.

020 4542 7323

Solutions

  • All solutions
  • Identity (IDV/KYC)
  • Business (KYB)
  • Bot detection
  • AML & PEP screening
  • Seller verification (KYS)
  • UK registry checks
  • Ongoing monitoring
  • Review queue & trust score
  • Fraud checks
  • IP geolocation
  • Email validation
  • Escrow (secure transactions)

Industries

  • Marketplaces

Developers

  • Platform
  • Integrations
  • Developer docs
  • API reference
  • Webhooks
  • Changelog
  • API status
  • Help centre

Blog

  • All articles
  • Glossary
  • Compare
  • Sumsub alternatives
  • Onfido alternatives
  • Veriff alternatives

Company

  • About TrustVerify
  • Careers
  • Contact sales
  • Privacy policy
  • Cookie policy
  • Terms of service

© 2026 Magnificentech Solutions Ltd (Company No. 16321180), trading as TrustVerify. Registered in England & Wales. All rights reserved. · trustverify.co.uk

TrustVerify, Willow Farm, Choppington, Northumberland NE62 5EU · 020 4542 7323

  1. Blog/
  2. Developer/
  3. KYC Webhooks and Decision Handling for Marketplaces
Developer

KYC Webhooks and Decision Handling for Marketplaces

A practical guide to consuming KYC and fraud webhooks on a marketplace: signatures, retries, idempotency and mapping decisions to seller states.

Ayodele Michael Omotayo avatar
Ayodele Michael Omotayo
Founder & CEO, TrustVerify · 31 October 2026 · 7 min read

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.

The events you can subscribe to

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:

EventWhen it fires
verification.completedA KYC verification was approved
fraud.score.generatedA fraud score was produced for a transaction
aml.hitA monitored subject matched a sanctions, PEP or adverse-media entry they had not matched before
aml.monitor.suspendedRe-screening stopped because the plan no longer covers the monitored subjects
arbitration.resolvedAn 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.

Verify the signature before anything else

Every delivery carries three headers:

  • X-TrustVerify-Event: the event name
  • X-TrustVerify-Signature: an HMAC-SHA256 of the request body, hex-encoded, using your endpoint's secret
  • X-TrustVerify-Delivery-Id: a unique ID for this delivery

Your 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:

  1. Use the raw body. Many web frameworks parse JSON before your code sees it. Re-serialising a parsed object can change spacing or key order and break the signature. Capture the raw bytes.
  2. Use a constant-time comparison in your own code (for example crypto.timingSafeEqual in Node.js or hmac.compare_digest in Python).
  3. Store the secret like a password. It is shown when the endpoint is created. If it leaks, rotate it.

Reject anything that fails the check with a 4xx and log the delivery ID, not the payload.

Make the handler idempotent

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:

  • Record the delivery ID and skip any you have already processed.
  • Make state changes conditional. "Set seller to verified if they are currently pending" is safe to run twice. "Increment verified sellers by one" is not.

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.

Treat the webhook as a nudge, then read the check

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.

Mapping decisions to seller states

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:

  • Approve: the seller moves to verified. Listings go live and payouts follow your normal schedule.
  • Review: the seller stays pending. A person on your team looks at the check. Set a target time and track it. Our review queues page shows how the queue is organised.
  • Step-up: ask for more before deciding. That might be a further document, a check on the business behind the seller, or a verification of a bank account. The seller is not rejected, but they cannot transact yet.
  • Block: the seller cannot list or receive payouts. Record the reason internally and have a clear appeals route, because some blocks will be wrong.

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.

Monitoring alerts are different

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.

A short checklist before go-live

  • Endpoint registered with a live key, using HTTPS and answering in well under ten seconds.
  • Signature checked on the raw body with a constant-time compare.
  • Delivery IDs stored; handler safe to run twice.
  • Every decision outcome mapped to an internal state, including the ones you think are rare.
  • Daily reconciliation for sellers stuck in pending.
  • 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.

Next step

If you are wiring verification results into your seller lifecycle, the webhooks guide is the place to start. Read the TrustVerify webhooks docs.

Frequently asked questions

Is there a webhook for rejected or review KYC outcomes?
Not today. `verification.completed` fires on approval. Read other outcomes from `GET /api/v1/checks/{checkId}`, triggered by your own flow or a reconciliation job.
How are webhooks signed?
With an HMAC-SHA256 of the request body, hex-encoded, sent in the `X-TrustVerify-Signature` header and keyed with your endpoint secret.
What happens if my endpoint is down?
Deliveries are retried with backoff, three times by default. After that, use the check lookup to reconcile.
Can I subscribe to every event with a wildcard?
No. Subscriptions match exact event names. Unknown names are rejected with a list of valid ones.
Should an aml.hit automatically block a seller?
That is your policy decision, but most teams route it to a person first, because name matches need checking.

See TrustVerify in action

KYC, KYB, AML screening and fraud prevention in one place, with published pricing.

Book a 30-minute demoSee pricingRead the API docs
Ayodele Michael Omotayo avatar

Ayodele Michael Omotayo

Founder & CEO, TrustVerify

Founder and CEO of TrustVerify. Building identity and business verification for UK marketplaces, with every decision recorded.

LinkedIn →

Related posts

Cover image: Using the TrustVerify Sandbox: Test Keys and Your First Check

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.

Cover image: Rate Limits, Retries and Idempotency for Verification APIs

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.

Cover image: Pulling Verification Reports via API

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.

On this page

  • The events you can subscribe to
  • Verify the signature before anything else
  • Make the handler idempotent
  • Treat the webhook as a nudge, then read the check
  • Mapping decisions to seller states
  • Monitoring alerts are different
  • A short checklist before go-live
  • Next step