Fluxo passo a passo de abertura de conta digital — atende PF (CPF) e PJ (CNPJ + sócios), com integração Dock, KYC via Unico SDK, convite multicanal para sócios e webhooks de progresso.
Este guia explica exatamente como abrir uma conta digital na Autra, chamada por chamada. A API atende dois tipos de pessoa:
- PF — pessoa física (CPF). Quem está abrindo conta no próprio nome.
- PJ — pessoa jurídica (CNPJ + sócios). Empresas, MEIs, etc.
Os dois fluxos compartilham a maior parte dos endpoints. Só os passos que dependem do tipo (preencher CPF x preencher CNPJ + sócios, e o disparo do processo) são diferentes.
Provedor BaaS: Dock. Você não fala com a Dock — só com a API da Autra. Nós orquestramos.
Antes de começar — checklist
- Você tem
client_id+client_secretda Autra. - Você sabe gerar um Bearer JWT via
POST /v1/oauth/token?grant_type=client_credentials(rotaAuthentication, headerAuthorization: Basic base64(client_id:client_secret)). - Você decidiu se vai abrir conta PF ou PJ.
- Frontend: você tem device_id (UUID) do dispositivo que vai fazer o KYC.
- Frontend: você integrou (ou vai integrar) o SDK Unico para captura da selfie + documento de identificação (RG / CIN / CNH / RNE / Passaporte).
- (PJ) Você sabe quem é o master — sócio responsável pelo onboarding.
- (PJ) Você sabe quem são os outros sócios e como vai contatá-los (email/WhatsApp).
Resumo dos endpoints — PF x PJ
| # | Etapa | PF | PJ |
|---|---|---|---|
| 1 | Criar proposta | POST /onboarding | POST /onboarding |
| 2 | Buscar termos | GET /onboarding/{id}/terms | GET /onboarding/{id}/terms |
| 3 | Aceitar termos | POST /onboarding/{id}/terms/accept | POST /onboarding/{id}/terms/accept |
| 4 | Salvar dados | PUT /onboarding/{id}/personal-data | PUT /onboarding/{id}/legal-entity |
| 5 | Sócios | — (não tem) | POST /onboarding/{id}/partners (1+ vezes) |
| 6 | Convidar sócios | — | POST /onboarding/{id}/partners/{partnerId}/invite |
| 7 | Sócio convidado preenche | — | PUT /onboarding/invite/{token}/personal-data (público) |
| 8 | Iniciar processo Dock | POST /onboarding/{id}/start | POST /onboarding/{id}/start-pj |
| 9 | Pollar arquivos pendentes | GET /onboarding/{id}/files/pending | GET /onboarding/{id}/files/pending |
| 10 | Upload selfie + doc identificação | POST /onboarding/{id}/files | POST /onboarding/{id}/files/pj/partners/{partnerId} |
| 11 | Upload docs empresa | — | POST /onboarding/{id}/files/pj/company |
| 12 | Marcar uploads completos | POST /onboarding/{id}/files/complete | POST /onboarding/{id}/files/complete |
| 13 | Pollar status final | GET /onboarding/{id} | GET /onboarding/{id} |
Todas as rotas usam o prefixo
https://api.autra.io/v1/banking. Headers obrigatórios em rotas privadas:Authorization: Bearer <JWT>,Content-Type: application/json.
State machine (estados da proposta)
A proposta passa por estados. Você só avança chamando o endpoint certo no estado certo. Se errar, recebe 409 INVALID_STATUS.
DRAFT
└─► TERMS_ACCEPTED
│
│ (PF)
├─► PERSONAL_DATA_FILLED
│ └─► PROCESS_STARTED
│ └─► FILES_PENDING
│ └─► FILES_UPLOADED
│ └─► PROCESSING
│ └─► COMPLETED | DECLINED | WAITING_*
│
│ (PJ)
└─► LEGAL_ENTITY_FILLED
└─► PARTNERS_PENDING (algum sócio incompleto/INVITED)
└─► PARTNERS_READY (todos sócios READY + 1 master)
└─► PROCESS_STARTED
└─► FILES_PENDING
└─► FILES_UPLOADED
└─► PROCESSING
└─► COMPLETED | DECLINED | WAITING_*
Estados terminais: COMPLETED · DECLINED · CANCELED · FAILED
Regra de ouro: o backend é fonte de verdade. Sempre cheque o status na resposta antes de chamar o próximo endpoint.
🟦 Fluxo PF — passo a passo
PF — Passo 1: Criar a proposta
POST /v1/banking/onboarding
Authorization: Bearer <JWT>
Content-Type: application/json
Idempotency-Key: pf-jorge-2026-05-01
{ "type": "PF" }Resposta 201:
{ "id": "0193b5a1-...", "type": "PF", "status": "DRAFT", ... }✅ Guarde o id — você vai usar em todas as chamadas seguintes. ✅ Idempotency-Key garante que se a chamada falhar e você reenviar com a mesma chave, a mesma proposta volta (não cria duplicada).
PF — Passo 2: Buscar os termos vigentes
GET /v1/banking/onboarding/{id}/terms
Authorization: Bearer <JWT>Resposta 200:
{
"tou": { "token": "tou-abc...", "title": "Termos de Uso", "url": "https://..." },
"privacy": { "token": "pp-xyz...", "title": "Política de Privacidade", "url": "https://..." }
}✅ Mostre os textos para o usuário ler. Guarde os 2 tokens (tou.token e privacy.token).
PF — Passo 3: Aceitar os termos
POST /v1/banking/onboarding/{id}/terms/accept
Authorization: Bearer <JWT>
{
"tou_token": "tou-abc...",
"pp_token": "pp-xyz...",
"fingerprint": "Mozilla/5.0 (iPhone)#187.45.32.10"
}Resposta 200: status: TERMS_ACCEPTED.
✅ O fingerprint é uma string livre — recomendamos <UserAgent>#<IP> para auditoria.
PF — Passo 4: Salvar dados pessoais
PUT /v1/banking/onboarding/{id}/personal-data
Authorization: Bearer <JWT>
{
"personal_data": {
"full_name": "Jorge Augusto Silva",
"cpf": "39053344705",
"birth_date": "1985-03-10",
"mother_name": "Maria da Silva",
"email": "[email protected]",
"phone": { "area_code": "11", "number": "914052149" }
},
"address": {
"zip_code": "06404250",
"suffix": "Avenida",
"street": "Anápolis",
"number": "100",
"neighborhood": "Alphaville",
"city": "Barueri",
"state": "SP"
}
}Resposta 200: status: PERSONAL_DATA_FILLED.
⚠️ Validamos: CPF (check digits), idade ≥ 18, CEP, formato de email.
PF — Passo 5: Iniciar processo na Dock
POST /v1/banking/onboarding/{id}/start
Authorization: Bearer <JWT>
{
"device_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"device_alias": "iPhone do Jorge",
"device_model": "iPhone 15",
"operating_system": "iOS 18",
"ip_address": "187.45.32.10"
}Resposta 200:
{
"status": "PROCESS_STARTED",
"process_instance_id": "abc-123",
"dock_proposal_id": "def-456",
"sdk_key": "eyJhbGciOi..."
}✅ Guarde o sdk_key — é o token efêmero do Unico SDK que você vai usar para capturar a selfie no app.
⚠️ A partir daqui, a Dock está processando. Não chame /start de novo (é idempotente, mas é desnecessário). Vá pro passo 6.
PF — Passo 6: Esperar liberação para upload (polling)
A Dock leva alguns segundos para liberar o estágio de upload. Pollar até receber 200:
GET /v1/banking/onboarding/{id}/files/pending
Authorization: Bearer <JWT>202→ ainda processando. Aguarde ~2s e tente de novo.200→ liberado. Resposta:
{
"proposal": { ... },
"files": [
{ "file_side": "SELFIE" },
{ "file_side": "IDENTITY_CARD_FRONT" },
{ "file_side": "IDENTITY_CARD_VERSE" }
],
"groups": [
{
"file_type": "BIOMETRIC_FILE",
"options": [
{ "category": "SELFIE", "label": "Selfie", "sides": ["SELFIE"] }
]
},
{
"file_type": "IDENTIFICATION_FILE",
"options": [
{ "category": "IDENTITY_CARD", "label": "RG", "sides": ["IDENTITY_CARD_FRONT", "IDENTITY_CARD_VERSE"] },
{ "category": "DRIVER_LICENSE", "label": "CNH", "sides": ["DRIVER_LICENSE_FRONT", "DRIVER_LICENSE_VERSE"] },
{ "category": "DIGITAL_DRIVER_LICENSE", "label": "CNH Digital", "sides": ["DIGITAL_DRIVER_LICENSE"] },
{ "category": "RNE", "label": "RNE", "sides": ["RNE_FRONT", "RNE_VERSE"] },
{ "category": "PASSPORT", "label": "Passaporte", "sides": ["PASSPORT"] }
]
}
]
}Como o app escolhe o tipo de documento:
groups[].file_type = "BIOMETRIC_FILE"é sempre obrigatório (1 opção: SELFIE).groups[].file_type = "IDENTIFICATION_FILE"traz N opções — o app deve mostrar pro usuário uma escolha (RG, CIN, CNH, CNH Digital, RNE, Passaporte) e enviar todos ossidesda opção escolhida viaPOST /files.- O campo legacy
files[]continua existindo, mas pega só a 1ª opção (sempre RG). Usegroups[]no app moderno pra dar a escolha pro usuário.
CIN (Carteira de Identidade Nacional, novo modelo 2022) entra na mesma categoria que o RG:
IDENTITY_CARDcom sidesIDENTITY_CARD_FRONT+IDENTITY_CARD_VERSE. A Dock não diferencia. No app, você pode mostrar "CIN" e "RG" como opções separadas (UX) e enviar usando os mesmos sides.
✅ Use backoff exponencial: 2s → 4s → 8s, máx 30s entre tentativas. Total: até 2min.
Dica: se você assina o webhook
process_files_receives_started, evita polling. O backend te avisa.
PF — Passo 7: Upload da selfie e do documento de identificação
Para cada file_side da opção escolhida no passo 6 (mais a selfie):
POST /v1/banking/onboarding/{id}/files
Authorization: Bearer <JWT>
{
"file_side": "SELFIE",
"jwt": "<JWT do Unico SDK obtido no app>"
}POST /v1/banking/onboarding/{id}/files
Authorization: Bearer <JWT>
{
"file_side": "IDENTITY_CARD_FRONT",
"base64": "<base64 da imagem capturada pelo SDK Unico>",
"jwt": "<JWT do Unico SDK>"
}Mapeamento file_side por tipo de documento (extraído do groups[] do passo 6):
| Documento | file_side (uma chamada por lado) |
|---|---|
| Selfie | SELFIE (sempre obrigatório, vai em jwt) |
| RG / CIN | IDENTITY_CARD_FRONT + IDENTITY_CARD_VERSE |
| CNH física | DRIVER_LICENSE_FRONT + DRIVER_LICENSE_VERSE |
| CNH digital | DIGITAL_DRIVER_LICENSE (1 arquivo único — PDF/JPG do app oficial) |
| RNE | RNE_FRONT + RNE_VERSE |
| Passaporte | PASSPORT (foto da página de identificação) |
Regras importantes:
- Selfie vai no campo
jwt(vem direto do SDK Unico, é JWT que carrega a imagem + liveness). - Documentos vão no campo
base64(mais ojwtdo SDK quando capturados via Unico). Para CNH digital exportada do app, é o conteúdo do arquivo em base64. - Frente e verso são chamadas separadas — uma
POST /filespor lado. - O backend repassa o JWT/base64 pra Dock; nada é validado/transformado no nosso lado.
PF — Passo 8: Marcar uploads como completos
POST /v1/banking/onboarding/{id}/files/complete
Authorization: Bearer <JWT>Resposta 200: status: FILES_UPLOADED.
⚠️ Pré-condição: todos os arquivos do passo 6 enviados. Se faltar, retorna 409 FILES_INCOMPLETE.
PF — Passo 9: Aguardar aprovação
GET /v1/banking/onboarding/{id}
Authorization: Bearer <JWT>Pollar (ou usar webhooks) até status virar:
COMPLETED→ aprovado! A resposta incluiaccountcombank,agency,numberda nova conta.DECLINED→ reprovado.WAITING_CORRECTION→ algum arquivo precisa ser refeito. Use o blocoanalysis(abaixo) para saber quais. Volte ao passo 7.WAITING_MANUAL_ANALYSIS→ mesa manual da Dock. Aguarde (pode levar horas).FAILED→ erro permanente. Olast_error.codeindica a causa (DOCK_PROCESS_EXPIREDquando a Dock fechou por timeout — proposta precisa ser refeita).
✅ Pronto. Conta aberta. Você pode emitir extrato, transferir, etc.
Quando arquivos são rejeitados — analysis.resend_files
analysis.resend_filesSempre que a Dock devolve um diagnóstico (em WAITING_CORRECTION, DECLINED ou FAILED por arquivos rejeitados), a resposta de GET /onboarding/{id} inclui dois blocos prontos pro frontend orientar o usuário.
Funciona pra PF e PJ
A estrutura é a mesma nos dois fluxos, mas em PJ cada arquivo rejeitado vem identificado com subject_type + subject_name — porque a rejeição pode estar na empresa OU em qualquer um dos sócios. Use isso pra mostrar "Reenvie a selfie do João" vs "Reenvie o contrato social da empresa".
last_error — mensagem amigável
last_error — mensagem amigávelPF:
"last_error": {
"code": "DOCK_FILES_DECLINED",
"message": "Arquivos rejeitados pela análise. Envie novamente: RG (verso) de Fernando, selfie de Fernando, RG (frente) de Fernando.",
"occurred_at": "2026-05-05T11:05:47Z"
}PJ:
"last_error": {
"code": "DOCK_FILES_DECLINED",
"message": "Arquivos rejeitados pela análise. Envie novamente: contrato social da empresa, selfie de João, RG (frente) de Maria."
}Use last_error.message direto como banner — já está em PT-BR, cita os arquivos pelos nomes amigáveis e identifica o dono.
analysis — diagnóstico estruturado (exemplo PF)
analysis — diagnóstico estruturado (exemplo PF)"analysis": {
"files_status": "DECLINED",
"files_reason_code": "17",
"data_result": "APPROVED",
"data_info": "Data analysis approved.",
"resend_files": [
{
"file_side": "IDENTITY_CARD_VERSE",
"label": "RG (verso) de Fernando",
"proposal_person_id": "019df4c9-ed05-6a4e-aa59-695a917f34c4",
"subject_type": "PARTNER",
"subject_name": "fernando roberto de paula"
},
{ "file_side": "SELFIE", "label": "selfie de Fernando", "proposal_person_id": "019df4c9-ed05-...", "subject_type": "PARTNER", "subject_name": "fernando roberto de paula" }
],
"invalid_files": [
{
"file_type": "IDENTIFICATION_FILE",
"file_category": "IDENTITY_CARD",
"file_side": "IDENTITY_CARD_VERSE",
"status": "INVALID",
"proposal_person_id": "019df4c9-ed05-...",
"subject_type": "PARTNER",
"subject_name": "fernando roberto de paula",
"subject_document": "26924591809"
}
]
}analysis — diagnóstico estruturado (exemplo PJ)
analysis — diagnóstico estruturado (exemplo PJ)"analysis": {
"files_status": "DECLINED",
"resend_files": [
{
"file_side": "ARTICLES_OF_ASSOCIATION",
"label": "contrato social da empresa",
"proposal_person_id": "019d-empresa-uuid",
"subject_type": "COMPANY",
"subject_name": "ACME Tecnologia LTDA"
},
{
"file_side": "SELFIE",
"label": "selfie de João",
"proposal_person_id": "019d-joao-uuid",
"subject_type": "PARTNER",
"subject_name": "João da Silva"
},
{
"file_side": "IDENTITY_CARD_FRONT",
"label": "RG (frente) de Maria",
"proposal_person_id": "019d-maria-uuid",
"subject_type": "PARTNER",
"subject_name": "Maria Costa"
}
]
}| Campo | Como usar |
|---|---|
analysis.resend_files[] | Lista pronta pro front — itere e mostre "Reenvie estes documentos: ..." usando label. |
analysis.resend_files[].subject_type | "COMPANY" ou "PARTNER". Use pra agrupar a UI: 1 cartão pra empresa, 1 cartão por sócio. |
analysis.resend_files[].subject_name | Nome do sócio (ou razão social) — pode usar direto na UI. |
analysis.resend_files[].proposal_person_id | UUID do proposal_person na Dock. Use pra rotear o reupload no endpoint certo (/files/pj/partners/{partnerId} ou /files/pj/company). |
analysis.invalid_files[] | Detalhes crus da Dock + os mesmos campos subject_* + subject_document (CPF/CNPJ). |
analysis.files_status | APPROVED / DECLINED / "" (sem análise ainda). |
analysis.data_result | Mesmo, mas pra dados pessoais (CPF, endereço). |
analysis.files_reason_code | Código numérico cru retornado pela Dock (ex: "14", "21"). Veja o catálogo abaixo. |
Catálogo oficial de files_reason_code (Dock)
files_reason_code (Dock)Códigos retornados em analysis.files_reason_code quando os arquivos individuais ficam VALID mas a análise consolidada é DECLINED:
| reasonCode | affectedDocument | reasonDescription | Conceito |
|---|---|---|---|
0 | DOCUMENT | Document not accepted | Documento enviado não é um documento aceito pelo módulo de validação |
1 | DOCUMENT | Uploaded image is not a document photo | A imagem que foi enviada não é uma foto de documento |
2 | DOCUMENT | Illegible document photo | O documento está ilegível. |
3 | DOCUMENT | Cropped document photo | O documento está cortado. |
4 | DOCUMENT | Expired document | Documento fora da validade aceita. |
5 | SELFIE | Low-quality selfie | Selfie com baixa qualidade. |
6 | SELFIE | Uploaded image is not a selfie | A imagem enviada não é uma selfie. |
7 | SELFIE | Face is not visible | O rosto não está visível. |
8 | ALL | Inconsistent selfie (facematch) | A selfie e a foto do documento possuem baixa similaridade. |
9 | ALL | Inconsistent document (automatic validation) | Dados e/ou documentos com alto risco de ação maliciosa |
10 | ALL | Screenphoto | A foto do documento ou da selfie não foi tirada diretamente da pessoa ou documento. |
11 | ALL | Photocopy | A foto de documento ou da selfie é uma fotocópia. |
12 | ALL | Inconsistent registration (document does not match with registration) | Cadastro inconsistente (o documento não corresponde ao cadastro) |
13 | DOCUMENT | Digital driver license without QR Code | CNH digital está sem o QR Code |
14 | ALL | Face in Fraudbook (high similarity) | Face com avaliação biométrica inconsistente |
15 | ALL | Document in Fraudbook (high similarity) | Foto do documento com avaliação biométrica inconsistente |
16 | NONE | Inconsistent data | Conjunto de dados informados apresenta alto risco de ação maliciosa. |
17 | ALL | Face not found | Não foi localizada uma face na selfie ou documento. |
19 | DOCUMENT | The loaded document type does not match the document category | O tipo de documento carregado é diferente do informado. |
20 | ALL | risk policy | Pessoa encontra-se com restrição junto a política de risco de AML dentro da Dock. |
21 | ALL | Inconsistent biometric | Face com avaliação biométrica inconsistente |
24 | NONE | Inconsistent data | Conjunto de dados informados apresenta alto risco de ação maliciosa. |
25 | NONE | Victim of ideological falsehood | Conjunto de dados informados são de vítimas de fraude ideológica |
Observação sobre o código
21(catálogo Dock):
- Resposta automática: o CPF foi encontrado na base de Cadastros Ativos da Oiti e a face não teve correspondência por similaridade biométrica com a face cadastrada para o mesmo CPF. Face e CPF foram certificados negativamente por baixa similaridade.
- Resposta manual: mesa identificou um caso de fraude biométrica e entendeu que essa face deve ser inclusa no book de faces fraudadoras.
A mensagem em last_error.message é montada usando exatamente o texto da coluna "Conceito" acima, sem texto adicional.
Boas práticas pra selfies e documentos (oficial Dock)
Mostre estas dicas antes do usuário tirar as fotos pra reduzir reprovações:
Selfie
- Foto recente, refletindo a aparência atual (não vale foto antiga ou digitalizada).
- Fundo branco ou esbranquiçado, ambiente bem iluminado, rosto inteiro de frente para a câmera, ambos os olhos abertos.
- Apenas o usuário na imagem (sem outras pessoas).
- Não segurar documento na selfie — vai em foto separada.
- Sem máscara, óculos escuros, chapéu ou acessório que cubra o rosto.
- Sem sombras ou reflexos de luz.
- Formato
.jpgou.png, mínimo 600×600 px, orientação vertical.
Documentos (RG/CNH/CIN físicos)
- Documento dentro da validade (até 10 anos da emissão).
- Frente e verso em fotos separadas.
- Tirar capas plásticas mesmo transparentes — reflexo deixa a foto ilegível.
- Sem reflexos; refazer se sair embaçada.
- Não usar fotos digitalizadas ou capturas de tela — caem em revisão manual ou são recusadas.
- CNH física dobrada: enviar as duas partes em fotos separadas, não a CNH aberta inteira.
- Não enviar a mesma imagem duplicada em categorias diferentes.
- Formato
.jpgou.png, mínimo 600×600 px.
CNH Digital (categoria DIGITAL_DRIVER_LICENSE, único arquivo — sem frente/verso)
- Formato
.pdfou.jpg, exportada direto do app "Carteira Digital de Trânsito" (mostra documento aberto + QR Code à direita). - Não aceito: capturas de tela, frente/verso/QR separados.
Carteira de Identidade Nacional (CIN) — usar categorias IDENTITY_CARD_FRONT e IDENTITY_CARD_VERSE normalmente, formatos .pdf ou .jpg.
Erros de validação KYC (data_result: DECLINED)
data_result: DECLINED)Quando os dados pessoais (CPF/nome/mãe/nascimento) caem na validação KYC, a Dock devolve um destes códigos. Aparecem em analysis.data_info ou no body do erro 409 ao tentar criar o processo:
| Código | Descrição |
|---|---|
1000 | Registro nacional não pôde ser validado — tentar novamente em 1 min; se persistir, dados não podem ser validados |
1001 | Status do documento não está regular |
1002 | Nome não corresponde a fontes oficiais do governo |
1003 | Nome da mãe não corresponde a fontes oficiais |
1004 | Data de nascimento não corresponde a fontes oficiais |
1005 | Operação não permitida para o documento (sanções) |
1006 | Recusado pela política de risco interna |
1007 | Rejeitado por política de risco DICT / Resolução BCB 6/2023 |
Em 1002, 1003 e 1004, oriente o usuário a revisar exatamente o campo correspondente. Em 1000, sugerir nova tentativa em 1 minuto. Demais códigos: encaminhar ao suporte da Autra com o proposal.id.
Como reagir no front (PF)
- Se
status = WAITING_CORRECTION: itereanalysis.resend_filese refaça só esses viaPOST /onboarding/{id}/files(passo 7). - Se
status = DECLINEDouFAILED: a proposta é terminal. Mostrelast_error.messagee crie nova proposta. - Se
analysis.data_result = "DECLINED": dados pessoais foram rejeitados (raro). Revise CPF, nome da mãe, data de nascimento —analysis.data_infotraz a explicação.
Como reagir no front (PJ)
- Agrupe
resend_filesporsubject_type+subject_name— uma seção "Documentos da empresa", uma seção por sócio. - Roteie o reupload baseado em
subject_type:COMPANY→POST /onboarding/{id}/files/pj/companycomfile_side(passo 10).PARTNER→ use oproposal_person_idretornado pra encontrar opartnerIdAutra correspondente na sua proposta, e chamePOST /onboarding/{id}/files/pj/partners/{partnerId}(passo 11). Odock_proposal_person_iddo sócio voltou nopartners[]da resposta de/start-pj.
- Sócios convidados (que recebem link) só veem os arquivos deles — filtre
resend_filesno frontend público pelosubject_nameousubject_documentque casa com o sócio do convite.
🟩 Fluxo PJ — passo a passo
PJ tem 2 fases antes da Dock:
- Master configura tudo — empresa + sócios (com convites se preciso).
- Sócios convidados preenchem seus dados (rota pública, sem login).
- Só depois o master dispara
start-pj.
App/Site (master) BFF Autra Dock Sócio convidado
----------------- ---------- ----- ----------------
master ─────────► /onboarding {PJ}
/legal-entity
/partners (stub)
/partners/{id}/invite ──────────────► recebe link
▼
/invite/{token}
/invite/{token}/personal-data
/start-pj ──────────► POST /starting
/files/pj/company ──► POST /files
/files/pj/partners/{id} ─► POST /files
◄── webhooks ──────── process_finished
PJ — Passo 1: Criar a proposta
POST /v1/banking/onboarding
Authorization: Bearer <JWT do master>
Idempotency-Key: pj-acme-2026-05-01
{ "type": "PJ" }Resposta 201: {id, type: PJ, status: DRAFT}. Guarde o id.
PJ — Passo 2 e 3: Termos (igual ao PF)
GET /v1/banking/onboarding/{id}/terms
POST /v1/banking/onboarding/{id}/terms/accept
{
"tou_token": "...",
"pp_token": "...",
"fingerprint": "Mozilla/5.0...#187.45.32.10"
}→ status: TERMS_ACCEPTED.
PJ — Passo 4: Salvar dados da empresa
PUT /v1/banking/onboarding/{id}/legal-entity
Authorization: Bearer <JWT>
{
"cnpj": "60116920000100",
"legal_name": "ACME Tecnologia LTDA",
"trade_name": "ACME",
"legal_nature": "2062",
"establish_date": "2020-01-15",
"industrial_classification": "6201500",
"business_classification": "Desenvolvimento de software sob encomenda",
"revenue": 5000000,
"address": { "zip_code": "06404250", "street": "Anápolis", ... },
"phone": { "area_code": "11", "number": "914052149" },
"email": "[email protected]"
}Resposta 200: status: LEGAL_ENTITY_FILLED.
Códigos de natureza jurídica suportados:
| Código | Tipo |
|---|---|
2135 | MEI / Empresário Individual |
2305 / 2313 | EIRELI |
2062 | LTDA |
2046 / 2054 | S.A. |
2143 / 2330 | Cooperativa |
⚠️ Validamos: CNPJ (check digits + único no tenant) + CNAE numérico + data de constituição não-futura.
PJ — Passo 5: Adicionar sócios
Você precisa cadastrar todos os sócios que aparecem no contrato social. Há 2 modos:
Modo A — Sócio com dados completos (master ou sócio que está ao seu lado)
POST /v1/banking/onboarding/{id}/partners
Authorization: Bearer <JWT>
{
"role": "PARTNER",
"person_type": 1,
"is_account_handler": true,
"is_responsible_onboarding": true,
"personal_data": {
"full_name": "Jorge Augusto Silva",
"preferred_name": "Jorge",
"cpf": "39053344705",
"birth_date": "1985-03-10",
"mother_name": "Maria da Silva",
"gender_id": 3,
"marital_status_id": 8,
"is_pep": false,
"email": "[email protected]",
"phone": { "area_code": "11", "number": "987654321" }
},
"address": { "zip_code": "06404250", ... }
}→ Status do sócio: READY.
Modo B — Sócio "stub" (vai receber convite)
POST /v1/banking/onboarding/{id}/partners
Authorization: Bearer <JWT>
{
"role": "PARTNER",
"person_type": 1,
"is_responsible_onboarding": false,
"email_invite": "[email protected]",
"phone_invite": { "area_code": "11", "number": "999887766" }
}→ Status do sócio: INVITED. Proposta vai pra PARTNERS_PENDING.
⚠️ Regras:
- Exatamente 1 sócio precisa ter
is_responsible_onboarding=true(o "master"). - CPFs precisam ser únicos dentro da proposta (
409 DUPLICATE_PARTNER_CPFse duplicar). gender_idemarital_status_idvêm deGET /onboarding/setup-types— cache esse catálogo no front.
PJ — Passo 6: Gerar convite para sócios stub
Para cada sócio stub (Modo B do passo 5):
POST /v1/banking/onboarding/{id}/partners/{partnerId}/invite
Authorization: Bearer <JWT>
{ "channels": ["EMAIL", "WHATSAPP"] }Resposta 201:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-05-08T16:00:00Z",
"invite_url": "https://autra.io/onboarding/invite/eyJhbGc...",
"channels": {
"email": { "mailto": "mailto:[email protected]?subject=...&body=..." },
"whatsapp": { "wa_me": "https://wa.me/5511999887766?text=..." }
}
}✅ O backend NÃO envia o email/WhatsApp. Ele te dá os deep links prontos. O master clica no mailto: (abre o app de email) ou no wa.me/ (abre WhatsApp já com a mensagem) e dispara do próprio dispositivo.
⚠️ Se você gerar um convite novo para o mesmo sócio, o anterior é revogado (vira INVITE_TOKEN_REVOKED).
PJ — Passo 7: Sócio convidado preenche dados (rota PÚBLICA)
Esta etapa não é o master que faz. É o sócio que recebeu o link.
O frontend público (sem login Cognito) carrega a página https://autra.io/onboarding/invite/{token} e chama:
7a. Buscar o estado atual do convite
GET /v1/banking/onboarding/invite/{token}(sem Authorization)
Resposta 200:
{
"company_name": "ACME Tecnologia LTDA",
"partner_role": "PARTNER",
"needs": ["personal_data", "address"]
}7b. Submeter os dados pessoais
PUT /v1/banking/onboarding/invite/{token}/personal-data
{
"personal_data": { "full_name": "...", "cpf": "...", ... },
"address": { ... }
}→ Sócio fica READY.
⚠️ O sócio convidado não pode alterar role, person_type, is_account_handler ou is_responsible_onboarding — o backend bloqueia.
⚠️ Quando todos os sócios estiverem READY + houver 1 master, a proposta vai pra PARTNERS_READY. Só então o master pode chamar start-pj.
PJ — Passo 8: Iniciar processo na Dock
(De volta ao master.)
POST /v1/banking/onboarding/{id}/start-pj
Authorization: Bearer <JWT do master>
{
"device_id": "uuid",
"device_model": "iPhone 15",
"operating_system": "iOS 18",
"ip_address": "187.45.32.10"
}⚠️ Pré-condição: status = PARTNERS_READY. Se não estiver, retorna 409 INVALID_STATUS.
Resposta 200:
{
"status": "PROCESS_STARTED",
"process_instance_id": "...",
"dock_proposal_id": "...",
"partners": [
{ "id": "p1", "dock_proposal_person_id": "..." },
{ "id": "p2", "dock_proposal_person_id": "..." }
]
}✅ Cada sócio agora tem um dock_proposal_person_id. A empresa também tem um na raiz (dock_proposal_person_id).
PJ — Passo 9: Esperar liberação de upload (polling)
Igual ao PF passo 6:
GET /v1/banking/onboarding/{id}/files/pending202→ aguardar e repolar.200→ resposta lista o que cadaproposal_person_idprecisa enviar.
PJ — Passo 10: Upload dos documentos da empresa
Documentos exigidos variam pela natureza jurídica:
| Natureza | Documentos |
|---|---|
| MEI | MEI_CCMEI |
| LTDA | ARTICLES_OF_ASSOCIATION (contrato social) + última alteração |
| S.A. | COMPANY_BYLAWS (estatuto) + ata da última eleição |
| EIRELI | ARTICLES_OF_ASSOCIATION |
Para cada documento:
POST /v1/banking/onboarding/{id}/files/pj/company
Authorization: Bearer <JWT do master>
{
"file_side": "ARTICLES_OF_ASSOCIATION",
"base64": "<conteúdo do PDF em base64>"
}✅ Roteia automaticamente para o proposal_person_id da empresa.
PJ de sócio único (MEI / dono único): a Dock abre o slot do documento da empresa de forma assíncrona — a proposta pode já estar em
PROCESSINGquando o contrato social/CCMEI for enviado. Por isso este endpoint aceita o doc da empresa também com a proposta emPROCESSING/WAITING_MANUAL_ANALYSIS(não só emFILES_PENDING). Se o upload voltar409 INVALID_STATUSlogo após ostart-pj, aguarde alguns segundos e tente de novo — o slot ainda está sendo criado.
PJ — Passo 11: Upload da selfie e do documento de identificação de cada sócio
Para cada sócio (master + Regulares), via SDK Unico:
POST /v1/banking/onboarding/{id}/files/pj/partners/{partnerId}
Authorization: Bearer <JWT>
{ "file_side": "SELFIE", "jwt": "<JWT do Unico SDK>" }Repita com os file_sides do documento escolhido (RG/CIN: IDENTITY_CARD_FRONT + IDENTITY_CARD_VERSE; CNH física: DRIVER_LICENSE_FRONT + DRIVER_LICENSE_VERSE; CNH digital: DIGITAL_DRIVER_LICENSE; RNE: RNE_FRONT + RNE_VERSE; Passaporte: PASSPORT). A lista de opções vem do groups[] em GET .../files/pending.
⚠️ O sócio Regular faz isso acessando o link de convite — depois de preencher os dados (passo 7), o frontend público continua para a etapa de selfie/documento no mesmo dispositivo dele (com o JWT de convite, não o do master).
PJ — Passo 12: Marcar uploads completos
POST /v1/banking/onboarding/{id}/files/complete
Authorization: Bearer <JWT do master>→ status: FILES_UPLOADED.
PJ — Passo 13: Aguardar aprovação
Igual ao PF:
GET /v1/banking/onboarding/{id}Estados terminais: COMPLETED (com account populada), DECLINED, WAITING_CORRECTION (refazer arquivo), WAITING_MANUAL_ANALYSIS (PJ com 1 sócio só).
✅ Pronto. Conta PJ aberta.
Sobre BACEN 491 — dispositivo autorizado para Pix
Conta aberta (COMPLETED) NÃO significa device autorizado pra Pix. Odevice_idque você mandou emPOST /start/POST /start-pjserve só pro KYC do onboarding — ele não é registrado na Trusted Devices API da Dock. Antes de qualquer operação Pix/DICT você precisa registrar o dispositivo (passo abaixo). Pular isso faz o Pix/DICT retornarNO_AUTHORIZED_DEVICE(e, na Dock,PIX-4002).
Passo obrigatório após o COMPLETED — registrar o device
COMPLETED — registrar o deviceO BACEN 491/2024 exige um dispositivo autorizado (registrado + confirmado por MFA) pra operações Pix mutantes:
- Criar/remover chaves Pix DICT
- Enviar Pix (P2P, TED out)
- Gerar QR Code dinâmico
Fluxo de autorização (SMS MFA) — é o único caminho, não um extra:
POST /v1/banking/devices— inicia o registro e dispara o SMSPOST /v1/banking/devices/{id}/mfa-confirm— confirma o código recebido → device fica autorizado- (se precisar)
POST /v1/banking/devices/{id}/mfa-resend— reenvia o código
Depois disso, ao chamar POST /v1/banking/accounts/{id}/pix-keys (ou qualquer rota Pix), o backend resolve o dispositivo autorizado automaticamente. Enquanto não houver device autorizado, essas rotas respondem NO_AUTHORIZED_DEVICE (422) — esse é o sinal pro app disparar o fluxo acima.
Gerenciar dispositivos
GET /v1/banking/devices— lista devices autorizados da contaDELETE /v1/banking/devices/{id}— revoga device perdido/roubado- Para um segundo aparelho (troca de celular, tablet), repita o mesmo fluxo
POST /v1/banking/devices+mfa-confirm.
Detalhes completos no Guia Trusted Devices.
Limites pra dispositivos NÃO autorizados (BACEN 491)
- Pix: R$ 200 por transação e R$ 1.000 por dia
- DICT (chaves Pix): bloqueado — qualquer create/delete/portability exige device autorizado
- Devices inativos por mais de 12 meses são bloqueados automaticamente pela Dock
Webhooks (opcional — recomendado em produção)
Se você assina os webhooks da Autra, evita polling. Endpoint que você expõe:
POST <seu-endpoint> com body cifrado em AES-256-GCM (chave compartilhada via Setup).
Eventos enviados durante o onboarding:
event_type | Quando ocorre | O que fazer |
|---|---|---|
process_started | Logo após /start ou /start-pj | Apenas registrar |
process_kyc_analysis_started | Dock começou KYC | Apenas registrar |
process_files_receives_started | Upload liberado | Frontend pode chamar /files/pending agora |
process_files_corrections_started | Algum arquivo foi rejeitado | Notificar usuário, pedir refile |
process_data_corrections_started | Algum dado foi rejeitado | Notificar usuário |
process_files_analysis_started | Análise de arquivos rolando | Apenas registrar |
process_desk_analysis_started | Mesa manual (só PJ 1 sócio) | Avisar usuário que pode levar horas |
process_registries_started | Cadastro nos órgãos | Quase lá |
process_finished | Proposta finalizada | Buscar status final via GET /onboarding/{id} |
process_failed | Erro na Dock | Tratar como FAILED |
Idempotência (importante)
POST /onboardingaceitaIdempotency-Key— mesma key = mesma proposta.POST /partners(PJ) valida CPF único na proposta.POST /partners/{id}/invite(PJ) revoga token anterior — sempre.POST /startePOST /start-pjsão idempotentes — reenviar não recria na Dock.
Erros comuns
| Code | HTTP | O que fazer |
|---|---|---|
INVALID_STATUS | 409 | Você chamou no estado errado. Cheque GET /onboarding/{id} antes. |
MISSING_DEVICE_INFO | 400 | Faltou device_id no payload de /start. |
PJ_ONLY | 409 | Você chamou rota PJ em proposta PF (ou vice-versa). |
INVALID_LEGAL_ENTITY | 422 | CNPJ/CNAE/data inválidos. Releia o passo 4 PJ. |
INVALID_PARTNER | 422 | Dados do sócio incompletos. |
MASTER_PARTNER_REQUIRED | 422 | Você tentou start-pj sem 1 sócio com is_responsible_onboarding=true. |
DUPLICATE_PARTNER_CPF | 409 | CPF já está em outro sócio desta proposta. |
CANNOT_REMOVE_MASTER | 409 | Promova outro a master antes de remover este. |
PARTNER_NOT_FOUND | 404 | partnerId não existe nesta proposta. |
INVITE_TOKEN_EXPIRED | 401 | Convite passou de 7d. Gere outro. |
INVITE_TOKEN_REVOKED | 401 | Você gerou um convite novo — use o atual. |
DOCK_FILES_DECLINED | — (em last_error.code) | Análise de arquivos rejeitada. Use analysis.resend_files para refazer só os marcados como INVALID. |
DOCK_DATA_DECLINED | — (em last_error.code) | Análise de dados rejeitada. Cheque analysis.data_info — geralmente CPF, nome da mãe ou data de nascimento. |
DOCK_AWAITING_CORRECTION | — (em last_error.code) | Dock pediu correção mas a Autra ainda não tem detalhe. Faça novo GET /onboarding/{id} e siga o analysis. |
DOCK_PROCESS_EXPIRED | — (em last_error.code) | Proposta expirou na Dock (timeout). Status vira FAILED. Crie uma nova proposta. |
⚠️ 202 em /files/pending NÃO é erro. É "aguarde e tente de novo em ~2s".
Boas práticas
- Cache
setup-typesno frontend —gender_id,marital_status_idetc. raramente mudam. - Polling com backoff: 2s → 4s → 8s → 16s (máx 30s).
- Use webhooks em produção — polling fica para desenvolvimento/teste.
- CPFs mascarados na resposta (
123.***.***-45). Não tente reconstruir; peça de novo se precisar exibir. - Idempotency-Key sempre que possível em
POST /onboarding(evita duplicar proposta se a chamada falhar e for retentada). - (PJ) Convites: deixe o master escolher os canais (EMAIL/WHATSAPP) — alguns sócios preferem um, outros outro.
Limitações conhecidas
- Sócios
person_type=2(PJ-relacionada) — suportado mas raro. - Procuradores (
role: ATTORNEY) não podem ser master. - Mesa manual (
process_desk_analysis_started) só dispara para PJ com 1 único sócio. - Recovery automático de processo Dock pré-existente: hoje só PF; em PJ você precisa cancelar e refazer.
- Após
PROCESS_STARTED, a composição societária está congelada na Dock — não dá pra adicionar/remover sócios. Cancele e refaça.
FAQ
Posso trocar o type (PF/PJ) depois de criar a proposta? Não. Cancele e crie outra.
O master precisa ter conta na Autra antes de criar a proposta? Sim — autenticação Cognito obrigatória.
Sócio convidado (PJ) precisa criar login Cognito? Não — ele acessa pelo deep link público.
Posso reenviar convite se o sócio não respondeu? Sim. POST /partners/{id}/invite gera token novo e revoga o anterior.
O backend manda mesmo o email/WhatsApp pro sócio? Não. Ele te dá mailto: e wa.me/?text=... prontos — o master abre do próprio dispositivo.
Posso adicionar sócios depois de start-pj? Não. Composição congelada na Dock.
Como sei que a conta foi aprovada? Polla GET /onboarding/{id} ou aguarde webhook process_finished. Quando aprovada, a resposta tem account com bank, agency, number.
Quanto tempo leva o onboarding? PF: minutos a algumas horas. PJ: pode levar 1 dia útil (mais documentos).
Onde vejo o que falta upar? GET /onboarding/{id}/files/pending — lista o file_side exigido por proposal_person_id.
