Skip to main content
POST
cURL

Quando usar

Use este endpoint para registrar um cliente no kycert antes ou independentemente de rodar um bureau. Ideal para fluxos em que o cadastro acontece em etapas separadas da verificação KYC.

Campos doc, email e external_id

doc

Aceita CPF/CNPJ formatado (123.456.789-01, 12.345.678/0001-99) ou só dígitos — a API normaliza internamente removendo tudo que não for número. Além da quantidade de dígitos (11 para CPF, 14 para CNPJ) e da consistência com o type informado, o dígito verificador é validado. Qualquer uma dessas falhas retorna 400 invalid_document.

email

Obrigatório e validado para type: "pf" — ausente ou em formato inválido retorna 400 invalid_email. Para type: "pj" é opcional; se omitido, nenhuma validação de formato é aplicada.

external_id

Identificador do seu próprio sistema, opcional, até 255 caracteres. Único por tenant — reenviar um external_id já usado por outro cliente retorna 409 external_id_conflict (ver Cliente duplicado abaixo).

Header Idempotency-Key

Envie um UUID único por tentativa de chamada no header Idempotency-Key. Se a mesma chave for reenviada nas próximas 24h, a API retorna a resposta original em cache — sem criar um segundo cliente nem disparar o bureau de novo. Use sempre que seu código faz retry automático (timeout de rede, erro 5xx, etc.), principalmente com run_bureau: true: sem a chave, um retry num cliente que já existe em rascunho pode disparar um segundo bureau run para o mesmo cliente, cobrado em dobro. Veja Idempotência para o comportamento completo de retry com a mesma chave.
O cache é por tenant — a mesma chave usada por dois tenants diferentes nunca reaproveita a resposta um do outro. Só respostas de sucesso (201) são cacheadas; erros de validação (400) e conflitos (409) não são — uma nova tentativa com a mesma chave após um erro consulta o estado atual normalmente.
Se duas chamadas com a mesma Idempotency-Key chegarem simultaneamente (em voo ao mesmo tempo, não uma depois da outra terminar), a segunda recebe 409 idempotency_key_in_progress (com header Retry-After em segundos) em vez de processar de novo — evita duplicar a criação do cliente/bureau run quando o cliente HTTP dispara um retry antes de a primeira chamada terminar. Aguarde o Retry-After e tente de novo com a mesma chave: a chamada original, quando concluir, já deixa a resposta em cache para o replay normal.

Cliente duplicado (409)

Chamar POST /customers com um CPF/CNPJ ou external_id já cadastrado no tenant retorna 409, não 400 — é um conflito de estado, não um erro de validação do request.
Os dois códigos trazem existing_customer_id — antes de tratar como falha, consulte GET /customers com ?doc= ou ?external_id= (ou GET /customers/ direto com o existing_customer_id) para decidir se o fluxo deve seguir com o cliente já existente em vez de reportar erro ao usuário final.

Campo doc na resposta

O CPF ou CNPJ nunca é retornado em claro. A resposta sempre retorna uma versão mascarada:
  • CPF: ***456789**
  • CNPJ: **34567890****

Campo run_bureau

Quando run_bureau: true, o bureau é disparado imediatamente após criar o cliente. O comportamento é idêntico ao POST /api/v1/bureau/runs e o resultado chega via webhook — payload completo, eventos disponíveis e política de retry em Visão geral de webhooks. Para sobrescrever a URL de webhook configurada no dashboard só nesta chamada, envie webhook_url. Veja Conceitos — Run para entender o ciclo de vida de um run, e o guia de onboarding completo para o fluxo fim-a-fim (cadastro → documento → bureau → webhook → consulta).

Template padrão — run_bureau sem template_id

Se o tenant tem um template padrão configurado em Configurações → Bureau no dashboard (um para PF, outro para PJ), template_id é opcional: a API resolve automaticamente o template do type do cliente. Prioridade de resolução (a primeira que existir vence):
  1. template_id enviado explicitamente
  2. Template do perfil indicado em onboarding_profile (se o slug for válido)
  3. Template padrão do tenant para o type do cliente
Se nenhuma das três resolver, a chamada retorna 400 missing_default_template — o cliente não é criado.
O status do cliente usa o vocabulário de decisão de onboarding (em_analise, aprovado, pendencia, recusado) — distinto do status de bureau run, que usa inglês. Veja Status de bureau run vs status de cliente. livemode reflete se a chamada usou uma chave sk_live_... (produção) ou sk_test_... (sandbox) — veja Sandbox. Sem template padrão configurado e sem template_id, a mesma chamada retornaria:

Campo onboarding_profile

