Skip to main content

apipj: API CNPJ gratuita para Python

API para consultar CNPJ em Python: o cliente oficial da API de CNPJ do apipj, com plano gratuito de 50 mil consultas por mês, sem cartão. Consulte CNPJ e receba razão social, situação cadastral, endereço, CNAEs, Simples/MEI e sócios a partir dos dados abertos da Receita Federal, com suporte ao CNPJ alfanumérico.

  • Python 3.9 a 3.13, zero dependências (usa só a biblioteca padrão) e tipado (py.typed, TypedDict para cada resposta).
  • Valida o CNPJ (inclusive alfanumérico) localmente antes de chamar a API: CNPJ inválido não gasta cota.
  • Repete sozinho em limite por minuto (429 com Retry-After), erro 5xx, falha de rede e tempo esgotado.
  • Consulta em lote com consultar_varios, em paralelo e respeitando o limite por minuto do seu plano.

Atenção: a chave de API é secreta. Não a escreva no código-fonte, não a envie para o Git e não a coloque em aplicativos distribuídos (desktop, mobile, front-end): qualquer pessoa conseguiria copiá-la e gastar a sua cota. Guarde-a numa variável de ambiente ou num cofre de segredos do servidor.

Instalação

pip install apipj

Crie uma conta grátis em apipj.com.br/criar-conta, gere a chave no painel e exporte-a:

export APIPJ_KEY=apipj_live_...

Consultar CNPJ

from apipj import Apipj, ApipjErro, cnpj_valido, normalizar_cnpj, formatar_cnpj

api = Apipj(
    chave=None,                       # padrão: lê APIPJ_KEY só na hora de consultar
    base_url="https://apipj.com.br",
    timeout=10,                       # segundos, por tentativa
    tentativas=3,                     # contando a primeira
)

# Documento completo, ou None se o CNPJ não está na base da Receita (404)
empresa = api.consultar("11.378.117/0001-20")
if empresa:
    print(empresa["razao_social"])                          # razão social
    print(empresa["situacao_cadastral"]["descricao"])       # ATIVA, BAIXADA, INAPTA...
    print(empresa["endereco"]["municipio"]["nome"], empresa["endereco"]["uf"])
    print(empresa["cnae_principal"])                        # {'codigo': ..., 'descricao': ...}

# Formato simplificado: plano, com datas DD/MM/AAAA e CNPJ, CEP e telefone já formatados
simples = api.consultar("11378117000120", formato="simplificado")
if simples:
    print(simples["cnpj"], simples["nome"], simples["abertura"])

# Status do serviço e mês do lote da Receita carregado (sem chave e sem cota)
print(api.status()["dataset_month"])

# Planos, preços e limites (sem chave e sem cota)
for plano in api.planos()["plans"]:
    print(plano["name"], plano["rpm"], plano["monthly_quota"], plano["price"])

O retorno é um dict comum, tipado com TypedDict (EmpresaCompleta ou EmpresaSimplificada, conforme o formato): o editor completa os campos e o mypy/pyright conferem o acesso. No formato completo, campo ausente na base da Receita vem como None; nenhuma chave some.

Validar CNPJ (inclusive alfanumérico)

Offline, sem chamar a API:

from apipj import cnpj_valido, normalizar_cnpj, formatar_cnpj

print(cnpj_valido("12.ABC.345/01DE-35"))      # True  (alfanumérico)
print(cnpj_valido("12ABC34501DE36"))          # False (dígito verificador errado)
print(cnpj_valido("00.000.000/0000-00"))      # False (zerado)
print(normalizar_cnpj("12.abc.345/01de-35"))  # 12ABC34501DE35
print(formatar_cnpj("11378117000120"))        # 11.378.117/0001-20

cnpj_valido confere formato e dígitos verificadores do CNPJ numérico e do alfanumérico (IN RFB 2.229/2024: cada caractere vale o código ASCII menos 48, módulo 11); não diz se o CNPJ existe. Também são exportados validar_local (mesmo formato de resposta de api.validar) e calcular_dv.

Pela API (sem chave e sem consumo de cota):

print(api.validar("12.ABC.345/01DE-35"))
# {'cnpj': '12ABC34501DE35', 'valido': True, 'formatado': '12.ABC.345/01DE-35', 'alfanumerico': True, 'erro': None}

Consultar CNPJ em lote

lista = ["11.378.117/0001-20", "00.000.000/0001-91", "11378117000120", "123"]

