Inyo

Manual Review

in_review means a person at Inyo decides the outcome. It is not a failure and not a final answer, and it can reach you on either entry point β€” including in the synchronous response from POST /v1/verifications and on a redirect your customer arrives on.


Why a Verification Is in_review

auto_status tells you what the pipeline decided before any routing or human decision, so in_review is never ambiguous:

statusauto_statusWhat happened
in_reviewin_reviewA soft check failed β€” for example an MRZ check digit, a document-number format mismatch, or a data mismatch
in_reviewapprovedA borderline pass, routed by your review threshold
in_reviewdeclinedA rejection held for a human, because you enabled held rejections

Read auto_status before deciding how to treat a held session in your own product. A borderline pass and a held rejection are very different signals, even though both arrive as in_review.


Routing a Borderline Approval

A configured review threshold catches auto-approvals whose confidence falls below your bar and routes them to review instead. It applies identically to widget sessions and server-to-server verifications β€” one setting, one routing decision, whichever entry point the verification arrived through.

Confidence is the weakest score among the checks carrying a calibrated per-capture measure, which depends on how the liveness result was obtained:

Liveness resultChecks that count toward confidenceFloorOperative band on defaults
Selfie mode (default)face_matchYour face-match threshold(90, 100]
Streaming liveness sessionface_match, livenessThe lower of the two thresholds(80, 100]

Both counted checks are hard checks that must already clear their own thresholds for a verification to be approved. A review threshold at or below that floor can therefore never fire β€” configuring one is rejected with a message naming the computed floor. And because the floor moves with your own thresholds, read the current values from each check's detail rather than assuming the platform defaults.

liveness is deliberately excluded in selfie mode: there its score is an image-quality heuristic over face confidence, sharpness, and brightness, so routing on it would turn this into a photo-quality gate rather than a confidence gate. It remains a hard check either way β€” a poor capture still declines; it just does not drive review routing.

A verification with no selfie carries no biometric score at all. That counts as unmeasured, not confident, so with a threshold configured it routes to review rather than auto-approving. Send a selfie, or leave the threshold unset, if you need document-only verifications decided synchronously.


Holding a Rejection for a Human

The review threshold catches borderline approvals. A separate setting β€” off by default β€” catches rejections: a verification the checks rejected routes to in_review instead of declined, so an analyst confirms it before it is final. A false decline loses a real customer silently, and that is the case this exists for.

What it covers is whatever a human could complete. A rejection is held when the document was readable β€” expired, face mismatch, liveness, rejected jurisdiction, failed authenticity, screen recapture. It is not held when the core identity fields never came out of the document, because approving such a session would deliver a verified identity with nothing in it; those keep auto-declining, and an analyst cannot approve one either.

This behaves the same on both entry points. The widget offers a retake on recoverable capture problems and server-to-server does not, but that difference is about coaching a live customer β€” it does not change what your setting means.

The load is uncapped. Every held rejection becomes an analyst task and nothing throttles that queue, so with this setting on, review volume scales with however much fraud you attract.


How the Decision Reaches You

When an analyst decides, the stored result is updated in place and re-delivered.

ChannelBehavior
WebhookWith a webhook_url configured, the decided result is POSTed to it β€” signed exactly like any other delivery. This covers redirect-mode sessions and server-to-server verifications too, via result notifications
PollingGET /v1/sessions/{session_id} returns the live status and result. This is the only channel if you have no webhook_url, or if you have disabled notifications

The delivered result carries a manual_review object:

{
  "session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
  "status": "approved",
  "auto_status": "declined",
  "manual_review": {
    "action": "review",
    "reviewer": "analyst-7",
    "reason": "Expiry misread by OCR; document valid through 2029 on the physical card",
    "auto_status": "declined"
  },
  "notified_at": "2026-07-31T14:41:09.882Z"
}
FieldDescription
actionreview for a decision on a queued session, override for a quality-control reversal of an already-completed one
reviewerWho decided
reasonWhy, in the reviewer's words
auto_statusThe pipeline's original verdict, preserved for audit

status and auto_status at the top level tell you the same story: after a decision, status is the human outcome and auto_status still shows what the automation concluded.


Completed Outcomes Can Change

A verification that already reached approved or declined can be reversed later by a quality-control override. It arrives through the same channel, with manual_review.action set to override.

This is why ordering matters: apply the highest notified_at and ignore anything older (see Receiving Results). A session can have two deliveries in flight at once β€” one still retrying while a newer decision is dispatched.


What to Build

RequirementWhy
A pending state in your own model, distinct from approved and rejectedin_review is neither, and your customer may be waiting on a landing page that received it
An idempotent result handler keyed on session_id, resolving by notified_atThe same session's result legitimately arrives more than once
The ability to reverse a decision you already acted onA quality-control override can flip a completed outcome
A reconciliation job for non-terminal sessionsDelivery is best-effort; polling is authoritative

If neither the review threshold nor held rejections are configured for your tenant, in_review still occurs β€” a failed soft check produces it β€” so handle the state regardless.


Next Steps