Skip to main content
A transaction is the unit of work in chmod. It is created by your backend, carried out by the SDK on the user’s device, analysed by chmod, and read back by your backend.

Customers and transactions

A customer is a person. You create one the first time you verify someone and reuse the same customer_id for every later transaction. This matters more than it looks. On the first transaction there is no enrolled face to compare against, so chmod records one. On every transaction after that, the new selfie is compared against that enrolled face, and the extracted document data is checked against what the customer’s earlier documents said. A customer whose date of birth suddenly changes is a signal you only get if you reuse the id.
Creating a fresh customer for every verification throws that history away. Store customer_id against your own user record and reuse it.
A transaction is one verification attempt. It carries its own configuration, so two transactions for the same customer can enforce entirely different rules.

Transaction lifecycle

A transaction that reaches FINISHED or FAILED is terminal. To try again, create a new transaction for the same customer.

The decision

Once analysis completes, result_data.decision is one of three values:

APPROVED

Every applicable check ran and none of them rejected.

REJECTED

At least one check rejected. Every reason is in issues[].

UNDETERMINED

The analysis could not run — a malformed request, an invalid configuration or a provider failure. Not a risk verdict.
UNDETERMINED means exactly one thing: nothing could be concluded. It is not a grey zone between approved and rejected. If the analysis ran at all, the answer is APPROVED or REJECTED.

What gets checked

The transaction type decides which families of checks apply. 1 Only when the customer already has an enrolled face. On a first transaction the comparison is skipped — it is not a rejection — and an informational FACE_COMPARISON_SKIPPED_NO_REFERENCE issue is emitted. All applicable checks always run to completion. chmod does not stop at the first rejection, so issues[] lists every problem at once rather than making you resubmit to discover the next one.

Getting the result

Two ways, and they are not exclusive:

Webhook

chmod calls the URL in your transaction config as soon as the decision exists. Signed, so you can verify it came from us.

Polling

Fetch the transaction whenever you want. Useful as a fallback and for reconciliation.
Use the webhook as the trigger and the fetch as the source of truth: the webhook tells you a decision is ready, and the GET gives you the full result to act on.