Onboarding API

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

  1. Create the requisition. Call POST /v3/onboarding/form with the document (CPF or CNPJ), the e-mail and the onboarding type (PF or PJ). For a company (PJ) also send representative_document — the CPF of the legal representative who will perform the liveness. The response returns the onboarding_requisition_id, a liveness_url, liveness_status as PENDING and the access_token.
  2. Store the access token. Save it against the onboarding_requisition_id. Every later call in the journey sends it in the X-Onboarding-Token header.
  3. 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 as representative_document when the requisition was created.
  4. Poll until the liveness passes. Call GET /v3/onboarding/{onboarding_requisition_id} until liveness_status becomes PASSED. At that moment current_step moves from LIVENESS to FORM. If it becomes FAILED, request a new attempt with the liveness retry endpoint.
  5. 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 be true). For PJ, pre-fill the legal representative with representative_document from the status endpoint — that CPF cannot change.
  6. Submit the form and the documents. Call POST /v3/onboarding/{onboarding_requisition_id}/submit with the collected data and the documents encoded in base64. The request is accepted with 202 and the background verification runs asynchronously.
  7. Poll until the journey is finished. Keep calling GET /v3/onboarding/{onboarding_requisition_id} until current_step is DONE. The final outcome is in status_internal: APPROVED or REJECTED.
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:

  1. Read whether an update is due. Call GET /v3/onboarding/registration-update/status with the account holder's Bearer token. can_start is true only when the deadline has already expired and a new update can be started.
  2. Start the update. Call POST /v3/onboarding/registration-update with 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 an onboarding_link.
  3. 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 answers 200 with the same requisition and access_token as null. Treat the token as unrecoverable and contact support for that document.
  • Send it on every later call in the X-Onboarding-Token header: status, form submission, liveness retry and liveness refresh.
  • A missing or wrong token answers 404 Onboarding requisition not found. — the same answer given for an onboarding_requisition_id that 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 200 with the existing requisition and access_token as null. 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}.

StepMeaningWhat your application should do
LIVENESSThe 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.
FORMThe 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.
PROCESSINGThe form was submitted and the verification is running.Keep polling. Nothing else is required from the end user.
REVIEWThe verification finished and the requisition is waiting for the final decision.Keep polling. Show the end user that the registration is under review.
DONEThe 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.

ValueMeaning
PENDINGThe requisition was created and the verification has not started yet.
IN_PROGRESSThe verification is running.
APPROVEDThe verification finished and the requisition passed the automated checks.
REPROVEDThe verification finished and the requisition did not pass the automated checks.
COMPLETEDThe 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.

ValueMeaning
PENDINGThe registration was received and is queued for analysis.
WAITING_APPROVALThe analysis finished and the registration is waiting for the final decision.
APPROVEDFinal outcome: the registration was approved and the account can be opened.
REJECTEDFinal outcome: the registration was rejected.

liveness_status — the status of the proof of life. It is null when the verification never started.

ValueMeaning
PENDINGThe liveness link is open and waiting for the end user. liveness_url is filled only in this state.
PASSEDThe proof of life was approved. The form submission is now allowed.
FAILEDThe 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_url is filled only when liveness_status is PENDING; as soon as the result is known it comes back as null. 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 when liveness_status is FAILED. 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_left on the status endpoint tells you how many are still available; when it reaches 0 no 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_status stays PENDING for longer than expected, call the liveness refresh endpoint. It checks the verification directly and returns enqueued: true when a final result was found and picked up for processing, or enqueued: false when there is nothing new yet.

Available Endpoints

Opening a new account

Liveness operations

Registration update (existing account)

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:

EndpointAuthentication
POST /v3/onboarding/formNo authentication header. Returns the access_token.
GET /v3/onboarding/{onboarding_requisition_id}X-Onboarding-Token header
POST /v3/onboarding/{onboarding_requisition_id}/submitX-Onboarding-Token header
POST /v3/onboarding/{onboarding_requisition_id}/liveness/retryX-Onboarding-Token header
POST /v3/onboarding/{onboarding_requisition_id}/liveness/refreshX-Onboarding-Token header
POST /v3/onboarding/registration-updateAuthorization: Bearer of the account holder
GET /v3/onboarding/registration-update/statusAuthorization: Bearer of the account holder

The headers read by the opening-journey endpoints are:

ParameterTypeDescriptionRequired or OptionalExample
X-Onboarding-TokenStringThe access_token returned when the onboarding requisition was created. Required on every endpoint except the create call.required8Kx2QpN4vR7sT1yW3zA6bC9dE0fG5hJ8kL2mN4pQ
Content-TypeStringMust 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.conditionalapplication/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_at to detect that nothing has changed since the last read.
  • Stop polling as soon as current_step is DONE. That state is final.

Access token

  • Persist the access_token together with the onboarding_requisition_id in 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 (200 on the create call) returns access_token as null — keep the one you stored.

Handling a failed liveness

  • On liveness_status FAILED, check liveness_attempts_left before 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_left is 0, 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_status is PASSED, 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 as RG_FRONT, CNH, PASSPORT and RG_BACK. They are stored as front or back.