issues[] carries a code. Codes are a stable contract: once
published, a code is never renamed or repurposed. Branch your logic on code, never on
message.
Types
Some codes are marked policy-driven below: their type is not fixed, it comes from the
REJECT / WARN / IGNORE action you configured for that policy. With IGNORE, nothing
is emitted at all.
Most codes carry
details: null. details is populated only when it tells you something
you cannot get from elsewhere in the result — a similarity score you cannot recompute,
or a historical value that does not appear anywhere else. Thresholds and expected values
are omitted because they are in the config you sent; extracted values are omitted because
they are in result_data.Request and session
These abort the analysis.decision is UNDETERMINED.
These generally mean something went wrong between the SDK and the API rather than anything
about the user. Retry with a new transaction.
Configuration — blocking
Yourconfig could not be applied. Analysis does not run; decision is UNDETERMINED.
These are integration bugs, not user failures. Fix the config and create a new transaction.
Configuration — advisory
The config is valid but probably not what you meant. Analysis proceeds normally.Engine
decision is UNDETERMINED. No details — the diagnostics are internal.
Retriable. Create a new transaction rather than treating the user as rejected.
Customer
Device
All policy-driven viadevice_policy. No details —
the signals behind them are in result_data.metadata.
Location unavailable
Signal missing with policy active
Emitted only when the corresponding policy is notIGNORE. Never change the decision —
they tell you a rule you configured could not run.
Document — capture and legibility
Most of these are recoverable by the user — better lighting, a flatter surface, no glare.
Worth surfacing as “try again” rather than a hard failure.
Document — authenticity
Nodetails beyond one case: naming the check that caught the forgery would tell a
fraudster what to fix.
Document — eligibility
DOCUMENT_TYPE_NOT_SUPPORTED and DOCUMENT_NOT_ELIGIBLE are worth distinguishing in your
UI: the first means “we cannot read this”, the second means “you asked us not to accept it”.
Document — customer history
The customer’s history is not in the result, so all three carry it indetails.
Data matching
AllREJECT. Only the fuzzy comparisons carry details — you cannot recompute a
similarity score, but you already know the exact values you sent.
Liveness
AllREJECT. Scores and facial attributes are already in result_data.liveness.data.
Sunglasses, closed eyes, occlusion and poor quality are all things the user can fix.
Offering a retry converts most of them.
Face comparison
FACE_COMPARISON_SKIPPED_NO_REFERENCE is normal and expected on a customer’s first
transaction. It is INFO, not a rejection.
Not yet enforced
These codes are defined and their policies are accepted by the API, but the analysis engine does not evaluate them yet, so they are not currently emitted. Configure them if you want the intent recorded; do not rely on them as active protection.
Blocklist matches deliberately carry no
details: exposing why someone was listed is
exactly the information that makes a blocklist easy to evade.

