# CPF Direto — API v1

Documentação oficial para implementar clientes HTTP. Exemplos ilustram o contrato; não garantem a existência de um CPF no catálogo.

Base URL: https://cpfdireto.com
OpenAPI 3.1: https://cpfdireto.com/api/openapi.json
Documentação interativa: https://cpfdireto.com/api-consulta-cpf/

## Regras de integração

Integre CPF Direto em uma aplicação existente, respeitando a arquitetura e os padrões do projeto.
Contrato: https://cpfdireto.com/api/openapi.json
Guia: https://cpfdireto.com/api-guide.md
Base: https://cpfdireto.com (as rotas já incluem /api/v1).

1. Implemente a chamada no backend. Guarde CPF_DIRETO_KEY como segredo no servidor; solicite seu preenchimento pelo gerenciador de segredos, nunca pelo chat. Não exponha a chave em frontend, bundle, logs, URLs ou localStorage.
2. Proteja a rota da sua aplicação com autenticação, autorização por usuário e limite de uso. Não crie um proxy público para uma chave paga. Preserve o controle de origem/CSRF quando usar cookies.
3. Envie Authorization: Bearer <CPF_DIRETO_KEY> e Content-Type: application/json. POST /api/v1/consultas recebe {"cpf":"12345678909"}. CPF é string, nunca número. Preserve zeros iniciais; valide 11 dígitos e verificadores antes de enviar.
4. HTTP 200 pode ser {success:true,data:{name,cpf,birthday,gender},meta:{remainingCredits,consultedAt}} OU {success:false,data:null,meta:{remainingCredits,consultedAt}}. Não confunda ausência de registro com erro HTTP. birthday é YYYY-MM-DD; gender é M, F ou null. consultedAt é ISO 8601 UTC de processamento, não de atualização da fonte.
5. POST /api/v1/lotes recebe {cpfs:[strings]}, de 1 a 100 itens. Retorna {results:[{success,data}],meta}, em ordem e incluindo duplicatas. Inválidos e ausentes têm success:false/data:null. Cada ocorrência encontrada custa 1 crédito; duplicatas custam novamente. HTTP 402 cancela o débito de todo o lote.
6. GET /api/v1/saldo retorna {remainingCredits,includedCredits,includedUsed,extraCredits,renewsAt}. Use renewsAt para renovação; saldo não reserva créditos. GET /api/v1/historico retorna {rows,total}; filtros limit (1–500, padrão 500), offset (>=0), q (até 120 caracteres, busca mascarada), status, type, from e to (datas inclusivas em Brasília). /api/v1/historico.csv usa os mesmos filtros e paginação e retorna CSV UTF-8 com BOM e ponto e vírgula; erros são JSON.
7. Erros JSON: {error:{code,message}}. Trate status HTTP + error.code: 400 invalid_cpf/request_error, 401 unauthorized/invalid_api_key/request_error, 402 credits_exhausted, 403 email_unverified/billing_hold/request_error, 404 request_error, 413 request_error, 415 request_error, 429 rate_limited, 500 server_error e 503 catalog_unavailable/catalog_busy/real_data_disabled. A mensagem pode variar. Em 429, respeite Retry-After em segundos. Registre X-Request-Id sem documentos ou chaves.
8. Limite padrão: 120 requisições/minuto por conta, compartilhadas entre chaves e consultas do painel; observe X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset (Unix em segundos) quando presentes. Um lote conta como uma requisição. Saldo/histórico não gastam créditos, mas contam nesse limite.
9. Configure timeout e cancelamento, impeça duplo envio, mostre carregamento, encontrado, não encontrado, entrada inválida, falta de saldo e indisponibilidade. Não repita POST automaticamente após timeout, erro 500 ou falha de rede: pode ter sido cobrado. Não há garantia de idempotência nem suporte documentado a Idempotency-Key nas consultas. Limite as tentativas; não faça polling de consultas.
10. Renderize nomes como texto, sem HTML; evite cache público, analytics e logs com dados pessoais. Não apresente a consulta como prova de identidade, score ou situação fiscal. Não invente SDK, MCP, webhook ou endpoint de sandbox.
11. Escreva testes de contrato com respostas locais: encontrado com gender:null, não encontrado 200, erros 400/401/402/403/429/503, timeout incerto e lote misto. Não use consultas pagas nos testes automáticos. Documente onde preencher o segredo e como executar o projeto.

## Autenticação

Crie uma conta, confirme o e-mail e gere uma chave no painel. Use a chave somente no servidor. Todas as rotas abaixo são autenticadas. O playground real usa os créditos normais da conta; o modo Exemplos não faz requisições.

