---
title: "Consultar um CNPJ em curl, Python e Node.js"
description: "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."
canonical: "https://cnpj.ia.br/exemplos/consultar-cnpj"
date_modified: 2026-09-23
source: "cnpj.ia.br"
---

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](https://github.com/Atmosphere-Technologies/cnpj-ia-exemplos/tree/main/python)

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):

```python
"""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`](https://github.com/Atmosphere-Technologies/cnpj-ia-exemplos/blob/main/curl/consulta.sh) e [`node/consulta.mjs`](https://github.com/Atmosphere-Technologies/cnpj-ia-exemplos/blob/main/node/consulta.mjs). A primeira chamada, direto no terminal:

```bash
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](https://cnpj.ia.br/docs/campos), e os códigos de erro em [Erros e retentativas](https://cnpj.ia.br/docs/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](https://cnpj.ia.br/precos).

## Custo em créditos

| Operação | Quantidade por mil registros | Peso em créditos | Créditos |
| --- | --- | --- | --- |
| Consulta por CNPJ, perfil basic | 1000 | 1 | 1000 |
| Total por mil registros |  |  | 1000 |
