Pular para o conteúdo
Documentação

Início rápido da API de consulta de CNPJ

Da chave de teste ao primeiro resultado: autenticação, criação da consulta, webhook assinado, sandbox, erros e idempotência, com exemplos em cURL e Python.

Visão geral

O ProCNPJ é uma API REST. Você envia o CNPJ, numérico ou alfanumérico, e recebe o desfecho da consulta e, quando o CNPJ é encontrado, razão social, nome fantasia, situação cadastral, datas, natureza jurídica, atividades econômicas (CNAE), capital social e endereço.

A consulta é assíncrona: a criação responde na hora com a consulta na fila, e o desfecho chega por webhook ou por consulta pelo id.

URL base
https://api.procnpj.com.br/v1
Endpoints da API v1
EndpointPara que serve
POST/v1/consultationsCria uma consulta e a coloca na fila.
GET/v1/consultations/{id}Devolve o status e o resultado de uma consulta.
GET/v1/consultationsLista as consultas da conta.
GET/v1/usageMostra o consumo e a cota do mês.
POST/v1/webhooksCadastra um destino de webhook.
GET/v1/webhooksLista os destinos cadastrados.
POST/v1/webhooks/deliveries/{id}/resendReenvia uma entrega de webhook.

Autenticação

Toda chamada leva a chave de API no cabeçalho Authorization. O prefixo da chave define o ambiente:

  • pcnpj_test_...: sandbox. Usa um simulador, não custa nada e não consome cota.
  • pcnpj_live_...: produção. Consulta de verdade, conta na cota.
Cabeçalho
Authorization: Bearer pcnpj_test_...

As chaves são criadas no console. O valor completo aparece uma única vez, na criação: o ProCNPJ guarda só o hash. Se a chave vazar, revogue no console e gere outra. Use a chave apenas no seu servidor, nunca no navegador ou no aplicativo.

Criar uma consulta

POST/v1/consultations

cnpj
Obrigatório. CNPJ numérico ou alfanumérico, com ou sem máscara. Os dígitos verificadores são validados antes de a consulta entrar na fila, pela regra que cobre os dois formatos.
external_reference
Opcional. Um identificador seu (até 120 caracteres), que volta na resposta e no webhook.
Idempotency-Key
Cabeçalho opcional. Veja Idempotência.

cURL

cURLPOST /v1/consultations
curl -X POST https://api.procnpj.com.br/v1/consultations \
  -H "Authorization: Bearer pcnpj_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: fornecedor-8841" \
  -d '{"cnpj": "11.222.333/0006-96",
       "external_reference": "fornecedor-8841"}'

Python

Pythonrequests
import requests

API = "https://api.procnpj.com.br/v1"
HEADERS = {"Authorization": "Bearer pcnpj_test_..."}

response = requests.post(
    f"{API}/consultations",
    headers={**HEADERS, "Idempotency-Key": "fornecedor-8841"},
    json={"cnpj": "11.222.333/0006-96", "external_reference": "fornecedor-8841"},
    timeout=10,
)
response.raise_for_status()
consultation = response.json()
print(consultation["id"], consultation["status"])  # status: pending

Resposta

A API responde 202 Accepted com a consulta na fila. Guarde o id.

JSON202 Accepted
{
  "id": "3f0e6a52-9c1b-4d7e-8a35-2b6f1c9d4e70",
  "status": "pending",
  "outcome": null,
  "cnpj": "11.222.333/0006-96",
  "external_reference": "fornecedor-8841",
  "sandbox": true,
  "result": null,
  "error": null,
  "personal_data_purged": false,
  "created_at": "2026-09-30T17:03:11.482913+00:00",
  "finished_at": null
}

Buscar o resultado

GET/v1/consultations/{id}

Enquanto a consulta está em andamento, o status é pending ou processing. Ela termina em done (concluída) ou failed (falhou). Você pode esperar o webhook ou consultar o id de tempos em tempos.

cURL

cURLGET /v1/consultations/{id}
ID=3f0e6a52-9c1b-4d7e-8a35-2b6f1c9d4e70
curl https://api.procnpj.com.br/v1/consultations/$ID \
  -H "Authorization: Bearer pcnpj_test_..."

