docs · base agosto/2026Atualizado em

GET /v1/cnpjs

Lista empresas por UF, município, CNAE, porte, situação cadastral, Simples, MEI, natureza jurídica, capital social e data de abertura. Paginação por cursor, cobrança por empresa retornada, perfil basic.

GET /v1/cnpjs lista empresas que atendem a um conjunto de filtros. Cada página traz até 20 empresas no perfil basic e custa 1 crédito por empresa retornada; página vazia custa 0. A paginação é por cursor opaco, com ordenação fixa por CNPJ. A busca exige um plano pago: no Free ela responde 403 insufficient_plan.

O que retorna

data é um array de empresas no perfil basic, os mesmos campos da consulta por CNPJ sem contatos e sócios. Para os contatos de uma empresa da lista, faça a consulta individual em full; os sinais has_phone, has_email e has_website já vêm na busca e dizem para quais vale a pena.

meta traz, além dos campos de toda resposta, três específicos da busca:

  • next_cursor: o cursor da página seguinte, ou null na última.
  • page_size: quantas empresas vieram nesta página. É campo de resposta; não existe parâmetro para pedir páginas maiores.
  • total_count_capped: texto com a contagem de empresas que atendem aos filtros. Abaixo do teto de exibição é exata; a partir dele vem com o sufixo + (por exemplo "10000+") e informa um mínimo. null quando não foi calculada. É uma contagem com teto, nunca uma estimativa.

Filtros

Todos os filtros são opcionais e se combinam com E lógico. Não há busca por texto livre nem ordenação escolhida pelo cliente; a ordem é sempre por CNPJ, o que torna a paginação estável.

Parâmetro Tipo Valores
uf string Sigla da unidade federativa (PR, SP)
municipio string Código IBGE do município, sete dígitos (4106902 = Curitiba)
cnae string CNAE fiscal: subclasse de sete dígitos sem pontuação (1091102) ou um prefixo (classe, grupo ou divisão)
porte string ME, EPP ou DEMAIS; a correspondência com os códigos da Receita Federal está em Campos
situacao string ATIVA, SUSPENSA, INAPTA, BAIXADA ou NULA; os códigos correspondentes estão em Campos
simples boolean Optante do Simples Nacional
mei boolean Optante do MEI
natureza string Código da natureza jurídica, quatro dígitos
capital_min, capital_max number Faixa de capital social em reais
abertura_de, abertura_ate date Faixa de data de início de atividade, AAAA-MM-DD
cursor string Cursor opaco devolvido em meta.next_cursor da página anterior; os demais filtros não podem mudar

Filtro desconhecido ou valor fora do enum responde 400 invalid_filter sem custo. Na busca, porte e situação são filtrados pelos nomes acima; na resposta, os mesmos campos vêm como código e descrição da Receita Federal, listados em Campos da resposta.

Exemplo de requisição

curl
# padarias ativas em Curitiba (CNAE 1091-1/02), optantes do Simples
curl "https://api.cnpj.ia.br/v1/cnpjs?uf=PR&municipio=4106902&cnae=1091102&situacao=ATIVA&simples=true" \
  -H "Authorization: Bearer $CNPJIA_KEY"

# próxima página
curl "https://api.cnpj.ia.br/v1/cnpjs?uf=PR&municipio=4106902&cnae=1091102&situacao=ATIVA&simples=true&cursor=<meta.next_cursor>" \
  -H "Authorization: Bearer $CNPJIA_KEY"
Python
import os, requests

HEADERS = {"Authorization": f"Bearer {os.environ['CNPJIA_KEY']}"}
filtros = {"uf": "PR", "municipio": "4106902", "cnae": "1091102", "situacao": "ATIVA", "simples": "true"}

def paginas(filtros: dict):
    cursor = None
    while True:
        params = {**filtros, **({"cursor": cursor} if cursor else {})}
        r = requests.get("https://api.cnpj.ia.br/v1/cnpjs", params=params, headers=HEADERS, timeout=10)
        r.raise_for_status()
        body = r.json()
        yield from body["data"]
        cursor = body["meta"].get("next_cursor")
        if not cursor:
            break

for empresa in paginas(filtros):
    print(empresa["cnpj"], empresa["razao_social"])
Node
const headers = { Authorization: `Bearer ${process.env.CNPJIA_KEY}` };
const filtros = { uf: "PR", municipio: "4106902", cnae: "1091102", situacao: "ATIVA", simples: "true" };

async function* paginas(filtros) {
  let cursor;
  do {
    const url = new URL("https://api.cnpj.ia.br/v1/cnpjs");
    Object.entries({ ...filtros, ...(cursor && { cursor }) }).forEach(([k, v]) => url.searchParams.set(k, v));
    const res = await fetch(url, { headers });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const { data, meta } = await res.json();
    yield* data;
    cursor = meta.next_cursor;
  } while (cursor);
}

for await (const e of paginas(filtros)) console.log(e.cnpj, e.razao_social);

Paginação e custo

Repita a chamada com os mesmos filtros, passando em cursor o valor de meta.next_cursor da página anterior, até ele vir null. Mudar um filtro no meio invalida o cursor. Cada página cobra 1 crédito por empresa retornada, então percorrer todas as empresas custa tantos créditos quantas empresas houver; total_count_capped na primeira página dá esse número quando está abaixo do teto, e um mínimo quando vem com +.

Erros

Status Código Quando
400 invalid_filter Filtro desconhecido, valor fora da tabela ou cursor inválido
401 invalid_api_key, key_expired Chave ausente, revogada ou vencida
402 quota_exceeded Franquia e pacotes esgotados
403 insufficient_plan Plano sem busca (Free); o menor plano com busca é o Starter
429 rate_limited Requisições por minuto da conta excedidas
503 maintenance Janela de atualização da base
504 upstream_timeout Tempo limite na consulta; nada é cobrado

Relacionados

Perguntas frequentes

Posso buscar por nome da empresa?

Não no v0. A busca é por filtros estruturados: UF, município, CNAE, porte, situação, Simples, MEI, natureza jurídica, capital e data de abertura. Se você tem o nome mas não o CNPJ, a consulta individual é o caminho quando o CNPJ for conhecido; texto livre está fora do contrato atual.

Por que a busca não vem no plano Free?

Porque uma única busca pode percorrer milhares de empresas e a franquia do Free é feita para testar a integração. A busca está em todos os planos pagos; no Free ela responde 403 insufficient_plan sem consumir crédito.

Como sei quanto uma busca vai custar antes de rodar?

Pela primeira página: meta.total_count_capped traz quantas empresas atendem aos filtros, exato abaixo do teto de exibição e um mínimo quando vem com +, e a cobrança é por empresa retornada. Se o número passar do que você quer gastar, refine os filtros antes de paginar.

A ordem dos resultados muda entre páginas?

Não. A ordenação é fixa por CNPJ e a paginação usa cursor, então uma empresa não aparece duas vezes nem some entre páginas enquanto os filtros forem os mesmos. Mudar um filtro invalida o cursor.

A busca devolve telefone e e-mail?

Não. A busca devolve o perfil basic de cada empresa, com os sinais has_phone, has_email e has_website. Para os contatos, consulte a empresa em full; o sinal evita pagar o custo do full por uma empresa sem contato.