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. Ela também exige ao menos um filtro além de cursor.
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
Os filtros se combinam com E lógico e ao menos um deles é obrigatório; sem filtro a resposta é 400 invalid_filter. Os parâmetros de código aceitam vários valores separados por vírgula (uf=SP,RJ, cnae=47,6201501): os valores de um mesmo parâmetro se combinam com OU, e municipio_excluir exclui todos os municípios da lista. O limite de valores por parâmetro está na referência gerada; acima dele a resposta é 400 invalid_filter. nome e socio_nome buscam texto contido, sem diferenciar maiúsculas. Não há ordenação escolhida pelo cliente: a ordem é sempre por CNPJ, o que torna a paginação estável.
Cada filtro tem um plano mínimo. Filtro acima do plano da conta responde 403 filter_not_in_plan, sem consulta e sem custo, e a mensagem diz qual plano libera o filtro.
| Parâmetro | Tipo | Valores | Plano mínimo |
|---|---|---|---|
uf |
string | Sigla da unidade federativa (PR, SP); aceita lista |
Starter |
municipio |
string | Código IBGE do município, sete dígitos (4106902 = Curitiba); aceita lista |
Starter |
cnae |
string | CNAE fiscal: subclasse de sete dígitos sem pontuação (1091102) ou um prefixo (classe, grupo ou divisão); aceita lista, com prefixos de tamanhos diferentes |
Starter |
porte |
string | ME, EPP ou DEMAIS; a correspondência com os códigos da Receita Federal está em Campos; aceita lista |
Starter |
situacao |
string | ATIVA, SUSPENSA, INAPTA, BAIXADA ou NULA; os códigos correspondentes estão em Campos; aceita lista |
Starter |
simples |
boolean | Optante do Simples Nacional | Starter |
mei |
boolean | Optante do MEI | Starter |
natureza |
string | Código da natureza jurídica, quatro dígitos; aceita lista | Starter |
capital_min, capital_max |
number | Faixa de capital social em reais | Starter |
abertura_de, abertura_ate |
date | Faixa de data de início de atividade, AAAA-MM-DD |
Starter |
regime |
string | LUCRO_PRESUMIDO, LUCRO_REAL, LUCRO_ARBITRADO, IMUNE ou ISENTA; casa também os regimes combinados que contêm o pedido; aceita lista |
Starter |
cnae_secundario |
boolean | Com true, cnae casa também os CNAEs secundários; exige cnae |
Starter |
natureza_categoria |
string | Primeiro dígito da natureza jurídica, de 1 a 5; aceita lista |
Starter |
matriz_filial |
string | MATRIZ ou FILIAL |
Starter |
filiais_min, filiais_max |
integer | Faixa de número de filiais | Starter |
situacao_data_de, situacao_data_ate |
date | Faixa de data da situação cadastral, AAAA-MM-DD; empresas sem data da situação não entram |
Starter |
motivo_situacao |
string | Código do motivo da situação, dois dígitos; aceita lista | Starter |
situacao_especial |
string | Código da situação especial, de 1 a 8; aceita lista |
Starter |
municipio_excluir |
string | Código IBGE do município a excluir, sete dígitos; aceita lista e exclui todos | Starter |
cep |
string | Prefixo do CEP, de um a oito dígitos | Starter |
bairro |
string | Nome do bairro, igual ao gravado | Starter |
com_email, com_site, com_telefone, com_celular |
boolean | true exige o contato; false exige que ele não exista |
Starter |
nome |
string | Texto contido na razão social ou no nome fantasia, de 3 a 100 caracteres | Starter |
socio_nome |
string | Texto contido no nome de algum sócio, de 3 a 100 caracteres | Pro |
socio_cnpj |
string | CNPJ de sócio pessoa jurídica, com ou sem pontuação; CPF não é aceito | Pro |
socio_qualificacao |
string | Código de qualificação do sócio, um ou dois dígitos; aceita lista | Pro |
cep_raio, raio_metros |
string, integer | Empresas a até raio_metros (de 100 a 20000) do CEP de oito dígitos, no município do CEP; os dois vêm juntos |
Pro |
faturamento |
string | ATE_360MIL, DE_360MIL_A_4_8MI ou ACIMA_4_8MI: a mesma faixa de faturamento, derivada do porte, que a consulta full mostra; aceita lista |
Pro |
funcionarios_min, funcionarios_max |
integer | Faixa do número esperado de funcionários (modelo estatístico da Oportunidados, arredondado), o mesmo da faixa que a consulta full mostra; empresa sem distribuição válida não entra |
Pro |
explicacao |
string | Ignorado: existe para que a saída de POST /v1/filters/generate possa ser repassada inteira; não filtra e não conta como filtro |
— |
cursor |
string | Cursor opaco devolvido em meta.next_cursor da página anterior; os demais filtros não podem mudar |
— |
Filtros de sócio respeitam os pedidos de remoção dos titulares: empresa com remoção ativa não aparece nessa busca nem na contagem.
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 +. Quando o saldo da conta não cobre uma página inteira, a página vem menor, com as empresas que o saldo paga, e next_cursor continua apontando para a seguinte.
Erros
| Status | Código | Quando |
|---|---|---|
| 400 | invalid_filter |
Filtro desconhecido, valor fora da tabela, lista acima do limite, par incompleto (cep_raio sem raio_metros, cnae_secundario sem cnae), cursor inválido ou nenhum filtro além de cursor |
| 401 | invalid_api_key, key_expired |
Chave ausente, revogada ou vencida |
| 402 | quota_exceeded |
Franquia e pacotes esgotados |
| 403 | insufficient_plan, filter_not_in_plan, payment_required |
Plano sem busca (Free; o menor plano com busca é o Starter) ou busca ainda fechada na liberação gradual; filtro acima do plano da conta; cobrança em atraso |
| 404 | not_found |
API desligada |
| 429 | rate_limited |
Requisições por minuto da conta excedidas, ou limite por IP antes da autenticação |
| 500 | internal_error |
Falha não prevista; nada é cobrado. Hoje inclui o tempo limite da busca, que passará a responder 504 |
| 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?
Sim, pelo parâmetro nome: ele casa as empresas cuja razão social ou nome fantasia contém o texto, sem diferenciar maiúsculas, e se combina com os demais filtros (por exemplo uf e municipio). Para o nome de um sócio, use socio_nome. Com o CNPJ em mãos, a consulta individual é mais direta.
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. Entre os planos pagos muda o conjunto de filtros: sócio, raio, faturamento e funcionários ficam nos planos acima do de entrada, e filtro acima do plano responde 403 filter_not_in_plan, também sem custo. A tabela de filtros mostra o plano mínimo de cada um.
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.