Identity verification (KYC)

Settlane verifies a customer's identity before it will send them money. This page describes how a merchant drives that from its own server, what each state means, and what stays with an operator.

Identity verification is set up for your account by Settlane. This is switched on per account. Ask [email protected].

The routes

Four routes, under the customers:read and customers:write scopes:

customer.kyc.updated is how you learn a decision was reached. It names the customer (customer_id, external_id), the attempt (verification_id, status) and the customer-level state, so a handler need not re-derive "verified" from an attempt. The API reference lists every field, and describes the event's payload under webhooks.

What stays with an operator, on the dashboard's Customers and Compliance screens: resolving a needs_review attempt, reopening a customer who has used up their attempts, and blocking a customer. A blocked customer can still be read — the KYC read answers retry.blocked_by: customer_blocked — and a verification or a payout for one is refused CUSTOMER_BLOCKED.

The flow

  1. Your server starts a verification for one customer. Pass return_url (where the customer's browser lands afterwards) and, if you hold one, expected_date_of_birth: it is compared with the document and then discarded.
  2. The customer completes the hosted check — a document and a liveness check — at hosted_url.
  3. The provider decides, and Settlane applies its own rules on top of that decision: the date of birth must match what was expected, the age gate must pass, and a duplicate or an AML hit is not an approval. A provider approved that fails one of Settlane's own rules is not an approved verification; it waits for a person as needs_review.
  4. customer.kyc.updated fires with the outcome.
  5. Payouts to that customer become possible, or do not.

The states

StatusWhat it means
pendingThe session exists and the customer has not finished it. decided_at is null exactly while this is the status.
approvedThe provider approved it and every rule Settlane applies afterwards passed.
declinedTerminal for this attempt. A retry is a new verification, subject to the cool-down and the attempt cap.
needs_reviewA human has to decide. Nothing about the customer changes until they do.
expiredThe provider session expired unused.
abandonedThe customer started and never came back.

Those are an attempt's statuses. The customer's state on GET /v1/customers/{id}/kyc is one of verified, pending, needs_review, declined, not_started and unavailable (no provider is configured for your tenant), derived from the latest decided attempt and whether one is pending. latest_verification is that attempt — the row the state was derived from, expired and abandoned included — so the two can never disagree. decided_at is null exactly while the status is pending — the database enforces that equality.

Retries, and the limits on them

A declined verification can be retried, and the limits exist so an attempt cannot be brute-forced:

retry on the KYC read says which applies and, for the cool-down, when it ends; customer_blocked is the fourth value, for a customer an operator has blocked.

The document's date of birth

Settlane stores no date of birth. A merchant that needs the document's one — to fill a date of birth it never collected, say — reads it once with GET /v1/verifications/{id}?include=document_dob: it is fetched live from the provider's decision, every such read is audited against your key and counts against the key's create budget, and once the provider session has been deleted (after your endpoint acknowledged customer.kyc.updated, at most seven days later) the read answers VERIFICATION_DOCUMENT_GONE. Only a decided attempt (approved, declined, needs_review) has a document to read: an undecided one, a simulated one (test mode without a sandbox application) or a decision that carries no date of birth answers the attempt without the field.

Test mode

A sk_test_ key verifies against the provider's sandbox when your tenant has one configured, and otherwise against a built-in simulator whose outcome is chosen by the external_id suffix — …_approved, …_declined, …_review. Today a simulated verification stays pending: the part of Settlane that resolves it runs in live mode only, for now.

What a check costs. Each verification that reaches a decision in live mode — approved, declined or sent for review — is billed at your workspace's per-check price, which is on your monthly statement. Sandbox and simulated checks, and attempts that expire or are abandoned, cost nothing.

Verifications you ran before Settlane can be imported, not redone: an operator imports your earlier provider decisions for your live customers (matched by your external_id), and an imported approval counts as a live verification exactly as one made through Settlane does. Imported decisions are never billed and never count against the attempt limit; a person whose attempt was still pending simply starts again here.

A sandbox or simulator result can never satisfy a live verification. Settlane refuses to cross modes here, both in the API and in its database.

Fail-closed, always

Every configuration failure refuses rather than skipping the check:

CodeState
IDENTITY_VERIFICATION_UNAVAILABLEThe tenant's provider credentials are missing, incomplete or disabled.
IDENTITY_PROVIDER_FAILEDThe provider threw or answered non-2xx. Retry; nothing about the customer changed.
IDENTITY_PROVIDER_SCHEMA_UNVERIFIEDSettlane cannot read the provider's decisions safely right now, so it decides nothing. Retry later, and contact support if it lasts.

Next