Skip to main content
When analysis finishes, a transaction carries one decision and a list of issues explaining it. The decision is what you act on; the issues are why.

The decision

Approved

Every applicable check ran and none rejected. May still carry warnings.

Rejected

At least one check rejected. Every reason is listed.

Undetermined

The analysis could not run. A system condition, not a verdict on the person.
The rule is mechanical and worth memorising: Warnings and informational findings never move the decision. There is no score, no threshold, no grey zone: a single rejecting finding rejects.
Undetermined is not “maybe”. It means the analysis did not complete — a configuration that could not be applied, a malformed session, or a provider failure. Treat it as an operational event: fix the cause if it is yours, retry with a new transaction, and never count it against the user.

Issues

Each finding is an issue with four parts:

Three kinds of issue

Fixed-type issues always have the same type. An expired document is always a rejection; a skipped face comparison on a first transaction is always informational. Policy-driven issues take their type from your configuration. An emulator detection is a rejection if you configured it that way, a warning if you chose that, and is not reported at all if you chose to ignore it. This is how you tune strictness without changing code. Advisory issues tell you about the analysis itself rather than the person: a rule that could not be evaluated because a signal was missing, a configuration that is valid but probably not what you meant, a comparison that was skipped. They are warnings or informational and never block. The full catalogue of codes is in the API Reference under Issue codes.

All checks run to completion

chmod does not stop at the first rejection. If a document is expired and the surname does not match and the device is an emulator, you get all three findings at once. You never have to resubmit to discover the next problem, and your operators see the whole picture on the first look.

Block statuses

Alongside the overall decision, each analysed area reports its own status so you can see where a rejection came from without scanning every code: Device, customer and configuration findings belong to no area. They sit in the issue list and affect the decision directly.

Acting on the result

Group findings by what can be done about them, not by which check produced them:
Cap retries and route fraud signals to a human. An unlimited retry on a manipulated document turns your flow into a testing ground where an attacker learns which forgery passes by trying until one does.

What to show the person

The message on each finding is written for your engineers and operators. It is precise about which check failed — which is exactly what a fraudster wants to know, and more than a genuine user needs. Map codes to your own copy instead: A genuine user with a bad photo gets actionable guidance. A fraudster gets nothing useful.

What to store

Keep the decision, the issue codes, the transaction id and the timestamp. That is enough for your audit trail, your analytics and your support conversations, and it avoids holding the document images and personal data that live inside the full result. Fetch the full result by id when you genuinely need it.