```http
Authorization: Bearer SUA_CHAVE
Content-Type: application/json
```


## POST /api/v1/consultas

Informe o CPF como string, com ou sem pontuação, até 32 caracteres. Os 11 dígitos e os verificadores são validados. Preserve zeros iniciais. Um registro encontrado consome 1 crédito; um CPF válido sem registro retorna HTTP 200, success: false e data: null, sem cobrança.

Corpo:

```json
{
  "cpf": "12345678909"
}
```


HTTP 200 (application/json):

```json
{
  "success": true,
  "data": {
    "name": "Pessoa de exemplo",
    "cpf": "12345678909",
    "birthday": "1990-06-15",
    "gender": null
  },
  "meta": {
    "remainingCredits": 19,
    "consultedAt": "2026-10-14T15:30:00.000Z"
  }
}
```

HTTP 200, sem registro:

```json
{
  "success": false,
  "data": null,
  "meta": {
    "remainingCredits": 20,
    "consultedAt": "2026-10-14T15:30:00.000Z"
  }
}
```


## POST /api/v1/lotes

Envie cpfs como uma lista de 1 a 100 strings, com até 32 caracteres cada. A resposta é síncrona e mantém a ordem, incluindo repetições. Itens inválidos e não encontrados retornam success: false e data: null. Valide os dígitos antes de enviar para distingui-los. Cada ocorrência encontrada custa 1 crédito; repetições também são cobradas. Com saldo insuficiente, todo o envio retorna 402 sem débito parcial.

Corpo:

```json
{
  "cpfs": [
    "12345678909",
    "52998224725"
  ]
}
```


HTTP 200 (application/json):

```json
{
  "results": [
    {
      "success": true,
      "data": {
        "name": "Pessoa de exemplo",
        "cpf": "12345678909",
        "birthday": "1990-06-15",
        "gender": null
      }
    },
    {
      "success": false,
      "data": null
    }
  ],
  "meta": {
    "remainingCredits": 19,
    "consultedAt": "2026-10-14T15:30:00.000Z"
  }
}
```


## GET /api/v1/saldo

Retorna o saldo atual, a franquia do plano, o consumo da franquia, os créditos adicionais e a próxima renovação. Não consome créditos, mas conta no limite de requisições. O saldo é informativo e não reserva créditos para outra requisição.

HTTP 200 (application/json):

```json
{
  "remainingCredits": 19,
  "includedCredits": 20,
  "includedUsed": 1,
  "extraCredits": 0,
  "renewsAt": "2026-11-01T03:00:00.000Z"
}
```


## GET /api/v1/historico

Retorna somente as operações da sua conta, da mais recente para a mais antiga, com documentos mascarados. rows contém a página; total é o número de itens que correspondem aos filtros, antes da paginação. Sem resultados: rows: [] e total: 0. Não consome créditos; conta no limite de requisições.

HTTP 200 (application/json):

```json
{
  "rows": [
    {
      "id": "10946738-6d63-40a0-bd01-5ee2a40de9cd",
      "document": "***.456.789-**",
      "status": "Encontrado",
      "type": "Individual",
      "date": "2026-10-14T15:30:00.000Z",
      "chargedCredits": 1
    }
  ],
  "total": 1
}
```


## GET /api/v1/historico.csv

Mesmos filtros e paginação do histórico JSON, inclusive o máximo de 500 linhas por chamada. Retorna text/csv; charset=utf-8 com BOM, separador ponto e vírgula e campos entre aspas. Use offset para exportar mais páginas. Erros continuam sendo JSON. Não consome créditos; conta no limite de requisições.

HTTP 200 (text/csv; charset=utf-8, BOM):

```csv
"Documento";"Resultado";"Tipo";"Data";"Créditos consumidos"
"***.456.789-**";"Encontrado";"Individual";"2026-10-14T15:30:00.000Z";"1"
```


## Filtros do histórico JSON e CSV

Todos opcionais. Use URLSearchParams ou equivalente. Ordenação: mais recente primeiro; novas consultas podem deslocar páginas enquanto você exporta.

- limit (integer): Itens por página: 1 a 500. Padrão: 500.
- offset (integer): Itens a pular, a partir de 0. Padrão: 0.
- from (string): Data inicial inclusiva, AAAA-MM-DD, no horário de Brasília.
- to (string): Data final inclusiva, AAAA-MM-DD, no horário de Brasília. Deve ser igual ou posterior a from.
- status (string): Filtre por resultado: Encontrado, Não encontrado ou Inválido.
- type (string): Filtre por tipo: Individual ou Em lote.
- q (string): Busca textual no documento mascarado, resultado e tipo. Até 120 caracteres; não busca nome ou CPF completo.

