Integração com a API de CNPJ
Guia para sistemas internos que consultam CNPJ por esta API: cartão, regime tributário, quadro societário e pesquisa com filtros, sobre a base aberta da Receita Federal.
| Endereço | https://cnpj.4uto.com.br (o provisório https://bolgest-cnpj-api.tpcjq6.easypanel.host continua respondendo) |
| Na mesma VPS | serviços do projeto bolgest no EasyPanel podem usar http://bolgest_cnpj-api:8000 (rede interna, sem passar pela internet) |
| Formato | JSON UTF-8 · datas AAAA-MM-DD · códigos sempre como texto (zeros à esquerda) |
| Autenticação | cabeçalho X-API-Key |
| Este guia | na própria API, em /documentacao (link no topo do painel) |
| Especificação | GET /openapi.json e documentação interativa em /docs (enquanto API_DOCS_ATIVAS=true) |
| Base | Receita Federal, atualizada todo mês (extração no 2º sábado); regime da ECF até o ano-calendário 2024 |
1. Chave de acesso
Cada sistema usa a sua chave, com só os escopos de que precisa. Quem opera a API cria a chave
no Console do serviço cnpj-api (EasyPanel):
cnpjctl chave criar --cliente "4UTO Office" --escopos cnpj,regime --limite 300
A chave (cnpj_live_ + 32 caracteres) aparece uma única vez. Guarde-a como segredo do sistema
(variável de ambiente ou cofre) — nunca no código, no Git ou em JavaScript que roda no navegador
de terceiros. Para revogar: cnpjctl chave revogar --prefixo cnpj_live_xxxxxxxx (vale em até 60 s).
Chave com prazo: --validade-dias 30 faz a chave parar de valer depois de 30 dias; aí é gerar
outra e trocar no sistema. GET /v1/meta diz até quando ela vale (chave.expira_em), e a chave
vencida recebe 401 com {"erro": "chave expirada em 25/10/2026; gere outra"}.
| Escopo | Libera | Para quem |
|---|---|---|
cnpj |
cartão do CNPJ | sistemas internos e parceiros |
regime |
regime tributário | sistemas internos e parceiros |
busca |
pesquisa com filtros | só sistemas internos |
socios |
quadro societário | só uso interno (nome + dígitos do CPF montam o mapa de empresas de uma pessoa) |
processos |
processos judiciais por CNPJ, CPF ou nome | só sistemas do escritório (a consulta ao Jus.br sai com o login do advogado) |
/v1/meta e /v1/dominios/* aceitam qualquer chave válida.
Limite de uso: cada chave tem um limite de consultas por minuto (padrão 60; o da chave acima é
300). Passou do limite → 429 com o cabeçalho Retry-After (segundos até liberar).
2. Consultar um CNPJ
GET /v1/cnpj/{cnpj}
X-API-Key: cnpj_live_...
{cnpj} com ou sem pontuação, sem a barra (46272132000173 ou 46.272.132-0001-73). Aceita o
CNPJ alfanumérico (letras nas 12 primeiras posições). Dígito verificador errado → 422; CNPJ válido
que não está na base → 404.
{
"cnpj": "46272132000173",
"cnpj_formatado": "46.272.132/0001-73",
"cnpj_basico": "46272132",
"razao_social": "PJMEI INOVA SIMPLES (I.S.)",
"nome_fantasia": null,
"matriz_filial": {"codigo": "1", "descricao": "Matriz"},
"natureza_juridica": {"codigo": "2348", "descricao": "Empresa Simples de Inovação"},
"qualificacao_responsavel": {"codigo": "65", "descricao": "Titular Pessoa Física Residente ou Domiciliado no Brasil"},
"porte": {"codigo": "01", "descricao": "Microempresa"},
"capital_social": 10000.0,
"ente_federativo_responsavel": null,
"situacao_cadastral": {"codigo": "02", "descricao": "Ativa", "data": "2022-05-05",
"motivo": {"codigo": "00", "descricao": "SEM MOTIVO"}},
"data_inicio_atividade": "2022-05-05",
"cnae_principal": {"codigo": "6203100", "descricao": "Desenvolvimento e licenciamento de programas de computador não-customizáveis"},
"cnaes_secundarios": [
{"codigo": "4761001", "descricao": "Comércio varejista de livros"},
{"codigo": "5811500", "descricao": "Edição de livros"}
],
"endereco": {"tipo_logradouro": "RUA", "logradouro": "ARISTIDES CARAMURU", "numero": "35",
"complemento": "ED. ERNESTRO SARAIVA - APT 1.205", "bairro": "MUQUICABA",
"cep": "29215180", "uf": "ES",
"municipio": {"codigo_receita": "5647", "nome": "GUARAPARI"}, "exterior": null},
"contato": {"telefones": ["2835217048"], "fax": null, "email": "JDDANZI@GMAI.COM"},
"simples": {"optante": true, "desde": "2023-01-01", "ate": null},
"mei": {"optante": false, "desde": null, "ate": null},
"situacao_especial": null,
"fonte": "Receita Federal do Brasil — Dados Abertos do CNPJ (CC-BY)",
"versao_base": {"mes": "2026-09", "data_extracao": "2026-09-12", "amostra": false}
}
Observações:
- A API não corrige dados. Devolve o que a Receita publica, com os erros de digitação do
cadastro (
GMAI.COM,ERNESTROno exemplo acima). municipio.codigo_receitaé o código da Receita, não o do IBGE.- Telefones vêm com DDD, só dígitos (
2835217048= (28) 3521-7048). - Situação cadastral:
01Nula ·02Ativa ·03Suspensa ·04Inapta ·08Baixada. - Porte:
00Não informado ·01Microempresa ·03Empresa de Pequeno Porte ·05Demais.
3. Regime tributário
GET /v1/cnpj/{cnpj}/regime
Regra: o Simples da base mensal vem primeiro (MEI, depois Simples Nacional). Quem não é do
Simples recebe o regime da ECF mais recente da própria empresa (as ECFs de SCP são ignoradas).
Sem nenhum dos dois → "Não identificado".
{
"cnpj": "46272132000173",
"cnpj_formatado": "46.272.132/0001-73",
"regime": "Simples Nacional",
"origem": "Simples Nacional (base mensal da Receita)",
"desde": "2023-01-01",
"ano_referencia": null,
"historico_ecf": [],
"observacao": "Optante pelo Simples na extração mensal mais recente da Receita. A data mostra só o período atual de opção.",
"fonte": "Receita Federal do Brasil — Dados Abertos do CNPJ e Regimes Tributários/ECF (CC-BY)",
"versao_base": {"mes": "2026-09", "data_extracao": "2026-09-12", "amostra": false}
}
Empresa fora do Simples (Banco do Brasil, 00000000000191):
{
"regime": "Lucro Real",
"origem": "ECF",
"desde": null,
"ano_referencia": 2024,
"historico_ecf": [{"ano": 2024, "formas": ["LUCRO REAL"]}, {"ano": 2023, "formas": ["LUCRO REAL"]}, "…"],
"observacao": "Regime declarado na ECF do ano-calendário 2024; pode ter mudado depois."
}
Valores possíveis de regime: MEI, Simples Nacional, Lucro Real, Lucro Presumido,
Lucro Arbitrado, Imune de IRPJ, Isento do IRPJ, formas mistas (Lucro Presumido/Real) e
Não identificado. Mostre sempre o ano_referencia quando a origem for a ECF: a base de
regimes vai até 2024, e a empresa pode ter mudado depois.
4. Quadro societário (escopo socios)
GET /v1/cnpj/{cnpj}/socios
{
"cnpj": "46272132000173",
"cnpj_basico": "46272132",
"socios": [
{
"identificador": {"codigo": "2", "descricao": "Pessoa Física"},
"nome": "JACQUES DOUGLAS DANZI",
"cpf_cnpj": "***XXXXXX**",
"qualificacao": {"codigo": "65", "descricao": "Titular Pessoa Física Residente ou Domiciliado no Brasil"},
"data_entrada": "2022-05-05",
"faixa_etaria": {"codigo": "5", "descricao": "41 a 50 anos"},
"pais": null,
"representante_legal": null
}
]
}
O CPF já vem mascarado pela Receita (3 primeiros e 2 últimos dígitos ocultos). Nunca tente
reconstruí-lo. Sócio pessoa jurídica traz o CNPJ completo em cpf_cnpj.
5. Pesquisa avançada (escopo busca)
GET /v1/busca?municipio=5647&situacao=02&limite=100&pagina=1
| Parâmetro | Tipo | O que filtra |
|---|---|---|
uf |
ES |
estado |
municipio |
5699 |
código da Receita (lista em /v1/dominios/municipios?uf=ES) |
cep |
29165 |
CEP completo ou o começo |
bairro |
texto | contém, sem diferenciar acento/caixa |
nome |
texto | razão social ou nome fantasia contém |
cnae |
4781400 |
CNAE principal |
cnae_secundaria |
true |
inclui quem tem o CNAE como secundária |
natureza |
2135 |
natureza jurídica |
situacao |
02 ou 02,08 |
uma ou mais situações |
porte |
01 |
porte da empresa |
mei / simples |
true / false |
optante (false = não optante) |
matriz |
true / false |
só matriz / só filial |
aberta_desde / aberta_ate |
2025-01-01 |
data de abertura |
capital_min / capital_max |
50000 |
capital social em R$ |
ddd |
27 |
DDD de algum dos telefones |
com_telefone / com_email |
true |
tem telefone / e-mail |
telefone |
fixo / celular |
só fixo / só celular |
pagina |
1 |
começa em 1 |
limite |
100 |
itens por página, até 1.000 |
Regras (400 se não forem cumpridas): exige uf, municipio, cep ou cnae; nome e
bairro exigem municipio ou cep; cnae_secundaria exige uf, municipio ou cep. Consulta
que passa de 15 s → 400 pedindo filtros mais específicos.
Resposta (trecho; Guarapari/ES, ativas, base 2026-09):
{
"total": 24380,
"total_exato": true,
"pagina": 1,
"limite": 100,
"paginas": 244,
"tem_proxima": true,
"resultados": [
{
"cnpj": "46272132000173", "cnpj_formatado": "46.272.132/0001-73", "matriz": true,
"razao_social": "PJMEI INOVA SIMPLES (I.S.)", "nome_fantasia": null,
"situacao_cadastral": {"codigo": "02", "descricao": "Ativa"},
"uf": "ES", "municipio": {"codigo_receita": "5647", "nome": "GUARAPARI"},
"bairro": "MUQUICABA", "cep": "29215180",
"cnae_principal": {"codigo": "6203100", "descricao": "Desenvolvimento e licenciamento de programas de computador não-customizáveis"},
"data_inicio_atividade": "2022-05-05", "natureza_juridica": "2348",
"porte": {"codigo": "01", "descricao": "Microempresa"}, "capital_social": 10000.0,
"telefones": ["2835217048"], "email": "JDDANZI@GMAI.COM", "mei": false, "simples": true
}
],
"fonte": "Receita Federal do Brasil — Dados Abertos do CNPJ (CC-BY)",
"versao_base": {"mes": "2026-09", "data_extracao": "2026-09-12", "amostra": false}
}
Total: a contagem tem 5 s. Em pesquisas muito grandes ela é pulada: total, paginas = null
e total_exato = false. A lista continua completa — pagine por tem_proxima, não por paginas:
pagina = 1
while True:
r = api.get("/v1/busca", params={**filtros, "pagina": pagina, "limite": 1000})
processar(r["resultados"])
if not r["tem_proxima"]:
break
pagina += 1
Resultados em ordem de CNPJ, estáveis entre páginas da mesma versão da base.
6. Processos judiciais (escopo processos, só uso interno)
Diz em que processos um CNPJ, um CPF ou um nome aparece como parte. A API pergunta ao monitor jurídico do escritório, que consulta:
| Consulta | Fonte | Cobre |
|---|---|---|
| CNPJ ou CPF | Portal de Serviços do Jus.br (PDPJ/CNJ) | busca nacional pelo documento |
| nome | Comunica PJe (Diário de Justiça Eletrônico Nacional) | só processos com publicação em diário; traz homônimos |
Só para sistemas do escritório. A consulta ao Jus.br sai com o login do Douglas (OAB). Por
isso o escopo não é cedido a terceiros, o limite é baixo (10 por minuto por chave, 30 somando
todas as chaves) e cada resposta fica 10 minutos em cache (em_cache: true).
GET /v1/cnpj/{cnpj}/processos
POST /v1/processos/busca
No POST, mande exatamente um destes campos: {"cnpj": "…"}, {"cpf": "…"} ou
{"nome": "…"}. CPF e nome vão sempre no corpo, nunca na URL, porque a URL fica gravada em
log de acesso. O CPF é conferido pelo dígito verificador; o nome precisa de ao menos 5 letras e
nenhum número.
curl -s -X POST https://cnpj.4uto.com.br/v1/processos/busca \
-H "X-API-Key: $CNPJ_API_KEY" -H "Content-Type: application/json" \
-d '{"cpf": "529.982.247-25"}'
{
"consulta": {"tipo": "cnpj", "valor": "11222333000181", "razao_social": "EMPRESA EXEMPLO LTDA"},
"fonte": {"codigo": "pdpj", "nome": "Portal de Serviços do Jus.br (PDPJ/CNJ)"},
"total": 1,
"ocultos_por_sigilo": 0,
"processos": [
{
"numero": "50089593220268080011",
"numero_formatado": "5008959-32.2026.8.08.0011",
"tribunal": "TJES",
"grau": "G1",
"classe": "Procedimento do Juizado Especial Cível",
"assunto": "Indenização por Dano Moral",
"orgao_julgador": "1º Juizado Especial Cível de Vitória",
"ajuizado_em": "2026-06-24",
"valor_causa": 1000.5,
"partes": [{"polo": "ATIVO", "nome": "FULANO DE TAL"}, {"polo": "PASSIVO", "nome": "EMPRESA EXEMPLO LTDA"}],
"ultimo_movimento": {"data": "2026-09-08T11:57:17", "descricao": "Expedição de Certidão"},
"publicacoes": []
}
],
"observacao": "Busca nacional pelo documento no Jus.br. Processos em segredo de justiça não aparecem.",
"consultado_em": "2026-09-25T10:12:03-03:00",
"em_cache": false
}
- Sigilo: processo que o Jus.br não marca como público não aparece;
ocultos_por_sigilodiz quantos ficaram de fora. - Resultado do diário (
fonte.codigo = "comunica"): cada processo trazpublicacoes(data e trecho),partesvem vazio e os demais campos vêmnull. Na busca por CNPJ isso acontece quando o Jus.br não acha nada ou está indisponível: a API busca pela razão social no diário, e aobservacaoavisa. - Acesso ao Jus.br vencido: o login é renovado a cada 3 horas pelo computador do escritório.
Enquanto está vencido, CPF responde
503e CNPJ cai para a busca pela razão social. - Demora: a consulta ao Jus.br leva de 5 a 20 s, e até 2 minutos no pior caso. Use timeout de 120 s e não chame em tela que espera resposta instantânea.
- CNPJ exato: a busca é pelo CNPJ informado. Filial tem CNPJ próprio e processos próprios.
- Auditoria: fica registrado quem consultou o quê; do CPF, só os 6 dígitos do meio, como a Receita publica.
7. Versão da base e tabelas de apoio
GET /v1/meta
{
"versao_base": {"mes": "2026-09", "data_extracao": "2026-09-12", "ativada_em": "2026-09-24T18:22:…-03:00", "amostra": false},
"contagens": {"empresas": …, "estabelecimentos": …, "simples": …, "socios": …},
"proxima_atualizacao_prevista": "2026-10-12",
"regimes_tributarios": {"carregado_em": "2026-09-24T…", "ano_mais_recente": 2024},
"chave": {"cliente": "4UTO Office", "escopos": ["cnpj", "regime"], "limite_por_minuto": 300, "expira_em": null},
"fonte": "Receita Federal do Brasil — Dados Abertos do CNPJ (CC-BY)"
}
| Rota | Devolve |
|---|---|
GET /v1/dominios/municipios?uf=ES&q=serra |
{"itens": [{"codigo": "5699", "descricao": "SERRA", "uf": "ES", "estabelecimentos": …}]} |
GET /v1/dominios/cnaes?q=vestuario |
até 20 CNAEs por código ou descrição (sem acento) |
GET /v1/dominios/naturezas |
naturezas jurídicas |
GET /health · GET /health?estrito=1 |
pública; estrito confere banco e versão no ar (monitoramento) |
8. Erros
Corpo sempre {"erro": "mensagem"} (no 422, também "detalhes": [{"campo", "problema"}]).
| Status | Quando | O que fazer |
|---|---|---|
400 |
regra da busca não cumprida, ou pesquisa passou de 15 s | ajuste os filtros; não repita igual |
401 |
sem chave, chave errada, revogada ou expirada | confira o segredo do sistema; se expirou, gere outra |
403 |
chave sem o escopo da rota | peça a chave com o escopo |
404 |
CNPJ válido que não está na base | pode ter sido aberto depois da extração do mês — trate como "não encontrado" |
422 |
CNPJ com dígito errado, parâmetro inválido | valide antes de chamar |
429 |
limite por minuto da chave (em processos, também o limite geral) | espere Retry-After segundos e tente de novo |
502 |
processos: o Jus.br ou o diário não respondeu | tente mais tarde |
503 |
base ainda não carregada (só na primeira carga); em processos, acesso ao Jus.br vencido | tente mais tarde |
504 |
processos: a consulta passou de 120 s | tente mais tarde |
5xx |
falha do servidor | tente de novo com espera crescente (1, 2, 4 s…) |
9. Exemplos
curl
curl -H "X-API-Key: $CNPJ_API_KEY" https://cnpj.4uto.com.br/v1/cnpj/46272132000173
Python (httpx; serve também com requests)
import os, time
import httpx
class ApiCnpj:
def __init__(self, base="https://cnpj.4uto.com.br"):
self.http = httpx.Client(base_url=base, timeout=20,
headers={"X-API-Key": os.environ["CNPJ_API_KEY"]})
def _get(self, caminho, **params):
for tentativa in range(4):
r = self.http.get(caminho, params=params or None)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", "5")))
continue
if r.status_code >= 500:
time.sleep(2 ** tentativa)
continue
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
r.raise_for_status()
def cartao(self, cnpj):
return self._get(f"/v1/cnpj/{''.join(c for c in cnpj if c.isalnum())}")
def regime(self, cnpj):
return self._get(f"/v1/cnpj/{''.join(c for c in cnpj if c.isalnum())}/regime")
def buscar(self, **filtros):
return self._get("/v1/busca", **filtros)
api = ApiCnpj()
c = api.cartao("46.272.132/0001-73")
print(c["razao_social"], c["situacao_cadastral"]["descricao"], api.regime(c["cnpj"])["regime"])
JavaScript / TypeScript (no servidor — Node 18+; a chave não vai para o navegador)
const BASE = "https://cnpj.4uto.com.br";
export async function consultarCnpj(cnpj) {
const limpo = cnpj.replace(/[^0-9A-Za-z]/g, "").toUpperCase();
const r = await fetch(`${BASE}/v1/cnpj/${limpo}`, {
headers: { "X-API-Key": process.env.CNPJ_API_KEY },
signal: AbortSignal.timeout(20000),
});
if (r.status === 404) return null;
if (r.status === 429) throw new Error(`limite: tente em ${r.headers.get("Retry-After")} s`);
if (!r.ok) throw new Error((await r.json()).erro);
return r.json();
}
PHP
$ch = curl_init("https://cnpj.4uto.com.br/v1/cnpj/46272132000173");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["X-API-Key: " . getenv("CNPJ_API_KEY")],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
]);
$cartao = json_decode(curl_exec($ch), true);
10. Boas práticas
- Valide o CNPJ antes de chamar (dígito verificador) e mande só dígitos e letras.
- Guarde em cache por CNPJ +
versao_base.mes: a base só muda uma vez por mês.GET /v1/metadiz a versão atual e a próxima atualização. - Mostre a data da base (
versao_base.data_extracao) junto do dado: ele tem até ~1 mês de defasagem. Para "está ativa hoje?", combine com uma consulta pontual em tempo real. - Não chame a cada tecla digitada; espere o CNPJ completo.
- Pesquisas grandes: prefira
limite=1000e pagine portem_proxima. - Atribuição: a licença CC-BY exige citar a fonte — use o campo
fonte. - LGPD: telefone e e-mail são dados públicos da Receita, mas prospecção ativa exige base legal (legítimo interesse documentado), transparência e opt-out. Toda consulta fica registrada (chave, rota, CNPJ, IP) por 12 meses.