Slug de um perfil de cadastro (o mesmo ?perfil=slug do portal público de onboarding). Quando enviado e válido, o template configurado nesse perfil tem prioridade sobre o default do tenant. Slug inexistente, inativo, ou de outro tenant é ignorado silenciosamente — cai no default do tenant, nunca gera erro.
O toggle “Bureau automático” (bureau_enabled) do dashboard controla apenas se o portal público dispara bureau sozinho ao final do cadastro — não afeta esta API. run_bureau: true é um pedido explícito do integrador e sempre é respeitado, independente desse toggle.

Campo address

Todos os subcampos são opcionais entre si — envie apenas os que tiver. address é aceito e retornado tanto para clientes PF quanto PJ. Chaves fora dessa lista são aceitas e persistidas, mas ignoradas na validação — não quebram a chamada. Qualquer subcampo fora dessas regras retorna 400 invalid_address com param indicando o subcampo (ex: address.zip).

Campos complementares (PF e PJ)

Os mesmos campos profissionais, financeiros e de nacionalidade que o portal público de cadastro coleta — para fechar um cadastro completo via API sem precisar voltar ao dashboard depois. Cada campo é exclusivo do type indicado; enviá-lo com o type errado retorna 400 (ver tabela).
declared_income e annual_revenue são apenas armazenados — não acionam recálculo automático de capacidade financeira (motor de renda). Se a empresa precisa que esses valores alimentem risk scoring, isso continua sendo feito manualmente hoje.
Campo do tipo errado (ex: occupation com type: "pj") retorna 400 invalid_request_error com param indicando o campo:
Exemplo PF:
Exemplo PJ:

Lista de nacionalidades

Mesma lista usada pelo seletor do portal público — envie o valor exatamente como aparece abaixo (Brasileira, Alemã, Angolana, Argentina, Australiana, Austríaca, Belga, Boliviana, Canadense, Chilena, Chinesa, Colombiana, Coreana, Cubana, Dinamarquesa, Egípcia, Equatoriana, Espanhola, Estadunidense, Finlandesa, Francesa, Grega, Guatemalteca, Holandesa, Hondurenha, Húngara, Indiana, Indonésia, Inglesa, Iraniana, Irlandesa, Israelense, Italiana, Jamaicana, Japonesa, Libanesa, Marroquina, Mexicana, Moçambicana, Nigeriana, Norueguesa, Panamenha, Paraguaia, Peruana, Polonesa, Portuguesa, Russa, Salvadorenha, Sul-africana, Sueca, Suíça, Turca, Ucraniana, Uruguaia, Venezuelana, Vietnamita, Outra). Valor fora dessa lista retorna 400 invalid_nationality.

Verificação facial automática

