Como consultar a inscrição estadual de milhares de CNPJs em Python?
Script pronto com o SDK oficial: segue o limite do seu plano, para quando acabam as consultas e retoma de onde parou.
Atualizado em
Use o SDK oficial fiscalapi-br e o script desta página: ele consulta um CNPJ por vez no ritmo do seu plano, grava cada resposta na hora e, se parar (queda, saldo, Ctrl+C), continua de onde parou.
- Custo: 1 consulta por CNPJ, de R$ 0,025 a R$ 0,67 conforme o plano (tabela).
- Grátis para testar a API: 10 consultas por mês de IE em um estado e de CNPJ; a consulta nos 27 estados usada neste guia é paga (condições).
- Ritmo: 5 a 120 CNPJs por minuto, conforme o plano.
- Comece: crie a conta e a chave de API.
Antes de começar
- Python 3.9 ou mais novo. O SDK não tem dependências.
- A chave de API na variável de ambiente
FISCALAPI_API_KEY. - Um arquivo
cnpjs.csvcom a colunacnpj(pontuação é aceita).
pip install fiscalapi-br
export FISCALAPI_API_KEY="fapi_sua_chave_aqui"Primeira chamada isolada: Quickstart. Métodos do SDK: fiscalapi-python.
O script
Salve como consultar_lote.py:
"""Consulta a IE de uma lista de CNPJs nos 27 estados, com retomada."""
import csv
import json
import re
import sys
import time
from datetime import datetime, timezone
from fiscalapi_br import (
APIConnectionError,
AuthenticationError,
BadRequestError,
FiscalAPI,
InsufficientBalanceError,
RateLimitError,
ServerError,
)
ENTRADA = "cnpjs.csv" # coluna "cnpj"
SAIDA = "resultado.jsonl" # uma linha por CNPJ concluído (é também o checkpoint)
FALHAS = "falhas.jsonl" # 5xx e falhas de rede: entram de novo na próxima rodada
# Segundos entre chamadas, pelo limite por minuto do plano.
PAUSA = {"lite": 12.0, "sem_plano": 12.0, "starter": 3.0, "pro": 1.0, "enterprise": 0.5}
PLANO = "starter"
def limpar(valor: str) -> str:
return "".join(c for c in valor if c.isalnum()).upper()
def cnpj_valido(cnpj: str) -> bool:
"""Dígitos verificadores, também do CNPJ alfanumérico. CNPJ com DV errado não
volta erro da API: é consultado e cobrado. Melhor barrar antes."""
if not re.fullmatch(r"[0-9A-Z]{12}[0-9]{2}", cnpj) or len(set(cnpj)) == 1:
return False
v = [ord(c) - 48 for c in cnpj]
for n in (12, 13):
pesos = list(range(n - 7, 1, -1)) + list(range(9, 1, -1))
resto = sum(a * b for a, b in zip(v, pesos)) % 11
if v[n] != (0 if resto < 2 else 11 - resto):
return False
return True
def ja_concluidos() -> set[str]:
try:
with open(SAIDA, encoding="utf-8") as f:
return {json.loads(linha)["cnpj"] for linha in f if linha.strip()}
except FileNotFoundError:
return set()
def gravar(arquivo: str, registro: dict) -> None:
registro["consultado_em"] = datetime.now(timezone.utc).isoformat()
with open(arquivo, "a", encoding="utf-8") as f:
f.write(json.dumps(registro, ensure_ascii=False) + "\n")
def main() -> None:
api = FiscalAPI() # lê FISCALAPI_API_KEY; já repete sozinho em 429 e 5xx
pausa = PAUSA[PLANO]
with open(ENTRADA, encoding="utf-8", newline="") as f:
cnpjs = [limpar(linha["cnpj"]) for linha in csv.DictReader(f)]
feitos = ja_concluidos()
pendentes = list(dict.fromkeys(c for c in cnpjs if c and c not in feitos))
print(f"{len(feitos)} já concluídos, {len(pendentes)} pendentes")
ultima = 0.0
for i, cnpj in enumerate(pendentes, 1):
if not cnpj_valido(cnpj):
gravar(SAIDA, {"cnpj": cnpj, "erro": "CNPJ_INVALIDO"}) # não chama a API
continue
espera = pausa - (time.monotonic() - ultima)
if espera > 0:
time.sleep(espera)
ultima = time.monotonic()
try:
resp = api.consultar_ie_todos(cnpj=cnpj)
except InsufficientBalanceError as e:
# 402: acabaram as consultas do mês e não há saldo de recarga. Repetir não adianta.
print(f"Parei no {cnpj}: {e.message}. Rode de novo depois de recarregar.")
sys.exit(2)
except AuthenticationError as e:
# 403: chave ausente, inválida ou revogada.
print(f"Chave recusada: {e.message}")
sys.exit(3)
except RateLimitError as e:
# 429 mesmo depois das tentativas do SDK: espera e deixa para a próxima rodada.
print(f"Limite por minuto atingido; esperando {e.retry_after or 60} s")
time.sleep(e.retry_after or 60)
continue
except BadRequestError as e:
# 400: documento ausente ou sem dígitos. Grava como concluído.
gravar(SAIDA, {"cnpj": cnpj, "erro": e.code, "mensagem": e.message})
continue
except (ServerError, APIConnectionError) as e:
gravar(FALHAS, {"cnpj": cnpj, "erro": e.status_code, "mensagem": e.message})
continue
inscricoes = [
{"uf": estado["uf"], "ie": ie["inscricao_estadual"], "situacao": ie["situacao_ie"]}
for estado in resp["results"]
for ie in estado["results"]
]
gravar(SAIDA, {"cnpj": cnpj, "complete": resp.get("complete", True), "inscricoes": inscricoes})
if i % 100 == 0:
print(f"{i}/{len(pendentes)}")
print("Fim. Os que caíram em falhas.jsonl entram de novo se você rodar outra vez.")
if __name__ == "__main__":
main()Rode com python consultar_lote.py. Ajuste PLANO para o seu plano.
Como ele lida com cada situação
| Situação | O que o script faz |
|---|---|
| Limite por minuto | Espera PAUSA[PLANO] segundos entre uma chamada e a seguinte: 12 no Lite e sem plano, 3 no Starter, 1 no Pro, 0,5 no Enterprise. O limite é da conta, somando todas as chaves: não rode dois scripts ao mesmo tempo. |
429 | O SDK tenta de novo até 3 vezes, respeitando o Retry-After (até 60 s). Se ainda vier RateLimitError, o script espera e deixa o CNPJ para a próxima rodada. |
| CNPJ com dígito verificador errado | cnpj_valido barra antes e grava CNPJ_INVALIDO. Na consulta nos 27 estados, a API não confere o dígito: CNPJ errado seria cobrado. |
402 | InsufficientBalanceError: acabaram as consultas do mês e não há recarga. O script para na hora. Recarregue ou mude de plano e rode de novo. |
400 | BadRequestError: documento ausente ou sem dígitos. Vai para o resultado com o erro e não é repetido. |
5xx ou rede | O SDK tenta de novo em 500, 502, 503 e 504. Se persistir, o CNPJ vai para falhas.jsonl e entra na próxima rodada. |
403 | AuthenticationError: chave ausente, inválida ou revogada. O script para. |
| Interrupção | resultado.jsonl é o checkpoint: na próxima rodada, os CNPJs concluídos são pulados. |
| CNPJ repetido na lista | Consultado uma vez só. |
complete: false quer dizer que algum estado não respondeu, e aí uma lista vazia não prova que não há IE. A consulta foi cobrada (pelo menos um estado respondeu), por isso o script a grava como concluída. Para refazer só esses CNPJs, filtre "complete": false no resultado.jsonl e rode de novo; cada um é uma nova consulta.
Quanto tempo leva
O teto é o do plano: 5 CNPJs por minuto no Lite, 20 no Starter, 60 no Pro e 120 no Enterprise. Ou seja, 1.000 CNPJs levam pelo menos 50 minutos no Starter e 17 no Pro. Como o script faz uma chamada de cada vez, o tempo de resposta também pesa e, no Pro e no Enterprise, o ritmo costuma ficar abaixo do teto. Para chegar perto, rode algumas chamadas em paralelo (por exemplo, com concurrent.futures.ThreadPoolExecutor) sem passar do limite.
Sem programar, o painel aceita planilhas de até 20.000 linhas: veja consulta de IE em massa.
Variações
- Só um estado:
api.consultar_ie(uf="MT", cnpj=cnpj)devolve as inscrições direto emresp["results"]. - Produtor rural por CPF:
api.consultar_ie_todos(cpf="12345678909"). - Dados da Receita Federal:
api.consultar_cnpj(cnpj)devolveresp["result"]["razao_social"], CNAE, QSA e endereço. É mais uma consulta por CNPJ.
Quanto custa
| Lite | Starter | Pro | Enterprise | |
|---|---|---|---|---|
| Consulta de IE (1 UF ou 27 UFs) | R$ 0,67 | R$ 0,10 | R$ 0,065 | R$ 0,025 |
| Recarga, por consulta | sem recarga | R$ 0,12 | R$ 0,07 | R$ 0,02 |
| Consultas por minuto | 5 | 20 | 60 | 120 |
Cada CNPJ é uma consulta. No Enterprise, 10.000 CNPJs cabem na franquia de R$ 250 do mês. Resposta com erro HTTP (400, 402, 429, 500) não é cobrada. Veja Planos e limites.
Grátis para testar: conta que nunca assinou plano, sem recarga e com e-mail confirmado, tem 10 consultas por mês de IE em um estado e de CNPJ, também pela API. Teste com api.consultar_ie(uf="MT", cnpj=...): a consulta nos 27 estados usa plano ou recarga. Criar conta.
Perguntas frequentes
Existe biblioteca Python para a FiscalAPI?
Sim, o SDK oficial fiscalapi-br no PyPI (pip install fiscalapi-br, importado como fiscalapi_br). Ele não tem dependências, roda em Python 3.9 ou mais novo e tenta de novo sozinho em 429 e em falhas temporárias.
Como consultar inscrição estadual de vários CNPJs em Python?
Chame FiscalAPI().consultar_ie_todos(cnpj=...) para cada CNPJ, com uma pausa entre as chamadas conforme o plano, e grave cada resposta assim que ela chega. O script desta página faz isso e retoma de onde parou.
O que fazer quando a API devolve 429?
Esperar os segundos do header Retry-After e tentar de novo. O SDK já faz isso até 3 vezes; depois, levanta RateLimitError com retry_after.
O que significa o erro 402?
Que acabaram as consultas do mês (as grátis ou a franquia do plano) e não há recarga. O SDK levanta InsufficientBalanceError. Repetir não resolve: recarregue ou mude de plano.
Quantos CNPJs por minuto dá para consultar?
5 no Lite e na conta sem plano, 20 no Starter, 60 no Pro e 120 no Enterprise, somando todas as chaves da conta.
Esta pagina foi util?
Como consultar inscrição estadual no Power Automate?
Num fluxo de nuvem do Power Automate, a ação HTTP chama a API da FiscalAPI com o header X-API-Key e devolve a inscrição estadual de cada CNPJ. A ação HTTP é de conector premium.
Como consultar a inscrição estadual de milhares de CNPJs em Node.js?
Script pronto com o SDK oficial: segue o limite do seu plano, para quando acabam as consultas e retoma de onde parou.