Fraud signals
Suspicion is a first-class, structured output of this system — not a buried log
line. Every signal becomes a human-readable entry in decision_reasons, an event in
the audit chain, and an input to the decision engine. This page is the catalogue.
How signals map to outcomes
Section titled “How signals map to outcomes”The engine applies signals in severity order. The rule underneath everything: suspicion never auto-approves.
| Outcome | Triggered by |
|---|---|
rejected (hard fail) | Not an ID document · expired document · failed liveness · face match below threshold |
manual_review (suspicion or uncertainty) | Any tamper signal · MRZ check-digit failure · MRZ↔visual disagreement · low AI confidence · missing core fields · liveness not assessable · biometric stack unavailable · any pipeline error |
approved | Zero signals, all checks affirmatively passed |
Document signals
Section titled “Document signals”Signal (as seen in decision_reasons) | What it means | Why it matters |
|---|---|---|
MRZ validation failed: document number check digit invalid (also DOB / expiry / composite) | The ICAO 9303 check digits printed on the document don’t validate | Forgers who alter printed data rarely recompute the checksums — this is cheap, deterministic maths catching real tampering |
MRZ/visual disagreement: DOB mismatch … (also expiry, family name) | The machine-readable zone and the printed text disagree | Classic photo-substitution / partial-alteration signature: one zone edited, the other forgotten |
tamper signal: … (free text from AI inspection) | The vision model saw concrete artifacts: photo-substitution edges, font/kerning mismatches, digital editing traces, screen re-capture moiré | The broad net for forgeries the deterministic checks can’t see |
document expired on YYYY-MM-DD | Hard reject | Expired documents are never acceptable ID |
uploaded image is not an identity document | Hard reject | Cat photos, memes, blank paper |
low extraction confidence (0.xx) | AI couldn’t read the document confidently | Usually capture quality; occasionally deliberate obfuscation |
quality: … | Blur, glare, cropping, occlusion | Same — and a fraud vector (hide the tampered region under glare) |
Biometric signals
Section titled “Biometric signals”| Signal | What it means |
|---|---|
liveness check failed + step 'left': head yaw NN° outside expected range | The “person” didn’t perform the requested pose — static photo, replay, or puppet |
identity changed between frames (consistency 0.xx) | A different person appeared mid-challenge — the classic “accomplice does the turns, fraudster does the match frame” attack |
step 'x': expected exactly 1 face, found N | Nobody, or multiple people, in frame |
face match below threshold (0.xx) | The selfie is not the person on the document — stolen-document signature |
no face found on the document | Portrait unreadable or absent — quality or tampering |
no active challenge issued — liveness not assessable | Single-frame fallback path was used; match may pass but liveness can’t → review |
expected N challenge frames, got M | Device sent an incomplete challenge — abandoned flow or a client trying to skip steps |
Behavioural signals (yours to watch)
Section titled “Behavioural signals (yours to watch)”The audit chain gives you the raw material for velocity/pattern detection that the per-verification pipeline can’t see:
- The same
external_user_refcreating many verifications after rejections (retry-until-lucky). - Bursts of verifications from one API key outside its product’s normal traffic shape (leaked key).
- Many
manual_reviewoutcomes sharing one tamper-signal phrasing (a forgery template circulating — escalate per incident response). - 429s from the capture endpoints (automated abuse probing).
Alerting recipes for all of these: Monitoring.
Tuning the thresholds
Section titled “Tuning the thresholds”Current defaults, and the trade-off each controls:
| Knob | Default | Raising it | Lowering it |
|---|---|---|---|
| Face match threshold | 0.40 cosine | Fewer impostors pass; more twins/aging/photo-quality false rejects | Opposite |
| Frame consistency | 0.55 cosine | Stricter same-person enforcement across the challenge | Tolerates more pose/lighting variation |
| AI confidence floor | 0.85 | More reviews, fewer misreads acted on | Fewer reviews |
| Pose yaw windows | ±15° center · 18–90° turns | Stricter pose proof | Easier UX |
Calibrate against your population before trusting auto-approve: run 10–20 known- good real ID + selfie pairs and a handful of deliberate spoofs (printed photo, phone screen replay), and check both sides of each threshold. Re-run whenever demographics or capture hardware shifts materially.