Flow & Check List
How a verification session runs, end to end
This page walks through every step from the moment an end user enters the flow to the moment a signed webhook reaches your system — the checks that run at each step, and the exact numbers behind each decision.
Every weight, threshold and limit below is a value actually enforced in the platform. Per-tenant configuration can only tighten them, never loosen them.
- 8
- Flow steps — from session creation to webhook delivery
- 18
- Distinct document checks — 15 scored + 3 hard rules
- 5
- Document profiles — each with its own weight set
- 3
- Liveness layers — active, passive ML, heuristic
Step by step
Session flow
The photo and NFC paths are identical through step 3, diverge at step 4, and converge again at step 5.
- Your system
Session creation
Your backend opens a verification session. The tenant API key is used only in this call and never reaches the browser. The returned session_id is the only user identifier exposed externally.
POST /v1/sessions · X-Api-Key · state: created
Checks that run at this step
- Velocity limit: at most 5 sessions per applicant per 24 hours
- Velocity limit: at most 20 sessions per IP per 24 hours
- Tenant balance check on production sessions
- Reusable KYC: an approved verification newer than 180 days with no AML alert skips re-verification
- End user
Opening the flow
The user opens the WebSDK (iframe) or a mobile SDK. Instead of an API key, the SDK works with a short-lived JWT scoped to that session, valid for 15 minutes by default. Tenant theme and language (TR/EN) are applied at this step.
GET /v1/sessions/{id}/config · short-lived JWT (15 min) · CORS allowlist
Checks that run at this step
- Session validity window: 60 minutes (it moves to expired past that)
- Per-tenant CORS allowlist — the SDK only loads from declared origins
- Active modules (document / liveness) are read from the session config
- End user
Document selection and capture
The user picks a document type and captures it with the camera. Card edges are detected and cropped automatically; overly blurry or dark frames are flagged on-device and re-captured before ever reaching the server. On the NFC path the MRZ is scanned first — the key that unlocks the chip is derived from it.
POST /v1/sessions/{id}/access-keys · POST /{id}/documents/images
Checks that run at this step
- Supported types: Turkish ID card, passport, driving licence, residence permit, Ghana Card
- The back side is mandatory where the profile requires it (TD1 MRZ sits on the back)
- On-device quality gates: sharpness, brightness, framing
- IDV platformPhoto path
Document analysis
The session moves to document_processing and a background worker analyzes the images: PP-OCR field reading, MRZ decoding via a separate path calibrated for OCR-B, ICAO 9303 check digit validation, and tamper detection via ELA and texture analysis. Each check produces a 0–100 score, reduced to a single document score by the profile weights.
state: document_processing → liveness_pending | review | rejected
Checks that run at this step
- 15 scored checks (with per-profile weights in the table below)
- 3 unweighted hard rules: file integrity, document expiry, specimen detection
- Cross-field consistency between front and back (MRZ ↔ printed fields)
- IDV platformNFC path
Chip reading and passive authentication
On eMRTD-compliant documents the chip is accessed over a BAC-established encrypted channel (Secure Messaging); data groups DG1 (MRZ), DG11 and DG12 are read. ICAO 9303 Passive Authentication proves two things: the hashes in the SOD show the data is unaltered, and the Document Signer certificate shows the data was genuinely written by the issuing state.
POST /{id}/documents/nfc · state: nfc_processing → liveness_pending | review
Checks that run at this step
- SOD hash integrity — verified separately for each data group
- Document Signer certificate signature, validated against the CSCA trust chain
- Chip values are compared to the declared document number / date of birth / expiry — a mismatch goes to manual review (the chip is authoritative)
- IDV platform
AML / sanctions screening
The name extracted from the document is screened against open sanctions lists synced daily. Names are normalized (accents and Turkish characters folded), records with a fuzzy match score of 90% or above become candidates, and candidates whose birth year conflicts are eliminated.
rapidfuzz token_sort_ratio ≥ 90% · match → state: review
Checks that run at this step
- OFAC SDN (U.S. Treasury), UN Consolidated and EU FSF lists
- False-positive elimination via birth-year conflict checks
- A match never auto-rejects — the decision is left to a human
- End user
Liveness detection and face matching
The server generates a random sequence of 3–4 challenges (at least one blink and one head movement are guaranteed) alongside a single-use identifier. The user submits one frame per challenge plus a selfie; the server verifies each frame independently against its challenge type, then biometrically compares the selfie to the document photo.
POST /{id}/liveness/start → /{id}/liveness/submit · challenge TTL 300 s
Checks that run at this step
- Every active challenge must pass — no tolerance
- Frame-to-frame consistency: same person, and no static replay
- Passive anti-spoofing (MiniFASNet ensemble) + heuristic LBP/FFT/YCrCb signals
- ArcFace embedding comparison between document photo and selfie
- Each approved face is written to pgvector; the same face under a different identity raises a duplicate signal
- IDV platform
Decision and delivery
The outcome of every layer is reduced to a single terminal state. Whatever the decision, each state transition is written to a timestamped event log. The result is delivered to your system via an HMAC-SHA256 signed webhook, and can always be read back from the result endpoint.
webhook · X-Idv-Signature: hmac-sha256=… · GET /{id}/result
Checks that run at this step
- Terminal states: approved, review, rejected, expired
- A rejected session grants the user 3 retry attempts
- Failed webhook deliveries are retried; delivery records are retained
- Personal data is deleted automatically 90 days after the terminal state
State machine
Session states
A session can only make defined transitions, each one written to the audit log, with no way back. This structurally blocks replay attempts that resubmit an earlier step.
created
Created
Session opened; the user has not entered the flow yet.
document_pending
Awaiting document
SDK open, waiting for the document upload.
document_processing
Document in review
Image checks and OCR/MRZ decoding are running.
nfc_processing
Chip in review
On the NFC path, chip data and passive auth are being processed.
liveness_pending
Awaiting liveness
Document passed; waiting for the challenge sequence.
liveness_processing
Liveness in review
Active/passive layers and face matching are running.
approved
Approved
All checks passed — identity verified.
review
Manual review
No automatic decision; awaiting an operator.
rejected
Rejected
One or more checks failed conclusively.
expired
Expired
The session was not completed within 60 minutes.
Document engine
Check list and weights
Each document type carries its own weight set — the MRZ dominates on a passport, while text readability leads on a driving licence that has no MRZ. The percentages below are the contribution shares when every check runs.
| Check | TR ID Card | Passport | Driving Lic. | Residence P. | Ghana Card |
|---|---|---|---|---|---|
| MRZ ValidationICAO 9303 machine-readable zone: check digits and field consistency. | 19.5% | 27.1% | — | 25.3% | 23.5% |
| Text ReadabilityHow many document-specific keyword groups OCR can find. | 8.8% | 10.4% | 19.8% | 12.6% | 9.8% |
| Sharpness / FocusBlur measured via Laplacian variance. | 8.8% | 10.4% | 12.3% | 10.5% | 9.8% |
| Tampering (ELA)Error Level Analysis: traces of re-saved or edited regions. | 7.1% | 8.3% | 9.9% | 8.4% | 7.8% |
| Face DetectionPresence and placement of the biometric portrait on the document. | 7.1% | 8.3% | 9.9% | 8.4% | 7.8% |
| Screen/Print DetectionMoiré patterns via FFT periodic peak analysis — a photo of a screen. | 7.1% | 8.3% | 9.9% | 8.4% | 7.8% |
| Document ContourID-1 rectangular edge detection and the 1.586:1 aspect ratio. | 5.3% | 6.3% | 7.4% | 6.3% | 5.9% |
| Brightness & GlareOverly dark, blown-out or flash-glared frames. | 4.4% | 5.2% | 6.2% | 5.3% | 4.9% |
| Local Texture ConsistencyRegional texture deviation — region-level splicing detection. | 4.4% | 5.2% | 6.2% | 5.3% | 4.9% |
| ResolutionA readability floor of at least 600×400 pixels. | 2.7% | 3.1% | 3.7% | 3.2% | 2.9% |
| TR National ID AlgorithmMathematical checksum validation of the Turkish national ID number. | 8.0% | — | 14.8% | — | — |
| Ghana Card PINGHA-XXXXXXXXX-X format plus cross-check against the MRZ. | — | — | — | — | 8.8% |
| Colour SignatureThe turquoise/pink print colour signature of the Turkish ID card. | 7.1% | — | — | — | — |
| Micro PrintPresence of the repeating fine print pattern on the back side. | 4.4% | — | — | — | — |
| Data ConsistencyCross-comparison of MRZ fields against the printed fields on the front. | 5.3% | 7.3% | — | 6.3% | 5.9% |
A check that could not run (the MRZ with no back side, for example) never enters the score; the remaining checks are rescaled among themselves. Missing data therefore does not behave like a low score.
Unweighted hard rules
These three checks do not enter the score — they set the outcome directly. Even at a score of 100, a failure here blocks automatic approval.
File Integrity
Corrupt, empty or under-5 KB files — no other check is run.
Document Validity
A check-digit-verified expiry date in the past is a hard reject.
Specimen Detection
Specimen markings and known sample document numbers.
Scoring
How the decision is made
Every check produces a score between 0 and 100. The document score is the weighted average of the checks that ran, and falls into one of three decision bands.
Document score
Σ (check score × weight) ÷ Σ (weight)
Thresholds can be raised per tenant but never lowered — the rule engine clamps every value to the global floor.
- ≥ 70Automatic passDocument passed; the flow advances to liveness (or straight to approval in document-only mode).
- 45 – 69Manual reviewA document was detected but could not be fully verified; an operator decides.
- < 45Automatic rejectThe checks do not support the validity of the document.
Hard rules that override the score
In these cases the decision is as follows regardless of the weighted score.
Face but no text → reject
Catches users who upload a selfie instead of a document. The rule is disabled once the MRZ is verified, so a genuine card is never rejected by mistake.
No document evidence → reject
With no face, no readable text and no MRZ, this is not an identity document; even a review-band score is turned into a reject.
Expired document → reject
A hard reject when the expiry date is verified by its MRZ check digit and lies in the past.
Specimen document → reject
A conclusive specimen marking rejects; a weak or ambiguous marking goes to manual review instead of automatic approval.
National ID cross-check failed → review
Splicing the two sides of different cards is only visible in the cross-comparison; automatic approval is blocked and a human decides.
AML match → review
A sanctions list match never produces an automatic rejection under any circumstances.
Duplicate face → review
If the same face was previously approved under a different identity, the session is routed to a human.
Chip/declaration mismatch → review
Where the NFC chip value differs from the declared one, the chip is treated as authoritative and the session goes to review.
Liveness
Three layers of liveness assurance
The layers complement each other: the active layer proves the user is really there, the passive layer proves what faces the camera is not a screen or a print, and the heuristic layer looks for artifacts the other two miss.
- 1
Active challenges
The server generates a random sequence (blink, head turn). Each frame is verified independently on the server against its challenge type — the client claiming 'passed' counts for nothing.
MediaPipeHaar cascadeHead pose
- 2
Passive anti-spoofing
A MiniFASNet ensemble: two independent models sensitive to print, screen replay and moiré artifacts produce a single genuineness probability.
MiniFASNetV2MiniFASNetV1SEONNX
- 3
Heuristic signals
Texture, frequency and colour-space heuristics (LBP / FFT / YCrCb), frame-to-frame consistency and optical-flow motion analysis are weighed as secondary signals.
LBPFFTOptical flow
Liveness confidence score
(passive score × 0.35 + face match × 0.65) × 100
Two thirds of the weight sits on the face match: a genuine face that does not belong to the person on the document is not rescued by a high passive score. And the score alone is not enough — every gate beside it must be cleared as well.
Gates that must be cleared
- Active challenges
- allA single missing or failed frame fails the attempt; the user can retry.
- Passive score floor
- ≥ 0.40Lower bound on the ensemble genuineness probability.
- Anti-spoof gate
- ≥ 0.55Ensemble threshold for a 'genuine face' verdict.
- Confidence score
- ≥ 60Lower bound on the combined liveness confidence (a tenant may raise it).
- Challenge TTL
- 300 sValidity window of the single-use challenge id — it closes the replay window.
Face matching and duplicate detection
The document photo and the selfie are compared through ArcFace embeddings. Every approved face is written to a vector database, which catches the same face enrolling again under a different identity.
0.55
Match threshold
Lower bound on cosine similarity between document photo and selfie.
0.60
Quality gate
SCRFD detection score — no embedding is produced from blurry or partial faces.
0.75
Duplicate threshold
Normalized cosine; above it is a 'same person' suspicion and goes to manual review.
AML
Sanctions list screening
Screening uses publicly available lists only; identity data is never sent to a third-party commercial data vendor. Lists are downloaded by a daily cron and written to a local database.
OFAC SDN
U.S. Department of the Treasury — Specially Designated Nationals list (CSV).
UN Consolidated
United Nations consolidated sanctions list (XML).
EU FSF
European Union Financial Sanctions Files (CSV).
PEP (optional)
An operator-supplied politically exposed persons source — skipped when not configured.
How matching works
- 1The name is normalized: accents and Turkish characters are folded, leaving only A–Z and single spaces.
- 2Fuzzy matching runs via rapidfuzz token_sort_ratio, so a different word order does not break the match.
- 3Records scoring 90% or above are taken as candidates.
- 4A candidate whose birth year conflicts with the one read from the document is eliminated (false-positive filter).
- 5If any match survives, the session goes to manual review and the match details are written to the record.
A match never produces an automatic rejection. Because sanctions lists can contain people who merely share a name, the final decision always rests with a human.
Abuse protection
Limits and windows
All of these are counted per environment — sandbox testing never consumes a production limit.
- 5 / 24 h
- Sessions / applicant
- Daily sessions openable for the same applicant_external_id.
- 20 / 24 h
- Sessions / IP
- Daily sessions openable from the same IP address.
- 3
- Retries
- Retry attempts granted after a rejection; beyond that the API returns 409.
- 60 min
- Session lifetime
- An incomplete session becomes expired after this window.
- 15 min
- SDK token
- Lifetime of the short-lived JWT used by the web and mobile SDKs.
- 180 days
- KYC reuse
- An approved verification newer than this is not asked for again (absent an AML alert).
- 90 days
- PII retention
- How long after the terminal state personal data is automatically deleted.
Delivery
Getting the result into your system
A distinct event is produced for every status change. Webhooks are signed with HMAC-SHA256; undeliverable ones are retried, and every delivery attempt is recorded.
- document.verifiedThe document (or chip) was verified; the flow moved on to liveness.
- document.review_requiredThe document could not be auto-verified, or there is an AML match — an operator decides.
- document.rejectedDocument checks failed conclusively.
- liveness.failedOne of the liveness layers was not cleared.
- session.manual_reviewLiveness passed but there is a duplicate-face suspicion.
- session.approvedAll checks passed — identity verified.
# webhook
X-Idv-Signature: hmac-sha256=9d41…
{ "event_type": "session.approved",
"session_id": "s_7f3a…",
"status": "approved",
"environment": "production" }
Beyond the webhook, the result can always be read via GET /v1/sessions/{id}/result, so a missed webhook never stalls the flow.
Important note
This page describes the platform's current behavior. Thresholds and limits may be configured more strictly in your tenant agreement; loosening them is not possible.