Skip to main content

Account Opening — Individuals (PF)

This guide walks through opening an individual account using the default CorpX biometrics flow: we generate a facial capture link, you deliver it to the end user, and once the facial check is approved the account is opened automatically — no manual review.

Flow

Step 1: Create the accreditation

Request

curl -X POST "https://tenant.api.corpx.com/v1/accreditations/pf" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: onboard-customer-12345" \
-d '{
"person": {
"name": "Maria da Silva",
"cpf": "12345678901",
"birthDate": "1990-05-20",
"email": "maria@email.com",
"phone": "+5511999998888",
"monthlyIncome": 5000.00
},
"address": {
"zipCode": "01310100",
"street": "Avenida Paulista",
"number": "1000",
"complement": "Apto 42",
"neighborhood": "Bela Vista",
"city": "São Paulo",
"state": "SP",
"cityIbgeCode": "3550308"
}
}'

Parameters

FieldTypeRequiredDescription
person.namestringYesHolder's full name.
person.cpfstringYesCPF (11 digits, no punctuation).
person.birthDatestringYesBirth date (YYYY-MM-DD).
person.emailstringYesHolder's email.
person.phonestringYesPhone in DDI + area code + number format (e.g. +5511999998888).
person.monthlyIncomenumberNoDeclared monthly income (BRL).
address.*objectYesFull address. neighborhood is required (or legacy district). cityIbgeCode is the 7-digit IBGE city code.
biometryobjectNoOnly for the Bring Your Own biometrics flow.
callbackUristringNoWhere to take the holder back to at the end of the journey. Requires prior registration with support — see Returning to your app.

Initial PIX limits are applied automatically with conservative defaults. Limit changes (increase or decrease) require a manual request to support.

Response (201)

{
"accreditationId": "acr_9f8e7d6c5b4a",
"type": "pf",
"status": "PENDING_BIOMETRY",
"persons": [
{
"personId": "prs_3b1c9a7f2e4d",
"cpf": "12345678901",
"name": "Maria da Silva",
"biometryStatus": "PENDING",
"biometryLink": "https://cadastro.unico.app/process/abc123...",
"linkExpiresAt": "2026-07-14T18:00:00Z"
}
],
"createdAt": "2026-07-07T18:00:00Z"
}

The personId is the person's stable identifier within the accreditation. Use it to correlate the return to your app (see Returning to your app) — it is the personId, not the CPF, that appears in the return URI.

Account not bound yet

While status is PENDING_BIOMETRY, the CPF is not bound to the tenant and accountId does not exist yet. POST does not deduplicate — repeating with the same CPF creates another accreditation. Store the accreditationId and cancel abandoned pendings with POST /v1/accreditations/{id}/cancel. The accountId appears only after biometry is confirmed (accreditation.updated / accreditation.active webhooks).

Asynchronous link

The biometryLink is issued within seconds, but asynchronously — in rare cases it may be absent from the POST response. When that happens, receive it via the accreditation.biometry.link.created webhook or call the GET right after.

CPF that already has an account

If the CPF is already an account holder and your tenant has automatic portability enabled, the response comes back with status: "PENDING_CONSENT" and a consentLink instead of the biometryLink — there is no new account to open, but rather an authorization from the holder for you to operate the account they already have. Without that enablement (the default), the accreditation fails with existing_partner_account and portability goes through support. See Holder who already has an account below.

Deliver the biometryLink to the end user through your preferred channel (inside your app, WhatsApp, SMS, email). The capture journey runs in the phone's browser, no app installation required.

  • The link expires in 7 days (linkExpiresAt). If it expires, use the retry endpoint (Step 4).
  • The same link is also delivered in the accreditation.biometry.link.created webhook.

Step 3: Wait for completion

Once the user completes the capture and the biometrics are approved, approval is automatic — there is no manual review for PF in the default flow. Track it through webhooks:

  1. accreditation.updatedPENDING_BIOMETRYINTEGRATING;
  2. accreditation.active — account opened; the accountId is ready to operate.

If the biometrics are rejected or expire, you receive accreditation.updated with the person's details and can retry.

You can also poll:

curl -X GET "https://tenant.api.corpx.com/v1/accreditations/pf?document=12345678901" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany"
{
"items": [
{
"accreditationId": "acr_9f8e7d6c5b4a",
"accountId": "c283eb5a-58da-47ef-844a-f36e51f078d8",
"type": "pf",
"status": "ACTIVE",
"persons": [
{
"cpf": "12345678901",
"name": "Maria da Silva",
"biometryStatus": "APPROVED"
}
],
"createdAt": "2026-07-07T18:00:00Z",
"updatedAt": "2026-07-07T18:25:41Z"
}
]
}

If the link expired or the capture failed, generate a new link for the person:

curl -X POST "https://tenant.api.corpx.com/v1/accreditations/acr_9f8e7d6c5b4a/persons/12345678901/retry" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany"

