Skip to content

Verification flow

A verification is created by you (the integrator) and completed by your user (the applicant). Two surfaces, one record — and a session dashboard where you and your team review the result.

  • Integrator API (/v1) — your backend starts a verification → { id, onboarding_url }. Create one directly with POST /v1/verifications (inline accepted-document allowlist), or run a Flow you authored with POST /v1/flows/{slug}/intake. You own the config; the applicant never sees a choice you didn’t allow.
  • Hosted onboarding — the applicant opens onboarding_url (it carries a short-lived session token, the only client-side credential), captures the documents you allowed, takes a selfie, and submits.

The same record also surfaces in the dashboard’s Verifications list (each run is a Case), where a teammate with the cases:review permission opens Case Management to record a customer disposition alongside thibit’s assessment. The disposition is your team’s own outcome record — it never changes the assessment. The Template → Flow → Case model — and the intake and record_match pieces — are covered in Templates, Flows & Cases.

your backend ──POST /v1/verifications──▶ thibit ──onboarding_url──▶ your user
│
async engine run │ ◀──captures + selfie──┘
▼
your backend ◀──webhook / GET /v1/verifications/{id}── assessment
Status Meaning
collecting Session created; gathering documents on the hosted page.
pending Submitted; queued for the engine.
processing The engine is running (OCR + template + forensics + liveness).
completed An assessment was produced (assessment + confidence + result).
failed No assessment was produced (assessment_incomplete): processing failed, the document is not supported, or the hosted link expired before the applicant submitted. An expired link sends no webhook.
erased The record was erased on request (DELETE /v1/verifications/{id}); a PII-free tombstone + receipt remain.

Creation returns immediately — verification is asynchronous, so never block a request waiting for it. The result arrives by webhook or by polling GET /v1/verifications/{id}; poll too if you need to notice abandoned verifications, since a link that expires sends no webhook. A hosted link is valid for two hours by default (intake’s link_ttl_seconds sets 10 minutes to 7 days).

For each verification thibit runs: OCR (reads the document, compares to the applicant data) · template match (accepted documents — MRZ check-digits + tuned per-country templates) · authenticity (EXIF/metadata plus a vision-model tamper / recapture check) · liveness (selfie-to-document face match, with an active-liveness challenge) · then an assessment that weighs the whole bundle into one of:

assessment Meaning
no_material_concerns Nothing inconsistent surfaced.
manual_review_recommended A human should look before you act.
material_inconsistency The evidence contains a material inconsistency.
assessment_incomplete The assessment could not be completed.

This is a closed set — no other values appear — and it is advisory: the final business decision is always yours. Liveness and presentation-attack signals are assessed conservatively: a suspicious capture is routed to manual review, not guaranteed to be blocked.

A Flow can add two checks that never produce an adverse assessment on their own:

  • AML screening is a step a Flow can include, but no screening provider is connected in this release. The step reports the screening as unavailable, which never counts as clean: the result recommends manual review (reason sanctions_unavailable), never material_inconsistency.
  • Registry lookups ask an approved registry to confirm selected identity fields, when the Flow includes them and the verification carries a registry_authorization. They do not change the result: the registry’s answer is recorded as evidence for your reviewer.

type is kyc in this release — production rejects type: "kyb". Business verification (UBO declaration and roll-up) is outside the launch scope. The applicant never picks the type; you set it at creation.