Documentação da APIuso interno

Painel de consulta OpenAPI

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:

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
}

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