Exemplo

Consultar um CNPJ em curl, Python e Node.js

Consulta de um CNPJ na API do cnpj.ia.br em curl, Python (requests) e Node.js (fetch), nos perfis basic e full, com timeout, espera pelo Retry-After e a demonstração sem chave.

Python Node.js curl Código no GitHub

Uma consulta é um GET /v1/cnpjs/{cnpj}?profile=basic com a chave no header Authorization. O exemplo faz isso em curl, Python e Node.js, tira a pontuação do CNPJ antes de montar a URL, corta a chamada em 30 segundos e, em 429 ou 503, espera o Retry-After e repete uma vez. Sem chave, o mesmo script roda pela demonstração (GET /v1/demo).

O problema

Todo cadastro, CRM ou automação que recebe um CNPJ precisa confirmar que ele existe, está ativo e pertence a quem diz. A chamada é simples; o que quebra em produção é o resto: a barra de 00.000.000/0001-91 dentro do caminho da URL, que derruba a rota, uma chamada sem timeout que prende o processo, e o 429 repetido antes do prazo, que só gera outro 429.

O fluxo

  1. Normaliza o CNPJ: sem pontos, barra e hífen. Maiúsculas e minúsculas a API resolve.
  2. Chama GET /v1/cnpjs/{cnpj} com profile=basic (cadastro, CNAE, endereço e os sinais has_phone, has_email) ou profile=full (mais telefones, e-mail, site, sócios com CPF mascarado e as faixas).
  3. Em 429 ou 503, lê o Retry-After: até 60 segundos, espera e repete uma vez; acima disso, para com o request_id.
  4. Imprime o JSON com data e meta. meta.data_as_of é a data da base, e meta.credits_charged, o que a chamada custou.

O código

Python, com requests (python consulta.py 00000000000191 --profile full, ou --demo sem chave):

"""Consulta um CNPJ na API do cnpj.ia.br.

    CNPJIA_KEY=... python consulta.py                       # 00000000000191, perfil basic
    CNPJIA_KEY=... python consulta.py 00.000.000/0001-91 --profile full
    python consulta.py --demo                               # sem chave, pela demonstração

A demonstração (GET /v1/demo) não pede chave, aceita só os CNPJs públicos da
allowlist e devolve o perfil full sem o array socios.
"""

import argparse
import json
import os
import re
import sys
import time

import requests

API = "https://api.cnpj.ia.br"
ESPERA_MAXIMA = 60  # segundos; acima disso, o script para em vez de segurar o processo


def get(url, headers=None, params=None):
    """GET com timeout; em 429/503 espera o Retry-After e repete uma vez."""
    for tentativa in (1, 2):
        resp = requests.get(url, headers=headers, params=params, timeout=(5, 30))
        if tentativa == 1 and resp.status_code in (429, 503):
            espera = resp.headers.get("Retry-After", "")
            if espera.isdigit() and int(espera) <= ESPERA_MAXIMA:
                print(f"HTTP {resp.status_code}: aguardando {espera}s (Retry-After)", file=sys.stderr)
                time.sleep(int(espera))
                continue
        return resp


def main():
    parser = argparse.ArgumentParser(description="Consulta um CNPJ na API do cnpj.ia.br.")
    parser.add_argument("cnpj", nargs="?", default="00000000000191")
    parser.add_argument("--profile", choices=["basic", "full"], default="basic")
    parser.add_argument("--demo", action="store_true", help="usa GET /v1/demo, sem chave")
    args = parser.parse_args()

    # Tira a pontuação antes de montar a URL: a barra de "00.000.000/0001-91"
    # dentro do caminho quebra a rota. Maiúsculas e minúsculas a API normaliza.
    cnpj = re.sub(r"[./-]", "", args.cnpj)

    try:
        if args.demo:
            resp = get(f"{API}/v1/demo", params={"cnpj": cnpj})
        else:
            chave = os.environ.get("CNPJIA_KEY")
            if not chave:
                print("Defina CNPJIA_KEY, ou use --demo para a demonstração sem chave.", file=sys.stderr)
                sys.exit(2)
            resp = get(
                f"{API}/v1/cnpjs/{cnpj}",
                headers={"Authorization": f"Bearer {chave}"},
                params={"profile": args.profile},
            )
    except requests.RequestException as exc:
        sys.exit(f"Falha de rede ou timeout: {exc.__class__.__name__}")

    try:
        corpo = resp.json()
    except ValueError:
        sys.exit(f"HTTP {resp.status_code}: resposta sem JSON")

    print(json.dumps(corpo, ensure_ascii=False, indent=2))

    if not resp.ok:
        erro = corpo.get("error", {})
        print(
            f"HTTP {resp.status_code}: {erro.get('code')}: {erro.get('message')} "
            f"(request_id {erro.get('request_id')})",
            file=sys.stderr,
        )
        sys.exit(1)


if __name__ == "__main__":
    main()

Em curl e em Node.js, o mesmo fluxo está em curl/consulta.sh e node/consulta.mjs. A primeira chamada, direto no terminal:

curl -s "https://api.cnpj.ia.br/v1/cnpjs/00000000000191?profile=basic" \
  -H "Authorization: Bearer $CNPJIA_KEY"

O formato de cada campo está em Campos da resposta, e os códigos de erro em Erros e retentativas. A tabela abaixo conta mil consultas no perfil basic; o full custa mais por consulta, e o valor de cada perfil está em Preços.

Custo em créditos

OperaçãoQuantidade por mil registrosPeso em créditosCréditos
Consulta por CNPJ, perfil basic100011000
Total por mil registros1000

Atualizado em