Python

Pythonconsulta pelo id, com espera
import time


def wait_for_result(consultation_id, attempts=20, interval=2):
    """Consulta o id até a consulta sair de pending ou processing."""
    for _ in range(attempts):
        response = requests.get(
            f"{API}/consultations/{consultation_id}", headers=HEADERS, timeout=10
        )
        response.raise_for_status()
        consultation = response.json()
        if consultation["status"] in ("done", "failed"):
            return consultation
        time.sleep(interval)
    raise TimeoutError("Consulta ainda em andamento")


consultation = wait_for_result(consultation["id"])
if consultation["status"] == "failed":
    print("Falhou:", consultation["error"]["code"])  # não foi cobrada
elif consultation["outcome"] == "found":
    result = consultation["result"]
    print(result["legal_name"], result["registration_status"])
else:
    print("Desfecho:", consultation["outcome"])  # not_found

Resposta de uma consulta concluída

JSON200 OK
{
  "id": "3f0e6a52-9c1b-4d7e-8a35-2b6f1c9d4e70",
  "status": "done",
  "outcome": "found",
  "cnpj": "11.222.333/0006-96",
  "external_reference": "fornecedor-8841",
  "sandbox": true,
  "result": {
    "legal_name": "EMPRESA DE EXEMPLO LTDA",
    "trade_name": "EXEMPLO",
    "registration_status": "ativa",
    "registration_status_label": "Ativa",
    "registration_status_date": "2010-05-03",
    "opening_date": "2010-05-03",
    "head_office": true,
    "legal_nature": "206-2 - Sociedade Empresária Limitada",
    "main_activity": "62.01-5-01 - Desenvolvimento de programas de computador sob encomenda",
    "secondary_activities": [
      "62.02-3-00 - Desenvolvimento e licenciamento de programas customizáveis"
    ],
    "share_capital": "100000.00",
    "address": {
      "street": "AVENIDA DE EXEMPLO",
      "number": "1000",
      "complement": "SALA 1",
      "district": "CENTRO",
      "city": "SAO PAULO",
      "state": "SP",
      "zip_code": "01000-000"
    }
  },
  "error": null,
  "personal_data_purged": false,
  "created_at": "2026-09-30T17:03:11.482913+00:00",
  "finished_at": "2026-09-30T17:03:15.127406+00:00"
}

Campos da consulta

id
Identificador da consulta (UUID).
status
pending (na fila), processing (consultando), done (concluída) ou failed (falhou).
outcome
Desfecho da consulta concluída: found ou not_found.
cnpj
CNPJ consultado, formatado como 00.000.000/0000-00.
external_reference
A referência que você enviou na criação.
sandbox
true quando a consulta foi criada com chave de teste.
result
Dados cadastrais da empresa. Só vem preenchido quando o desfecho é found.
error
Código e mensagem da falha. Só vem preenchido quando o status é failed.
personal_data_purged
true depois que os dados da consulta foram apagados pelo prazo de retenção. A partir daí, result volta nulo.
created_at
Data e hora da criação.
finished_at
Data e hora do desfecho.

Desfechos

found
CNPJ encontrado. O CNPJ existe no cadastro. O resultado vem completo, com a situação cadastral.
not_found
CNPJ não encontrado. O número passa na conta dos dígitos verificadores, mas não existe no cadastro.

Campos de result

legal_name
Razão social.
trade_name
Nome fantasia, quando houver.
registration_status
Situação cadastral em código: ativa, baixada, suspensa, inapta, nula ou desconhecida.
registration_status_label
Situação cadastral por extenso, pronta para exibir.
registration_status_date
Data da situação cadastral, em AAAA-MM-DD.
opening_date
Data de abertura, em AAAA-MM-DD.
head_office
true para matriz, false para filial e null quando a fonte não informa.
legal_nature
Natureza jurídica.
main_activity
Atividade econômica principal (CNAE), com código e descrição.
secondary_activities
Lista das atividades econômicas secundárias (CNAE).
share_capital
Capital social, em texto.
address
Endereço do estabelecimento: street, number, complement, district, city, state e zip_code.

Quando a consulta falha