Se o cliente é criado com uma selfie e um documento de identidade suportado anexados (via upload simultâneo — hoje só possível anexando os dois em POST /customers//documents logo em seguida, já que POST /customers não aceita arquivo), e o tenant tem o módulo “Verificação facial” ativo (master) e a configuração habilitada (tenant), o kycert dispara Face Match e Passive Liveness automaticamente, em background — nunca soma latência à resposta deste endpoint. Não existe parâmetro no payload para ativar ou pular esse disparo por chamada; a decisão é sempre da configuração do tenant.
O disparo não é garantido — ele só acontece quando as duas camadas de ativação (módulo no master + configuração no tenant) estão ligadas. Nenhuma delas é acionável via API; é decisão do compliance officer no dashboard. Sem elas, o par selfie+identidade é apenas armazenado, sem nenhuma verificação rodando.
O resultado não vem na resposta deste endpoint — é sempre assíncrono. Consulte de uma das duas formas:
  • GET /customers/{id} retorna o campo facial_verification com o resultado da rodada mais recente — ver Buscar cliente. Melhor para quem só confere ocasionalmente (polling).
  • Webhook biometric_check.completed — notifica assim que a rodada termina. Ver Webhooks. Melhor para quem já automatiza reação a eventos.
Verificação bem-sucedida consome o mesmo saldo do tenant usado por bureau runs. Para validar biometria sem depender do par selfie+identidade estar completo no cadastro, use POST /verificacoes/facial — alternativa síncrona e avulsa, que retorna o resultado na própria resposta.

Erros

Formato completo do envelope e estratégia de retry em Tratamento de erros. Os códigos deste endpoint:
  • Autenticação/autorização: missing_api_key, invalid_api_key, insufficient_scope, channel_disabled
  • Validação de campos: missing_type, invalid_document, document_type_mismatch, missing_name, invalid_email, invalid_birth_date, invalid_address, invalid_external_id, invalid_metadata, invalid_webhook_url, e invalid_<campo> para cada campo complementar (nationality, occupation, declared_income, trade_name, annual_revenue, business_activity, employee_count)
  • Bureau (run_bureau: true): missing_default_template, template_not_found, subject_type_mismatch
  • Conflito: customer_already_exists, external_id_conflict — ver Cliente duplicado (409); idempotency_key_in_progress — ver Header Idempotency-Key

Authorizations

x-api-key
string
header
required

API key no header x-api-key (recomendado)

Headers

Idempotency-Key
string<uuid>

UUID único por tentativa. Mesmo valor nas próximas 24h retorna a resposta original sem criar o cliente nem disparar o bureau de novo — use sempre que implementar retry no seu código, especialmente com run_bureau: true.

x-kycert-api-version
string
Example:

"2026-06-03"

Body

application/json
type
enum<string>
required

Tipo do cliente — pessoa física ou jurídica

Available options:
pf,
pj
doc
string
required

CPF (11 dígitos) ou CNPJ (14 dígitos), sem formatação

Example:

"12345678901"

name
string
required

Nome completo (PF) ou razão social (PJ)

Required string length: 2 - 300
email
string<email>

Email do cliente. Obrigatório para PF.

phone
string

Telefone do cliente. Opcional.

birth_date
string<date>

Data de nascimento no formato YYYY-MM-DD (apenas PF)

nationality
string

Nacionalidade (apenas PF). Deve ser um valor exato da lista canônica usada pelo seletor do portal público de cadastro.

Example:

"Brasileira"

occupation
string

Profissão declarada (apenas PF).

Maximum string length: 120
Example:

"Engenheiro(a) de Software"

declared_income
string

Renda mensal declarada (apenas PF). Aceita um valor decimal (ex: "12000.00") ou um código de faixa (ex: "10001_20000", mesmo formato gravado quando o tenant usa modo de faixa no portal) — validado apenas como string não vazia, sem normalizar o formato. Apenas armazenado: não aciona recálculo automático de capacidade financeira (motor de renda).

Maximum string length: 20
Example:

"12000.00"

address
object

Endereço do cliente. Todos os subcampos são opcionais entre si — envie apenas os que tiver. Chaves fora das listadas abaixo são aceitas e persistidas, mas ignoradas na validação.

trade_name
string

Nome fantasia (apenas PJ).

Maximum string length: 300
Example:

"Kycert Tech"

annual_revenue
string

Faturamento anual declarado (apenas PJ). Mesma regra de passthrough de declared_income — string não vazia, sem normalizar o formato. Apenas armazenado: não aciona recálculo automático de capacidade financeira (motor de renda).

Maximum string length: 20
Example:

"5000000.00"

business_activity
string

Atividade principal da empresa (apenas PJ). Texto livre — não é validado contra nenhuma lista curada de atividades.

Maximum string length: 120
Example:

"Desenvolvimento de software / TI"

employee_count
string

Número de funcionários declarado (apenas PJ).

Maximum string length: 10
Example:

"25"

external_id
string

Seu identificador interno para este cliente. Deve ser único no tenant.

Maximum string length: 255
metadata
object

Até 10 pares chave-valor string

run_bureau
boolean

Se true, dispara um bureau run imediatamente após criar o cliente. Não requer template_id quando há um template padrão configurado para o tipo de pessoa (type) em Configurações → Bureau no dashboard — nesse caso a resolução é automática (ver template_id e onboarding_profile abaixo). Sem template_id explícito e sem template padrão configurado, retorna 400 missing_default_template.

template_id
string<uuid>

ID do template de bureau. Opcional quando run_bureau: true e houver um template padrão configurado no dashboard para o type do cliente (bureau_default_template_pf_id/_pj_id) — nesse caso é resolvido automaticamente, com prioridade: template_id explícito > onboarding_profile > default do tenant. Obrigatório apenas se nenhum template padrão estiver configurado.

onboarding_profile
string

Slug de um perfil de cadastro (o mesmo usado em ?perfil=slug no portal público) — quando enviado e válido, o template configurado nesse perfil tem prioridade sobre o default do tenant na resolução automática de template_id. Slug inexistente, inativo, ou de outro tenant é ignorado silenciosamente (cai no default do tenant) — nunca gera erro. Só tem efeito quando template_id não é enviado explicitamente.

Example:

"cadastro-pf-completo"

webhook_url
string<uri>

URL HTTPS para entrega do resultado do bureau (quando run_bureau: true)

Response

Cliente criado com sucesso

customer_id
string<uuid>

Identificador único do cliente

object
enum<string>
Available options:
customer
status
enum<string>
Available options:
em_analise,
aprovado,
pendencia,
recusado
Example:

"em_analise"

type
enum<string>
Available options:
pf,
pj
name
string
email
string
phone
string | null
doc
string

CPF/CNPJ mascarado — nunca retorna em claro

Example:

"***456789**"

external_id
string | null
metadata
object | null
created_at
string<date-time>
run_id
string<uuid> | null

ID do run de bureau criado (presente apenas quando run_bureau=true)

bureau_status
enum<string> | null

Status do bureau (presente apenas quando run_bureau=true)

Available options:
queued
livemode
boolean