Skip to main content
Backend and flow-level problems are covered here. For SDK-specific symptoms — crashes, permissions, build errors — see the troubleshooting sections on iOS and Android.

Authentication

The access token is missing, invalid or expired. Confirm you are sending it as a bearer token in the Authorization header and that it is under an hour old. When it expires, request a new one and retry.
Check the four form fields exactly: grant_type=client_credentials, your client_id, your client_secret, and scope=account-integration-api/account-api-access. The body must be application/x-www-form-urlencoded, not JSON.

Creating transactions

The error field names the field and the constraint. The usual suspects: a time limit outside 1–1440 minutes, a score outside 0.1–1.0, an age outside 0–200, or a webhook URL that is not https://. Nothing is created on a 400. See Errors.
Almost always a base URL mismatch: the token was minted against one host and the SDK is pointed at another, or at the OAuth host instead of the API host. The SDK’s base URL is the same API host your backend calls.
The token lives as long as the transaction’s time limit. If your app fetches a token and holds it before launching the flow, a short limit can expire in between. Mint the token when the user taps the button, not at app start.
You cannot. Configuration is fixed at creation. Create a new transaction — the old one will expire on its own.

Results

Check the findings. If you are testing on a simulator or emulator, you are hitting emulator detection, which rejects by default. Set that rule to ignore while you test on emulators — and make sure the configuration your real users get does not inherit that.
It is waiting on the user, not on chmod. Initiated means the SDK opened a session and the person has not finished capture. It will move to expired when the time limit runs out. If users are consistently stuck here, they are abandoning inside the flow — look at the SDK’s welcome screen, permission prompts and document guidance.
Read the findings. A configuration code means your rules could not be applied: fix them and create a new transaction. An engine code means a provider failure: retry with a new transaction, and alert if it keeps happening. Never treat undetermined as a rejection of the user.
This is the customer’s first transaction. There is no enrolled face yet, so the comparison against it cannot run. It is informational, it is expected, and the face captured now becomes the reference for next time. If you see it on a customer who should have history, you are probably creating a new customer per verification.
On a customer with no enrolled face, a biometric-only verification only proves a live person was present — it cannot prove who. Require a completed document-and-biometric verification before allowing biometric-only for that customer. See Verification types.
Your similarity threshold is too high, or you are matching against a name with a middle name the document omits (or vice versa). Documents print names uppercase and unaccented. 0.85 absorbs that; 1.0 does not. The finding’s details.score tells you how close each failure was.
Your accepted-documents list does not include that exact country and type. Check the filter mode too: under ALLOW, only listed documents pass. If the code is DOCUMENT_TYPE_NOT_SUPPORTED instead, chmod does not support that document at all — see the supported documents table.

Webhooks

In order: was the webhook set on the transaction? Is the URL HTTPS and reachable from the public internet (not localhost, not behind your VPN)? Is your endpoint returning a success status? See Webhooks.
The signed string is exactly the timestamp header value, a colon, and the transaction id from the body. No spaces, no newline, no re-formatting of the timestamp. Make sure you are verifying against the keys published on the same host that sent the webhook.
Expected. Delivery is at-least-once. Key your handler on the transaction id plus status and make repeats a no-op.

Frequently asked

No. It means the user finished the capture flow. The decision is produced afterwards and reaches your backend by webhook or by fetching the transaction. Show “we’re reviewing your document” at completed.
No. The app holds only the SDK token, which the SDK uses for its own session calls. Everything else — creating customers and transactions, reading results — is your backend, with credentials that never leave your server.
No. Transactions are single-use and terminal states are final. A retry is a new transaction for the same customer. That is cheap, and it keeps every attempt auditable.
Seventeen Latin American countries, with national ID, passport and driver licence in each, plus resident and temporary permits for Colombia. The full matrix is in Document policy.
A biometric-only verification runs a liveness check with no document. On a customer who already completed a document-and-biometric verification, it also confirms they are the same person. On a brand-new customer it proves only that a live human was present.
Normally seconds after the user finishes capture. If a transaction sits in processing for more than a couple of minutes, contact support with the transaction id.
Your account manager, or the support link in the navigation. Include the transaction id, the exact error message or finding codes, and the time in UTC.