Skip to main content
Onboarding a person takes four calls: create them, then upload a photo ID, a selfie and a proof of address. Everything else is optional.

Create the customer

POST /api/v0/customer with identity fields, the questionnaire and custom fields. The whole payload is validated first — one bad field and nothing is created.
Required fields
Returns 201 with the userId. Save it — every later call uses it.

Upload the photo ID

POST /api/v0/customer/{userId}/documents as multipart/form-data.
Nothing is submitted yet. The response stays SUBMITTED, and missing lists the steps still outstanding:

Upload the selfie

Same endpoint, idDocType=SELFIE.

Upload the proof of address

Same endpoint, idDocType=UTILITY_BILL — a utility bill or bank statement. It is checked against the residential address you sent on create.
This is the last required step, so the customer is submitted for review automatically — status moves to PENDING and missing is omitted:
Submission waits for all three document steps — identity (passport, ID card, driving licence or residence permit), selfie, and proof of address. The customer is submitted once the last of them is uploaded.

Identity fields

Document types

idDocType is validated — a value outside this list returns 400. PASSPORT · ID_CARD · DRIVERS · RESIDENCE_PERMIT · SELFIE · UTILITY_BILL UTILITY_BILL is the proof of address — a utility bill or bank statement. An invalid value is 400 ERRCUS_1406: idDocType must be one of PASSPORT, ID_CARD, DRIVERS, RESIDENCE_PERMIT, SELFIE, UTILITY_BILL.
DRIVERS_LICENSE is now DRIVERS — the value the verification provider expects. DRIVERS_LICENSE is still accepted as an alias so existing integrations keep working, but it is stored and returned as DRIVERS, for example in documents[].docType.
side is not validated. FRONT and BACK are meaningful only for two-sided documents (ID_CARD, DRIVERS). For a passport or selfie it is ignored, and any value — even nonsense — is accepted and passed through.
Files must be JPEG, PNG or PDF, at most 5 MB. Content is sniffed, not trusted by extension: a text file renamed .jpg returns 400.

Hosted verification instead of uploads

If you would rather not handle documents yourself, generate a KYC link and send the customer to it.
The link expires — ttlSeconds is one hour. Requesting one for an already verified customer returns 409 ERRCUS_1603.

Importing an already-verified customer

Pass a shareToken instead of the identity payload. Only email is required alongside it; identity comes from the token. country is validated (ERRCUS_1013), checked against country restrictions (ERRCUS_1605) and stored. firstName and lastName are stored and returned by GET. All other identity fields are ignored and listed in warnings. Note: warnings currently still lists firstName, lastName and country as well. The 201 status on an import is the copied review outcome — COMPLETED, REJECTED or PENDING — not INITIATED.
Request
Share tokens are single-use per partner. Reusing one returns 400. Use a fresh token each time.

Deleting

Delete is a soft delete. The customer stops appearing in listings and a later GET returns 404. The email is released, so the same person can be onboarded again. A customer holding a balance cannot be deleted — that returns 409 ERRCUS_1606, and the amount is never disclosed.