Se a primeira fonte não responde, o ProCNPJ tenta a próxima sozinho. A consulta só termina como failed quando nenhuma fonte respondeu ou quando a fonte recusou os dados. Nos dois casos ela não é cobrada e não consome cota. O campo error traz o motivo:

ENGINES_UNAVAILABLE
Nenhuma fonte respondeu. A consulta não é cobrada nem consome cota. Tente de novo.
INVALID_INPUT
A fonte recusou os dados informados. A consulta não é cobrada nem consome cota.

Webhooks

Com um destino cadastrado, o ProCNPJ avisa o seu servidor quando a consulta termina. São dois eventos: consultation.completed (consulta concluída) e consultation.failed (consulta que falhou).

O webhook não leva dado cadastral. Ele leva o id e o status, e o seu servidor busca o resultado por GET /v1/consultations/{id}, autenticado. Assim, os dados de um CNPJ nunca ficam em log de requisição recebida.

Cadastrar um destino

Pelo console ou pela API. O destino precisa ser um endereço público: endereços internos são recusados. O segredo de assinatura aparece uma única vez, na resposta da criação.

cURLPOST /v1/webhooks
curl -X POST https://api.procnpj.com.br/v1/webhooks \
  -H "Authorization: Bearer pcnpj_test_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://seusite.com.br/webhooks/procnpj",
       "description": "Cadastro de fornecedores"}'

# 201 Created: guarde o campo "secret", ele não volta a ser exibido

O que chega no seu servidor

HTTPPOST para a sua URL
Content-Type: application/json
X-ProCNPJ-Signature: sha256=9c1f...
X-ProCNPJ-Timestamp: 1790787795

{
  "event": "consultation.completed",
  "id": "3f0e6a52-9c1b-4d7e-8a35-2b6f1c9d4e70",
  "status": "done",
  "outcome": "found",
  "external_reference": "fornecedor-8841",
  "sandbox": true,
  "created_at": "2026-09-30T17:03:11.482913+00:00",
  "finished_at": "2026-09-30T17:03:15.127406+00:00"
}

Verificar a assinatura

A assinatura é um HMAC-SHA256, em hexadecimal, do texto {timestamp}.{corpo}, calculado com o segredo do destino. Ela chega em X-ProCNPJ-Signature com o prefixo sha256=, e o carimbo de tempo (segundos desde 1970) chega em X-ProCNPJ-Timestamp. Calcule sobre o corpo bruto da requisição, antes de interpretar o JSON, e compare em tempo constante.

Pythonverificação de assinatura
import hashlib
import hmac
import time

WEBHOOK_SECRET = "segredo-exibido-na-criacao"
TOLERANCE_SECONDS = 300  # exemplo: recuse avisos antigos, contra repetição


def is_valid_signature(raw_body: bytes, signature: str, timestamp: str) -> bool:
    """Confere a assinatura do ProCNPJ sobre "{timestamp}.{corpo}"."""
    if not signature or not timestamp.isdigit():
        return False
    if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS:
        return False
    signed_payload = timestamp.encode() + b"." + raw_body
    expected = hmac.new(WEBHOOK_SECRET.encode(), signed_payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)


# No seu endpoint: leia os cabeçalhos X-ProCNPJ-Signature e X-ProCNPJ-Timestamp,
# valide com o corpo bruto e só então busque o resultado pelo id.

Entrega e novas tentativas

  • Qualquer resposta 2xx do seu servidor confirma a entrega. Responda rápido e processe depois.
  • Resposta fora de 2xx, erro de rede ou demora contam como falha: o ProCNPJ tenta de novo, com intervalo crescente, até um limite de tentativas.
  • Redirecionamentos não são seguidos. Cadastre a URL final.
  • Esgotadas as tentativas, a entrega fica marcada como falha e pode ser reenviada pelo console ou por POST /v1/webhooks/deliveries/{id}/resend.
  • Trate o aviso de forma idempotente, pela dupla id e event: uma nova tentativa pode chegar depois de o seu servidor já ter processado a anterior.

Sandbox