## Erros

Use status HTTP e error.code, não compare o texto da mensagem. Não há data, meta ou requestId no JSON de erro. X-Request-Id está no cabeçalho. Rotas GET não retornam erros de processamento de consultas (402, 413, 415, 503).

### HTTP 400 — invalid_cpf

CPF individual com formato ou dígitos inválidos. Corrija o CPF antes de reenviar.

```json
{
  "error": {
    "code": "invalid_cpf",
    "message": "Confira os 11 dígitos e digite um CPF válido."
  }
}
```

### HTTP 400 — request_error

JSON, lista ou filtros inválidos. O texto da mensagem explica o campo. Confira o corpo e os parâmetros. Não repita a mesma entrada.

```json
{
  "error": {
    "code": "request_error",
    "message": "Envie de 1 a 100 CPFs."
  }
}
```

### HTTP 401 — unauthorized

Credencial ausente. Envie Authorization: Bearer SUA_CHAVE.

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Entre na sua conta para continuar."
  }
}
```

### HTTP 401 — invalid_api_key

A chave não está ativa. Confira ou substitua a chave no painel.

```json
{
  "error": {
    "code": "invalid_api_key",
    "message": "Chave de API inválida ou revogada."
  }
}
```

### HTTP 401 — request_error

Formato do cabeçalho Authorization incorreto. Use Bearer, um espaço e a chave, sem aspas.

```json
{
  "error": {
    "code": "request_error",
    "message": "Use Authorization: Bearer SUA_CHAVE."
  }
}
```

### HTTP 402 — credits_exhausted

Saldo insuficiente para os registros encontrados. Adicione créditos. Um lote não debita parcialmente.

```json
{
  "error": {
    "code": "credits_exhausted",
    "message": "Créditos insuficientes. Este envio precisa de 1 crédito(s); seu saldo é 0."
  }
}
```

### HTTP 403 — email_unverified

Confirmação de e-mail pendente. Confirme o e-mail da conta antes de consultar.

```json
{
  "error": {
    "code": "email_unverified",
    "message": "Confirme seu e-mail para consultar e contratar um plano."
  }
}
```

### HTTP 403 — billing_hold

Conta com pendência de pagamento. Resolva a pendência pelo suporte.

```json
{
  "error": {
    "code": "billing_hold",
    "message": "Há uma pendência de pagamento. Entre em contato com o suporte."
  }
}
```

### HTTP 403 — request_error

Origem de navegador não permitida ou proteção de sessão ausente. Integre pelo backend com a chave de API.

```json
{
  "error": {
    "code": "request_error",
    "message": "Origem não autorizada."
  }
}
```

### HTTP 404 — request_error

Caminho ou método HTTP não suportado. Confira a rota e o método; não confunda com CPF não encontrado.

```json
{
  "error": {
    "code": "request_error",
    "message": "Endpoint não encontrado."
  }
}
```

### HTTP 413 — request_error

Corpo maior que 128.000 bytes. Reduza o corpo; envie no máximo 100 CPFs por lote.

```json
{
  "error": {
    "code": "request_error",
    "message": "A requisição ultrapassa 128 KB."
  }
}
```

### HTTP 415 — request_error

Content-Type incorreto no POST. Envie Content-Type: application/json.

```json
{
  "error": {
    "code": "request_error",
    "message": "Envie JSON no corpo da requisição."
  }
}
```

### HTTP 429 — rate_limited

Limite de requisições atingido. Respeite Retry-After (segundos). Use fila e tentativas limitadas.

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Muitas requisições. Aguarde um minuto e tente novamente."
  }
}
```

### HTTP 500 — server_error

Falha interna inesperada. Registre X-Request-Id. Não repita POST automaticamente: o resultado pode ser incerto.

```json
{
  "error": {
    "code": "server_error",
    "message": "Não foi possível concluir. Tente novamente."
  }
}
```

### HTTP 503 — catalog_unavailable

Catálogo indisponível. Aguarde e limite novas tentativas. Se persistir, contate o suporte.

```json
{
  "error": {
    "code": "catalog_unavailable",
    "message": "Catálogo temporariamente indisponível. Tente novamente."
  }
}
```

### HTTP 503 — catalog_busy

