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, ounullna ú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.nullquando 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
- Referência gerada de
searchCnpjs. - Gerar filtro:
POST /v1/filters/generatetransforma uma descrição em linguagem natural nos filtros desta busca; é a ferramentagerar_filtrodo MCP. - Créditos, franquia e rate limit.
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.