Toda chamada feita com uma chave pcnpj_test_ roda no sandbox: mesmo fluxo da produção (fila, webhook, resultado), com um simulador no lugar da fonte. É grátis e não consome cota. O décimo segundo caractere do CNPJ, o último antes dos dígitos verificadores, escolhe o cenário. Vale para o CNPJ numérico e para o alfanumérico: uma letra nessa posição cai no cenário de situação ativa.

Cenários do sandbox pelo décimo segundo caractere do CNPJ
12º caractereCenário simuladoCNPJ de exemplo
0CNPJ não encontrado11.222.333/0000-09
2Situação baixada11.222.333/0002-62
3Situação suspensa11.222.333/0003-43
4Situação inapta11.222.333/0004-24
5Situação nula11.222.333/0005-05
9Falha simulada (a consulta termina como failed)11.222.333/0009-39
Qualquer outroSituação ativa11.222.333/0006-96

Os CNPJs de exemplo são sintéticos, com dígitos verificadores válidos. Para o formato alfanumérico, use 12.ABC.345/01DE-35, que volta como situação ativa. No sandbox, a razão social devolvida é sempre EMPRESA DE EXEMPLO LTDA, com endereço e atividades fictícios.

Erros

Use o status HTTP como primeira informação. Todo erro da API segue um formato único, com um code estável para o seu sistema e uma message para leitura humana. Quando há contexto, ele vem em details.

JSON429 Too Many Requests
{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "Cota mensal de consultas esgotada.",
    "details": {"monthly_limit": 100, "period": "2026-09"}
  }
}
Erros HTTP da API
StatusCódigoQuando aconteceO que fazer
400INVALID_REQUESTDados inválidos: CNPJ com dígitos verificadores errados ou campo obrigatório ausente.Corrija o campo apontado em details.
401UNAUTHENTICATEDChave de API ausente, inválida ou revogada.Confira o cabeçalho Authorization e o ambiente da chave.
402TRIAL_EXPIREDPeríodo de teste encerrado e conta sem plano.Fale com a equipe para seguir em produção. O sandbox continua disponível.
403REGISTRATION_INCOMPLETECadastro incompleto: falta aceitar os termos de uso no console.Um administrador da conta conclui o cadastro no console.
403FORBIDDENChave somente leitura tentando criar consulta ou webhook.Use uma chave com permissão de escrita.
429QUOTA_EXCEEDEDCota mensal de consultas esgotada.Espere a virada do mês (cabeçalho Retry-After) ou peça aumento de cota.
429RATE_LIMITEDLimite de requisições por minuto da chave excedido.Espere o tempo do cabeçalho Retry-After e tente de novo.

O período de teste dura 14 dias e a cota padrão é de 100 consultas por mês. Os bloqueios 402 e 429 acontecem antes de a consulta ser criada: nada é cobrado. Em 400, details aponta o campo com problema; em 401, message traz o motivo da recusa.

Idempotência

Redes falham, e repetir um POST sem cuidado criaria duas consultas. Para evitar isso, envie o cabeçalho Idempotency-Key com um valor único por operação (até 80 caracteres), como o id do seu cadastro.

  • Primeira chamada com a chave: cria a consulta e responde 202.
  • Chamada repetida com a mesma chave: devolve a consulta que já existe, com status 200, sem novo custo e sem consumir cota de novo.
  • A chave vale por conta: a mesma chave em outra conta não conflita.

Listagem e consumo

GET/v1/consultations lista as consultas da conta, da mais recente para a mais antiga, em páginas (count, next, previous e results). Filtros: status e external_reference.

cURLGET /v1/consultations
curl "https://api.procnpj.com.br/v1/consultations?status=done&external_reference=fornecedor-8841" \
  -H "Authorization: Bearer pcnpj_test_..."

GET/v1/usage devolve o consumo da conta: o período atual (period), as consultas usadas (used_in_period), a cota (monthly_limit), o fim do período de teste (trial_ends_at) e o histórico por mês, por status e por desfecho. Só a consulta concluída conta como uso: sandbox e consulta que falhou ficam de fora.

Referência OpenAPI

A referência completa da v1 é gerada do próprio código e fica sempre atualizada:

Dúvida de integração? Escreva para [email protected] com o id da consulta.