Verification sessions
A verification session ties one end user's document check, liveness check and face match together and returns a single decision. Use it when you need to know that the person holding the phone is the person on the document, not just that each check passed on its own.
Flow
- Your server calls
POST /v1/verificationswith a secret key and thecustomer_refof the person being verified. The response is the verification (vf_…) plus a session token (dv_tok_…) bound to it. - Your app uses that token to call
POST /v1/ocr(front and back of the document), thenPOST /v1/fraud/detectwith the same image files byte for byte, thenPOST /v1/liveness/check, exactly as it would for standalone checks. Each result is recorded as a step of the verification. A fraud check sent before the scan, or on other images (including a dropped or added back), is refused with400 validation_errorbefore any analysis or billing. - The platform compares the document portrait with the frame the liveness check scored, on the server, and decides. Your app never uploads a selfie for matching.
- Your server polls
GET /v1/verifications/{id}for the decision. Averification.completedevent is published for it as well; see Webhooks for which events can be subscribed to today.
The standalone endpoints keep working unchanged for integrations that only need one check.
Steps and decision
| Step | Completed when | Fails when |
|---|---|---|
document | OCR is eligible and a fraud check on the scanned images has run with a clean or needs_review decision | the fraud decision is fraudulent |
liveness | is_live is true | is_live is false, with the liveness reason as the reason code |
match | the document portrait and the scored liveness frame agree at or above the tenant's face_match_threshold | they do not, or one side has no usable face embedding |
The decision is made as soon as it is determined:
| Outcome | When |
|---|---|
rejected | fraud said fraudulent on any scan in the verification; liveness failed and no attempts remain; the face did not match and no attempts remain |
review | fraud said needs_review or the fraud memory found a collision on any scan (unless the policy lets that through); always when the match could not be computed |
approved | every required step completed and the faces match |
A liveness or match failure with attempts left keeps the verification
pending, so the app can ask the user to try again. A verification is
closed once decided; further calls with its token return
409 verification_closed, and calls for an expired or unknown verification
return 404 not_found.
Scanning the document again replaces the document step, and the new scan
needs its own fraud check. A needs_review, fraudulent or collision
verdict from any scan still counts, even one that arrives after the re-scan;
a retake verdict does not.
Policy
Defaults come from your tenant configuration and can be overridden per verification in the create request:
{
"customer_ref": "cust-42",
"policy": {
"required_steps": ["document", "liveness", "match"],
"liveness_mode": "challenge",
"max_liveness_attempts": 2,
"review_blocks_approval": true
}
}
| Field | Default | Notes |
|---|---|---|
required_steps | ["document", "liveness", "match"] | Which steps the decision waits for. |
liveness_mode | challenge | passive, burst or challenge. Enforced: a liveness call in another mode is a validation_error before any processing. |
max_liveness_attempts | 2 | 1 to 5. Liveness or match failures beyond this close the verification as rejected. |
review_blocks_approval | true | Whether a needs_review fraud decision or a fraud-memory collision holds the verification in review instead of approving. It never approves a verification whose face match could not be computed, and never overrides fraudulent. |
The token returned by POST /v1/verifications is a normal session token
(see Authentication) bound to the verification, so
client code that already takes a dv_tok_… works unchanged.
Retention and billing
A verification record is kept for 90 days after its session token expires, whatever its outcome. Each step bills its own feature exactly as the standalone call does; the verification object itself is free.