The response carries the new biometryLink and the new linkExpiresAt. The accreditation.biometry.link.created event is also re-emitted.

Step 5: Cancel (abandoned pending)

If the user abandoned before biometry, cancel the accreditation while status is PENDING_BIOMETRY (or PENDING_CONSENT):

curl -X POST "https://tenant.api.corpx.com/v1/accreditations/acr_9f8e7d6c5b4a/cancel" \
-H "Authorization: Bearer {token}" \
-H "X-Tenant-Id: tenant-yourcompany" \
-H "Content-Type: application/json" \
-d '{"reason":"customer abandoned onboarding"}'

It ends as FAILED with errorReason=cancelled (accreditation.updated / accreditation.failed webhooks). After biometry is confirmed, cancel is no longer allowed (409 invalid_state).

When the CPF is already an account holder, there is no new account to open. The path becomes the holder authorizing you to operate the account they already have — and that authorization is given by them, on a page hosted by us, with identity verification.

The POST /v1/accreditations/pf call is the same: you do not need to detect anything beforehand. What changes is the response.

Requires contractual enablement

Automatic portability is not enabled by default. It transfers control over the money in an account that already exists, so it depends on a specific contract and is enabled per tenant by our team.

Without it, a CPF that already has an account still ends in FAILED with errorReason=existing_partner_account and the message instructing the holder to request portability from support — in that case we run the process manually and no consentLink is issued.

To enable it, talk to your CorpX account contact.

{
"accreditationId": "acr_5c4b3a2f1e0d",
"type": "pf",
"status": "PENDING_CONSENT",
"persons": [
{
"personId": "prs_3b1c9a7f2e4d",
"cpf": "12345678901",
"name": "Maria da Silva",
"biometryStatus": "PENDING",
"consentStatus": "PENDING",
"consentLink": "https://tenant.api.corpx.com/v1/accreditations/consent/cst_...",
"consentExpiresAt": "2026-07-30T18:00:00Z"
}
],
"createdAt": "2026-07-23T18:00:00Z"
}
FieldDescription
statusPENDING_CONSENT — waiting for the holder's authorization.
persons[].consentLinkAuthorization page. Deliver it to the holder just like you already deliver the facial link.
persons[].consentStatusPENDING, ACCEPTED, DECLINED, DENIED or EXPIRED.
persons[].consentExpiresAtLink expiry (7 days). The journey as a whole expires in 30 days.

The same link arrives in the accreditation.consent.link.created webhook — subscribe to that event if your integration picks links up from webhooks, because accreditation.updated carries no link at all.

Re-posting does not reissue the consent

While the journey is in PENDING_CONSENT, repeating POST /v1/accreditations/pf for the same CPF answers 409 already_accredited — with accountId: null, status: "PENDING_CONSENT" and the accreditationId of the journey already in progress. It is not an existing account in your tenant: it is the authorization still pending with the holder.

To recover the link instead of re-posting:

  • GET /v1/accreditations/{accreditationId} returns the current link in persons[].consentLink, along with consentExpiresAt.
  • POST /v1/accreditations/{accreditationId}/persons/{cpf}/retry reissues the link with a fresh 7-day validity (the same endpoint as Step 4), as long as the 30-day journey has not expired.

If you really mean to abandon the journey, cancel it with POST /v1/accreditations/{accreditationId}/cancel (Step 5) before creating another one.

Flow

What the holder sees

  1. Before any capture, the page states who is requesting access and what the authorization allows — including moving and withdrawing the money in the account.
  2. Identity verification: a live selfie checked against official records by CPF. The page does not move forward without it.
  3. Only after the identity is confirmed do the account number and current balance appear — so the holder authorizes knowing exactly which money you will be operating.
  4. Explicit authorization, recorded with date, time, device and the balance that was disclosed.

The authorization is only valid in the same session and on the same device that went through the identity verification. Forwarding the link to someone else, replaying the page's POST or reusing an older verification authorizes nothing.

After the authorization

You receive accreditation.active with sharedAccount: true and an accountId to operate normally. Two important points:

  • It is the same account, not a copy: balance, statement and Pix keys are the ones that already existed. The accountId is that account's identifier within your tenant.
  • Whoever already operated the account keeps operating it. Every tenant authorized by the holder receives the webhooks for each movement — including those for operations that did not originate from your API (which arrive with external: true).

If the holder does not authorize, the accreditation ends as FAILED with one of these errorReason values: consent_declined, consent_expired, consent_facial_failed, castle_deny or consent_link_failed (details in Onboarding Webhooks).

Revocation

The holder can revoke a granted access at any time through support. From then on, the revoked tenant's calls for that account return 403 — the account stays active for the holder and for the other authorized tenants.

Account ready

With status ACTIVE, the account is bound to your tenant and ready to operate. Use the accountId on all other API endpoints — PIX, statement, boletos, QR Codes, etc.

tip

Store the accreditationId + accountId pair in your system. The accountId is the identifier you will use for every banking operation from then on.