Liveness & PAD policy
This page is for a backend engineer or a risk owner who reads the results of a hosted identity verification and wants to know why checks.liveness and checks.selfie read review, what each reason code means, and which decisions your system should leave to a reviewer. It explains what the results mean and what to do with them. Model and vendor names and the internal score limits are not published.
Key points
- PAD is advisoryNoxtica reports the PAD result and never lets it decide. Every PAD result reads review, whatever its score.
- Liveness and selfie read at best reviewpass is not reachable for checks.liveness or checks.selfie while PAD is advisory. This is policy, not a capture problem.
- Two layers keep a verification in reviewThe check cap, and the hosted outcome: unverified with provider_manual_review until a reviewer decides. A validated PAD would remove the first layer, not the second.
- Decide on the reviewer, not on a checkTake the outcome from the reviewer decision. Do not auto-approve on any check, and do not ask for a new capture because of pad_unvalidated_model.
What it is
Availability: Controlled availability. Identity verification is provisioned per tenant by your account team. This page describes what the hosted verification reports for the liveness step and for the selfie; it applies to every hosted verification.
In short
- Presentation-attack detection (PAD) is advisory. Noxtica reports its result and never lets it decide. Every PAD result reads
review, whatever its score. checks.livenessandchecks.selfieread at bestreview.passis not reachable for either while PAD is advisory.scorecard.overallis therefore at bestreviewas well.reviewfrompad_unvalidated_modelis policy, not a capture problem. The person did nothing wrong, and a retake reads the same.- The PAD score is information. It is not a live or spoof verdict.
- Two independent layers keep a verification in review: the check cap above, and the hosted outcome: the automated run of a hosted verification ends
unverifiedwithprovider_manual_review, and a reviewer’s decision is what moves it on. - Nothing here is a tenant setting. Every limit and both layers are the same for every customer.
What PAD is
Presentation-attack detection tries to tell a live face in front of a camera from a presentation of a face: a printed photo, a photo or video replayed on a screen, a mask. In hosted verification it looks at frames of the liveness challenge, and separately at the selfie.
PAD is not the same as the gesture checks. The gesture checks (turn_left, turn_right, turn_up, turn_down, blink) show that the person moved as asked. PAD looks at the pixels of a frame and produces a live score.
Why PAD is advisory
A PAD score is worth acting on once the point at which a frame counts as live or as an attack has been measured on the population it will judge: genuine people on real devices in real light, and real attacks of each kind. That qualification has not been done on Noxtica’s own capture population. Until it is, a high score is not evidence that the person is live and a low score is not evidence of an attack, so the result is reported and never used to decide.
Promoting PAD to a decision needs a new qualification and a documented contract change. When that happens it is published in the API reference and its change log, and this page changes with it. No version is promised here.
What advisory means for each check
| Surface | What you read while PAD is advisory |
|---|---|
checks.liveness (identity read) | review, fail or null. Never pass. fail when a gesture confidently failed. null when no automated result was recorded. |
checks.selfie (identity read) | At best review. It reads fail only when a hard selfie-quality check fails. |
session.scorecard.liveness | review or fail (or pending / skipped). Gesture checks can read pass, the pad check and the overall active_liveness check do not. |
session.scorecard.selfie | At best review, with presentation_attack_detection_inconclusive and pad_unvalidated_model when the quality checks all pass. |
session.stages.active_liveness | review or fail. score is null. |
session.scorecard.overall | At best review. |
numeric scores on the pad (liveness) and live_score_band / pad_class_score (selfie) checks | Information for a reviewer and for your own analysis. Not a verdict. Do not set your own live or spoof cut-off on them. |
The two review layers
| Layer | What it is | What lifts it |
|---|---|---|
| 1. Check cap | checks.liveness and checks.selfie cannot read pass while PAD is advisory. | A PAD whose operating point is qualified and that Noxtica then lets decide. |
| 2. Hosted outcome | The automated run of every hosted verification ends verification.status: "unverified" (verification.source: "pipeline") with reasonCodes: ["provider_manual_review"] and the session waits in review_pending. A reviewer’s approve makes verification.status verified (verification.source: "review"); an override is recorded in review and does not upgrade the status. Either one sends kyc.review.decided. | A reviewer decision. It is a separate policy from PAD. |
A validated PAD would remove layer 1 only. Layer 2 stays: no check result, however good, makes a hosted verification verified by itself.
PAD reason codes
| Code | Meaning | Status it causes | Emitted today |
|---|---|---|---|
pad_unvalidated_model | The PAD result is advisory by design. | pad check review | Yes, on every PAD result |
presentation_attack_detection_inconclusive | Scorecard form of the same fact: the PAD analysis as a whole is inconclusive. It appears next to pad_unvalidated_model on scorecard.liveness and scorecard.selfie. | step review | Yes |
pad_face_not_detected | The PAD analysis did not find a face on a frame, even though other checks may have. The verification does not end in an error: the other checks continue. In the liveness result it comes with pad_unvalidated_model. | review | Yes |
pad_unavailable | PAD could not run. | review | No, reserved. A liveness check that cannot run at all shows one of the “could not run” codes below instead. |
pad_incomplete | PAD did not evaluate every challenge. | review | No, reserved |
pad_review | A PAD score that falls in the middle band once PAD decides. | review | No, reserved for when PAD decides |
pad_rejected | A PAD score that falls in the lowest band once PAD decides. | fail | No, reserved for when PAD decides |
Reserved codes are part of the published vocabulary so that your code can already accept them. Do not branch on them today: they are not produced.
Gesture reason codes
These explain a gesture check that did not pass. The gesture checks are turn_left, turn_right, turn_up, turn_down and blink (the passive variant has one passive_hold check). A check that reads review is written <name>_inconclusive in scorecard reason codes, and a failed one <name>_failed.
| Code | Meaning | Status it causes |
|---|---|---|
challenge_direction_inconsistent | The head movement did not match the requested direction. It is present when the gesture failed, or when the gesture reads review and no more specific cause below applies. A review that names its cause (for example client_metrics_unavailable) does not carry it. | gesture fail (or review) |
landmark_peak_mismatch | The browser’s reported peak frame does not match the server’s measurement. For up and down it is judged just when the head-pose measurement was available. | gesture fail (turn left and right, and up and down with a head-pose measurement) |
no_face_detected, multiple_faces | A frame had no face, or more than one face. | gesture fail |
face_track_lost | The face was lost between frames. | review or fail |
client_metrics_unavailable, client_landmark_low_confidence | The browser did not provide its own measurements, or provided them with low confidence. A blink is judged by the server on its own frames and does not carry them. | caps at review |
neutral_reference_unavailable | No usable starting pose (fewer than three single-face frames in the blink burst). | review, never pass |
pose_landmarks_unavailable | The head-pose measurement was unavailable for a frame, so up and down cannot be judged. | pitch gesture review |
blink_inconsistent | The blink could not be confirmed. When a blink-like cycle existed it comes with one of the three codes below. | blink review or fail |
blink_closed_plateau | A real eye closing and reopening was found, but the closed frame sits next to another almost identical near-closed frame. | blink review |
blink_scene_changed | The blink was found, but the nose region, which serves as a control for lighting and head movement, changed between the open frame and the reopened frame. | blink review |
blink_cycle_partial | Just part of the evidence for a blink was present, or the cycle was incomplete. | blink review |
blink_duration_out_of_range | The blink cycle lasted outside 50 to 1500 ms. | blink review |
passive_temporal_evidence_unavailable, passive_temporal_inconsistent, motion_implausible, frame_duplicate_suspected | Passive-hold variant: not enough or implausible motion across the three frames, or repeated frames. passive_temporal_inconsistent is present when the result is fail, or when a review has no more specific cause. | review (inconsistent: fail) |
The scorecard also carries active_liveness_inconclusive, active_liveness_failed and active_liveness_fail for the overall liveness result.
Codes for a liveness check that could not run
When the liveness check could not run at all, the result is review, never fail, and the stage reason is one of these codes. They say that no gesture was judged, not that the person failed.
| Codes | Meaning |
|---|---|
evidence_missing, evidence_unavailable, evidence_wrong_content_type, invalid_evidence_package, evidence_lookup_failed | The capture package was missing, could not be read, was the wrong kind of file, was not a valid package, or could not be looked up. |
transport_error, unexpected_status, malformed_response, malformed_refusal_body | The verification service did not answer in time, refused the request, or answered in a form that could not be read. |
adapter_not_configured, adapter_config_invalid, not_configured, weights_ungated | The liveness analysis was not set up for the environment or was not available there. |
Prerequisites
- A hosted verification that has reached the submit step, so that a result exists. Before that, the liveness step reads
pending. - A server key that can read the session status (
GET /v1/kyc/sessions/{sessionId}, see Server API reference: KYC), and, forchecks.*, the identity read (GET /v1/kyc/verifications/{verificationId}/identity, permissionread:identity_details). - A webhook endpoint subscribed to
kyc.review.decided(andkyc.session.completedfor a hosted session), if you complete your own flow on the reviewer’s decision.
Steps
Decide what your system does with a result
- Take the outcome from the reviewer decision. Read
verification.status,verification.sourceandreviewin the session status, or react tokyc.review.decided. Treatunverified/pipelinewithprovider_manual_reviewas “waiting for a person”. - Do not auto-approve on any check. No check result changes
verification.status, and no check,passincluded, replaces the reviewer decision. - Do not read a gesture
passas proof that the face was live. The gesture checks show that the requested movement happened. They are not a presentation-attack test. - Do not treat
reviewwithpad_unvalidated_modelas a capture failure. Do not ask the person for a new capture because of it. - Read
failas “a gesture confidently failed”. Use the gesture check and its reason code to see which one. Afailon a person who is clearly genuine is a false reject: report it with thesessionId. - Treat the PAD score as information. Show it to your own reviewers if you like. Do not turn it into a cut-off.
- Do not auto-reject on
review.reviewmeans “no confident answer, a person should look”.
Read per-gesture checks as information
In session.scorecard.liveness.checks, read the five gesture checks first. When every gesture check is pass: true and only active_liveness and pad are pass: false, the person did all five gestures and the review is the PAD policy. When a gesture check is pass: false, its reason codes say why.
Read the outcome
Read verification and review in the session status, or react to kyc.review.decided.
Read the gesture checks
turn_left, turn_right, turn_up, turn_down and blink say whether each movement was seen.
Spot the PAD policy
When just active_liveness and pad read pass false, the review is the advisory PAD policy.
Look up a reason code
A check that did not pass names its cause in a reason code listed on this page.
Leave the decision to the reviewer
Do not auto-approve, auto-reject or ask for a retake because of pad_unvalidated_model.
Verify it works
Take a hosted session whose person completed the liveness step and the selfie, and read GET /v1/kyc/sessions/{sessionId}. A result that follows this policy looks like this (the values are an illustration):
| Where | Value |
|---|---|
session.verification | status: "unverified", source: "pipeline"; reasonCodes holds provider_manual_review while the session waits in review_pending |
session.scorecard.liveness.status | review |
session.scorecard.liveness.checks | turn_left, turn_right, turn_up, turn_down, blink: pass: true. active_liveness, pad: pass: false. |
session.scorecard.liveness.reasonCodes | active_liveness_inconclusive, presentation_attack_detection_inconclusive, pad_unvalidated_model |
session.scorecard.selfie.status | review, with presentation_attack_detection_inconclusive and pad_unvalidated_model |
checks.liveness, checks.selfie (identity read) | review, review |
| after a reviewer approves | session.verification reads status: "verified", source: "review", session.review.decision is approve, kyc.review.decided is delivered, and provider_manual_review stays in reasonCodes. The check results do not change. |
If your system reads this as a problem with the person’s capture, change the rule in your system: this is the expected reading.
Troubleshooting
| You see | It means | What to do |
|---|---|---|
checks.liveness: "review", every gesture pass: true | PAD policy (layer 1). | Nothing. Wait for the reviewer decision. |
checks.selfie: "review", quality checks all pass | PAD policy (layer 1). | Nothing. Do not ask for a new selfie. |
verification.status: "unverified", provider_manual_review, review: null | Layer 2. A reviewer has not decided yet. | Wait for kyc.review.decided. |
pad_face_not_detected | The PAD analysis found no face on a frame. The rest of the verification continued. | Nothing in your integration. A reviewer looks at it. |
blink_inconclusive | The blink was not measured or not confirmed. | Treat it as “not measured”, not “no blink”. A reviewer looks at it. |
turn_*_failed | The head barely moved, the face was very small, or the light was poor. | Your policy: the hosted page already has a retake budget for the person. |
fail on a genuine person | A false reject. | Report it with the sessionId. |
A stage reason such as evidence_missing | The liveness check could not run. | A reviewer looks at it. It is not a failure of the person. |
Related
- Identity verification integration: create a session and read the outcome.
- Read identity details with the API: the
checks.*summary of a verification. - Identity verification events and webhooks:
kyc.review.decidedandkyc.session.completed. - Identity verification FAQ and troubleshooting: statuses, review and a five-step triage.
- Server API reference: KYC: every check, threshold and reason code of the other steps, under “Check results” on
GET /v1/kyc/sessions/{sessionId}.