Fila de consultas ocupada. Reduza a concorrência e use espera progressiva com variação aleatória.

```json
{
  "error": {
    "code": "catalog_busy",
    "message": "Serviço ocupado. Tente novamente em instantes."
  }
}
```

### HTTP 503 — real_data_disabled

Consultas temporariamente desabilitadas no serviço. Aguarde a habilitação pelo responsável do serviço.

```json
{
  "error": {
    "code": "real_data_disabled",
    "message": "A operação com dados reais precisa ser habilitada pelo responsável."
  }
}
```


## Cabeçalhos e limites

O limite padrão é 120 requisições por minuto por conta. X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset aparecem quando disponíveis. Reset é timestamp Unix em segundos. Em 429 use Retry-After em segundos; os demais cabeçalhos de quota podem não aparecer. X-Request-Id identifica a requisição. Corpo POST: até 128.000 bytes.

Consultas individuais e lotes não têm garantia de idempotência. Nunca repita POST automaticamente após timeout, erro 500 ou falha de transporte. Um lote 402 não debita parcialmente. Saldo/histórico não consomem créditos, mas contam como requisições. Não há SLA de latência documentado.

## Compatibilidade

POST /api/v1/consulta é um alias legado de /api/v1/consultas. Use o plural nas integrações novas. Em erros de rota/método a API retorna 404 (não 405). O único nome de campo de nascimento é birthday. gender é M, F ou null; um gênero ausente não remove o registro. name é texto, cpf é string de 11 dígitos, birthday é data civil YYYY-MM-DD, consultedAt é instante UTC. Dados não representam score, dívida, identidade comprovada ou situação fiscal.

## FAQ

### Um HTTP 200 sempre significa que o CPF foi encontrado?

Não. HTTP 200 significa que a consulta foi processada. Verifique success antes de acessar data. Se success for false, data será null e não haverá consumo de crédito. HTTP 404 indica rota ou método incorreto, não um CPF ausente.

### Posso chamar a API diretamente do frontend?

A integração deve passar pelo seu backend ou função de servidor. Guarde a chave em uma variável de ambiente ou cofre de segredos. Nunca a coloque em variáveis VITE_ ou NEXT_PUBLIC_, código público, localStorage ou prompts. O playground desta página é uma ferramenta manual e envia a chave somente ao próprio CPF Direto.

### Como testo sem fazer uma consulta real?

O modo Exemplos do playground mostra os contratos sem rede, chave ou consumo de créditos. O modo Requisição real usa sua chave e o saldo da conta. Os dados ilustrativos não garantem que o mesmo CPF exista no catálogo. Não há um endpoint sandbox separado.

### O que acontece se repetir um CPF ou uma requisição?

Cada ocorrência encontrada consome um crédito, inclusive CPFs repetidos em um lote. As consultas não têm garantia de idempotência; um cabeçalho Idempotency-Key não elimina cobranças repetidas. Em timeout ou conexão interrompida, o servidor pode ter concluído a consulta. Não repita automaticamente.

### Quando os créditos são renovados?

No plano grátis, a franquia renova no início do mês no horário de Brasília. Em assinaturas pagas, a renovação acompanha o período efetivamente pago. A franquia não acumula; créditos adicionais permanecem até o consumo. Consulte renewsAt em /api/v1/saldo e não calcule a renovação pelo relógio do navegador.

### Gênero ausente significa que o CPF não foi encontrado?

Não. gender pode ser M, F ou null. Um gênero sem informação não muda success nem remove os demais dados do registro. A data de nascimento usa birthday, no formato AAAA-MM-DD.

### A resposta confirma identidade ou situação na Receita Federal?

A API retorna dados cadastrais presentes no catálogo. Não retorna score, dívidas, situação fiscal, comprovante de identidade ou consulta em tempo real à Receita Federal. consultedAt é o horário de processamento da consulta, não a data de atualização do cadastro.

### Como usar CPF Direto em uma aplicação com Auth0?

Auth0 autentica os usuários da sua aplicação. Seu backend valida o access token e a permissão do usuário; depois chama CPF Direto usando sua chave própria. Um token Auth0 não substitui a chave de CPF Direto. Use o prompt Com Auth0 para orientar seu agente de implementação.

### Há SDK, webhook ou MCP para consultas?

A integração documentada é HTTP com JSON e Bearer, sem SDK obrigatório. Os lotes são síncronos; não há job para acompanhar nem webhook de conclusão. Agentes podem ler OpenAPI e o guia em Markdown para implementar um cliente HTTP. Isso não representa um servidor MCP.
