Open an account for an individual or a company by submitting the registration through the API, then keep the registration up to date after the account is active.
The Onboarding API registers a new customer — an individual (PF) or a company (PJ) — so that an account can be opened for them. After the account is active, the same API starts a cadastral update when the registration deadline has expired.
Your application renders its own form. We do not host any screen for the data collection: you decide the layout, the copy and the field order. The only page the end user opens on our side is the liveness link, where the proof of life is captured. Everything else — personal data, company data, partners and document images — reaches us in a single submit call.
Integration Flow
- Create the requisition. Call
POST /v3/onboarding/formwith the document (CPF or CNPJ), the e-mail and the onboarding type (PForPJ). For a company (PJ) also sendrepresentative_document— the CPF of the legal representative who will perform the liveness. The response returns theonboarding_requisition_id, aliveness_url,liveness_statusasPENDINGand theaccess_token. - Store the access token. Save it against the
onboarding_requisition_id. Every later call in the journey sends it in theX-Onboarding-Tokenheader. - Send the end user to the liveness link. Redirect to
liveness_url(or open it in a webview). For a company (PJ) the person who performs the liveness must be the legal representative whose CPF was sent asrepresentative_documentwhen the requisition was created. - Poll until the liveness passes. Call
GET /v3/onboarding/{onboarding_requisition_id}untilliveness_statusbecomesPASSED. At that momentcurrent_stepmoves fromLIVENESStoFORM. If it becomesFAILED, request a new attempt with the liveness retry endpoint. - Render your form and collect the data. With the liveness approved, present your own form: company data (PJ only), the partners, the document images and the acceptance of the terms (
accepted_terms, which must betrue). ForPJ, pre-fill the legal representative withrepresentative_documentfrom the status endpoint — that CPF cannot change. - Submit the form and the documents. Call
POST /v3/onboarding/{onboarding_requisition_id}/submitwith the collected data and the documents encoded in base64. The request is accepted with 202 and the background verification runs asynchronously. - Poll until the journey is finished. Keep calling
GET /v3/onboarding/{onboarding_requisition_id}untilcurrent_stepisDONE. The final outcome is instatus_internal:APPROVEDorREJECTED.
sequenceDiagram
participant EndUser as End User
participant App as Your Application
participant API as Onboarding API
App->>API: POST /v3/onboarding/form (document, email, type, representative_document on PJ)
API-->>App: 201 - liveness_url, liveness_status PENDING, access_token
App->>EndUser: Redirects to the liveness link
EndUser->>API: Records the proof of life
loop Until liveness_status is PASSED
App->>API: GET /v3/onboarding/12345
API-->>App: 200 - liveness_status, current_step
end
App->>EndUser: Renders your own registration form
EndUser->>App: Fills in the data and uploads the documents
App->>API: POST /v3/onboarding/12345/submit
API-->>App: 202 - submitted_at
loop Until current_step is DONE
App->>API: GET /v3/onboarding/12345
API-->>App: 200 - current_step, status_internal
end
App->>EndUser: Shows the final outcome
Registration Update
After the account is open, a cadastral update can be required when the registration deadline has expired. This is a separate flow from opening the account:
- Read whether an update is due. Call
GET /v3/onboarding/registration-update/statuswith the account holder's Bearer token.can_startistrueonly when the deadline has already expired and a new update can be started. - Start the update. Call
POST /v3/onboarding/registration-updatewith the contact e-mail. The document and the PF/PJ type come from the authenticated account — they are not sent in the body. The response carries anonboarding_link. - Send the end user to the link and poll the status endpoint until the update is no longer
IN_PROGRESS.
Do not create a new opening requisition for a document that already went through a registration update. The create call answers 400 and points to this flow.
The Access Token
POST /v3/onboarding/form returns an access_token once and only once — in the body of the 201 response. It is the credential of that single onboarding requisition and it is never returned again by any other endpoint.
- Store it as soon as you receive it, linked to the
onboarding_requisition_id. If you lose it, that requisition can no longer be read or submitted, and creating a requisition again for the same document does not issue a new token — while the requisition is still in progress the create call answers200with the same requisition andaccess_tokenasnull. Treat the token as unrecoverable and contact support for that document. - Send it on every later call in the
X-Onboarding-Tokenheader: status, form submission, liveness retry and liveness refresh. - A missing or wrong token answers
404 Onboarding requisition not found.— the same answer given for anonboarding_requisition_idthat does not exist. This is deliberate: it makes it impossible to discover which requisition ids exist by probing the API. - Re-entry does not return a new token. If you create a requisition for a document that already has an onboarding in progress, the answer is
200with the existing requisition andaccess_tokenasnull. Keep using the token stored from the original creation.
The registration-update endpoints do not use X-Onboarding-Token. They use the Bearer access token of the account holder.
Journey Steps
current_step summarises where the journey is and what your application should do next. It is returned by GET /v3/onboarding/{onboarding_requisition_id}.
| Step | Meaning | What your application should do |
|---|---|---|
| LIVENESS | The proof of life has not been approved yet. | Send the end user to liveness_url and keep polling. If liveness_status is FAILED, request a new attempt. |
| FORM | The liveness passed and the registration form has not been submitted yet. | Render your form, collect the data and the documents, then call the submit endpoint. |
| PROCESSING | The form was submitted and the verification is running. | Keep polling. Nothing else is required from the end user. |
| REVIEW | The verification finished and the requisition is waiting for the final decision. | Keep polling. Show the end user that the registration is under review. |
| DONE | The journey is finished. | Stop polling and read status_internal to know whether the registration was approved or rejected. |
Status Reference
status — the overall status of the onboarding requisition.
| Value | Meaning |
|---|---|
| PENDING | The requisition was created and the verification has not started yet. |
| IN_PROGRESS | The verification is running. |
| APPROVED | The verification finished and the requisition passed the automated checks. |
| REPROVED | The verification finished and the requisition did not pass the automated checks. |
| COMPLETED | The requisition reached the end of its journey. |
status_internal — the outcome of the analysis of the registration. It is null while no decision has been taken.
| Value | Meaning |
|---|---|
| PENDING | The registration was received and is queued for analysis. |
| WAITING_APPROVAL | The analysis finished and the registration is waiting for the final decision. |
| APPROVED | Final outcome: the registration was approved and the account can be opened. |
| REJECTED | Final outcome: the registration was rejected. |
liveness_status — the status of the proof of life. It is null when the verification never started.
| Value | Meaning |
|---|---|
| PENDING | The liveness link is open and waiting for the end user. liveness_url is filled only in this state. |
| PASSED | The proof of life was approved. The form submission is now allowed. |
| FAILED | The proof of life was not approved. A new attempt can be requested while attempts remain. |
The final outcome of the journey is always read from status_internal: APPROVED means the registration was accepted and the account can be opened, REJECTED means it was refused. Both are reported together with current_step as DONE, and neither of them changes afterwards.
Liveness
The liveness is the proof of life of the person responsible for the registration. Your application does not capture it: you send the end user to the liveness_url returned when the requisition is created, and there the end user records a selfie and follows the on-screen instructions. When the verification finishes, the result appears in liveness_status on the status endpoint. For a company (PJ) that person is the legal representative identified by representative_document at creation — the CAF no longer reads an identity document to discover who is on camera.
A few rules worth knowing before you build the screen flow:
- The link is only returned while the verification is pending.
liveness_urlis filled only whenliveness_statusisPENDING; as soon as the result is known it comes back asnull. Do not cache the link expecting it to stay valid after the verification ends. - A new attempt is only possible after a failed one. The liveness retry endpoint opens a fresh verification and returns a new
liveness_url, but only whenliveness_statusisFAILED. Asking for a retry in any other state is rejected. - There are at most 3 attempts in total by default, counting the one opened when the requisition is created.
liveness_attempts_lefton the status endpoint tells you how many are still available; when it reaches0no further attempt can be opened for that requisition. - Refresh is for a verdict that seems stuck. If the end user says the proof of life was completed but
liveness_statusstaysPENDINGfor longer than expected, call the liveness refresh endpoint. It checks the verification directly and returnsenqueued: truewhen a final result was found and picked up for processing, orenqueued: falsewhen there is nothing new yet.
Available Endpoints
Opening a new account
- Create Onboarding Requisition - Create the requisition and receive the liveness link and the access token
- Get Onboarding Requisition Status - Read the current step, the liveness status and the final outcome of the journey
- Submit Onboarding Form - Send the registration data and the documents collected in your own form
Liveness operations
- Retry Liveness - Open a new proof of life attempt after a failed one
- Refresh Liveness - Reconcile a liveness result that has not arrived yet
Registration update (existing account)
- Submit Registration Update - Start a cadastral update when the registration deadline has expired
- Get Registration Update Status - Read whether an update is due, in progress or under review
Authentication
Opening-journey endpoints do not use a Bearer token or an HMAC signature. Access is granted per onboarding requisition, through the token returned when the requisition is created:
| Endpoint | Authentication |
|---|---|
POST /v3/onboarding/form | No authentication header. Returns the access_token. |
GET /v3/onboarding/{onboarding_requisition_id} | X-Onboarding-Token header |
POST /v3/onboarding/{onboarding_requisition_id}/submit | X-Onboarding-Token header |
POST /v3/onboarding/{onboarding_requisition_id}/liveness/retry | X-Onboarding-Token header |
POST /v3/onboarding/{onboarding_requisition_id}/liveness/refresh | X-Onboarding-Token header |
POST /v3/onboarding/registration-update | Authorization: Bearer of the account holder |
GET /v3/onboarding/registration-update/status | Authorization: Bearer of the account holder |
The headers read by the opening-journey endpoints are:
| Parameter | Type | Description | Required or Optional | Example |
|---|---|---|---|---|
| X-Onboarding-Token | String | The access_token returned when the onboarding requisition was created. Required on every endpoint except the create call. | required | 8Kx2QpN4vR7sT1yW3zA6bC9dE0fG5hJ8kL2mN4pQ |
| Content-Type | String | Must be application/json on the create and submit-form calls, which carry a body. Not used by the status, liveness retry and liveness refresh calls, which have no body. | conditional | application/json |
A request with a missing or wrong X-Onboarding-Token answers 404 Onboarding requisition not found., exactly like a request for an id that does not exist. Treat a 404 on a requisition you believe exists as a token problem first.
Best Practices
Polling cadence
- Poll
GET /v3/onboarding/{onboarding_requisition_id}every 3 to 5 seconds while the end user is on the liveness screen — this is the only phase where the end user is actively waiting for the result. - After the form submission, poll every 10 to 30 seconds. The verification runs asynchronously and the result is not immediate.
- Back off progressively and set an upper bound on your polling window instead of polling forever. Use
updated_atto detect that nothing has changed since the last read. - Stop polling as soon as
current_stepisDONE. That state is final.
Access token
- Persist the
access_tokentogether with theonboarding_requisition_idin the same transaction that records the creation. It is returned only once. - Never expose the token to the end user's browser if your form posts through your own backend. Anyone holding it can read and submit that requisition.
- Remember that a re-entry (
200on the create call) returnsaccess_tokenasnull— keep the one you stored.
Handling a failed liveness
- On
liveness_statusFAILED, checkliveness_attempts_leftbefore offering a "try again" button to the end user. - When attempts remain, call the liveness retry endpoint and send the end user to the new
liveness_url. Never reuse the previous link. - When
liveness_attempts_leftis0, stop the journey in your interface and direct the end user to your support channel.
Handling 409 and 412
- 412 on the submit endpoint means the proof of life has not passed yet. Do not retry immediately: go back to polling the status until
liveness_statusisPASSED, then submit again. - 409 on the submit endpoint means the form for that requisition was already submitted. Treat it as a success for the submission step — it typically happens when a request was retried after a network timeout — and move on to polling the status.
Documents
- Send the file content as raw base64, without the
data:prefix. - Keep each decoded file at or below 8 MB, and the whole submission at or below 25 MB decoded. Exceeding either limit answers
413. - Compress or resize the images in your application before encoding them — photographs taken by modern phones easily cross the per-file limit on their own.
- Front and back of an ID can be sent as
IMAGE_FRONT/IMAGE_BACK, or as aliases such asRG_FRONT,CNH,PASSPORTandRG_BACK. They are stored as front or back.