for r in api.consultar_varios(lista, simultaneas=4):
    # r = {"cnpj": ..., "documento": ... ou None, "erro": ApipjErro ou None}, na ordem de conclusão
    if r["erro"]:
        print(r["cnpj"], r["erro"].code, r["erro"].message)
    elif r["documento"] is None:
        print(r["cnpj"], "não encontrado")
    else:
        print(r["cnpj"], r["documento"]["razao_social"])
  • Lê o limite por minuto do seu plano dos cabeçalhos X-RateLimit-Limit/Remaining/Reset e nunca passa dele (a primeira consulta sai sozinha para descobrir o limite). Use rpm= para ficar abaixo do plano, por exemplo para dividir a chave com outro processo.
  • CNPJs repetidos (mesmo com máscaras diferentes) são consultados uma vez só.
  • CNPJs inválidos não chamam a API: saem com documento None e erro.code == "invalid_cnpj".
  • Erro de um CNPJ (por exemplo 5xx depois das tentativas) sai no próprio item e o lote continua.
  • 401 (chave inválida) e cota mensal esgotada (quota_exceeded) interrompem o lote lançando ApipjErro, depois de entregar os resultados já prontos.
  • Aceita lista, gerador ou qualquer iterável (por exemplo, as linhas de um arquivo). Um break no laço para de chamar a API.
  • Opções: simultaneas (padrão 4, threads), formato, rpm.

Tratamento de erros

Todos os erros da API viram ApipjErro, com status (HTTP, ou 0 para rede/tempo esgotado), code (estável, em snake_case) e message (em português).

def buscar(cnpj: str) -> str:
    try:
        empresa = api.consultar(cnpj)
    except ApipjErro as e:
        if e.code == "invalid_cnpj":      # 400: formato ou dígito inválido (verificado antes de chamar a API)
            return f"CNPJ inválido: {e.message}"
        if e.code == "unauthorized":      # 401: chave ausente, inválida ou revogada
            return "Confira a variável APIPJ_KEY"
        if e.code == "quota_exceeded":    # 429: cota mensal esgotada; e.upgrade_url e e.reset (epoch)
            return f"Cota do mês esgotada; planos em {e.upgrade_url}"
        if e.code == "rate_limited":      # 429: limite por minuto mesmo depois de esperar Retry-After
            return f"Tente de novo em {e.retry_after} s"
        raise                             # 5xx (dataset_unavailable, server_error), network_error, timeout
    if empresa is None:
        return "CNPJ não encontrado na base da Receita"
    return empresa["razao_social"]


print(buscar("11.378.117/0001-21"))   # CNPJ inválido: Dígitos verificadores inválidos
Situação O que o cliente faz
CNPJ inválido lança ApipjErro(400, "invalid_cnpj") sem chamar a API
404 (CNPJ válido, fora da base) devolve None
400, 401 lança na hora
429 quota_exceeded lança na hora, com upgrade_url e reset
429 rate_limited espera Retry-After e repete, até tentativas; depois lança com retry_after
5xx, falha de rede, tempo esgotado repete com espera de 1 s, 2 s...; depois lança

Depois de cada consulta, api.limites traz o que a API informou nos cabeçalhos X-RateLimit-* e X-Quota-*:

print(api.limites)
# {'por_minuto': {'limite': 10, 'restante': 9, 'reset': 60}, 'mensal': {'limite': 50000, 'restante': 49990, 'reset': 1793502000}}

Limites e plano gratuito

Cada consulta respondida (inclusive 404) conta 1 na cota mensal; também vale um limite de consultas por minuto por chave. validar, status e planos não consomem cota.

Plano Consultas por minuto Consultas por mês Preço
Gratuito 10 50.000 R$ 0
Dev 30 200.000 R$ 12,90/mês
Pro 200 600.000 R$ 59,90/mês

Valores atuais em apipj.com.br/precos (ou, no código, api.planos()). Para assinar o Pro direto: apipj.com.br/painel?assinar=pro.

Licença

MIT. Os dados vêm dos dados abertos do CNPJ publicados pela Receita Federal.

Metadata

Release files for apipj 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for apipj 0.1.0
File Size Uploaded
apipj-0.1.0.tar.gz 25.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for apipj 0.1.0
File Interpreter ABI Platform
apipj-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 46.5 kB

Release files / apipj-0.1.0.tar.gz

Download URL apipj-0.1.0.tar.gz
Size 25.8 kB
Tags Source
SHA-256 checksum
How to use checksums
963c90328e7ca7ac942f95538ed390dd82a0094e5b91fca4c34af2d7d4db7599
BLAKE2b-256 checksum
How to use checksums
7b4e7ea25ae22bf31ddf8b9d2502c3a43186a63778ab317102d95e5e324c2baa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / apipj-0.1.0-py3-none-any.whl

Download URL apipj-0.1.0-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e07b7b2cc878b8537ecb208974811165bbbac6a92eeb990198938209c5f405d3
BLAKE2b-256 checksum
How to use checksums
500e0d6bdb134ba423c1e7f2014a6156f92964c3dd734b3520cb19343ff4bace
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page