# Como consultar as certidões de um fornecedor por API?

> Script pronto em Python: CND Federal, CNDT e CRF do FGTS de uma lista de CNPJs, com a situação, a validade e o PDF de cada certidão.

URL: https://docs.fiscalapi.com.br/docs/guias/certidoes-fornecedor
Atualizado em 12/11/2026

Três chamadas por CNPJ: `/api/consultar-cnd-federal`, `/api/consultar-cndt` e `/api/consultar-crf-fgts`. O script desta página lê uma lista de CNPJs, grava uma planilha com a situação e a validade de cada certidão e salva os PDFs numa pasta.

* **Custo:** 1 consulta por certidão, 3 por CNPJ: de R$ 0,075 a R$ 2,01 por fornecedor, conforme o plano ([tabela](#quanto-custa)).
* **Sem PDF, mais barato:** [`/api/certidoes-todas`](#só-a-situação-numa-chamada) devolve as três situações em 1 consulta.
* **Para testar:** a API pede plano ou recarga, a partir de R$ 19,99/mês. No painel, sem programar, são 10 consultas grátis por mês.
* **Sem certificado digital:** basta o CNPJ.
* **Comece:** [crie a conta e a chave de API](https://app.fiscalapi.com.br?utm_source=docs\&utm_medium=docs\&utm_campaign=guia-certidoes).

## ## O que cada certidão prova

| Certidão                                                      | Órgão                  | Prova                                                                    | Validade |
| ------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------ | -------- |
| [CND Federal](/docs/certidoes-federais/consultar-cnd-federal) | Receita Federal e PGFN | Tributos federais, contribuições previdenciárias e Dívida Ativa da União | 180 dias |
| [CNDT](/docs/certidoes-federais/consultar-cndt)               | TST                    | Débitos trabalhistas                                                     | 180 dias |
| [CRF do FGTS](/docs/certidoes-federais/consultar-crf-fgts)    | Caixa                  | Regularidade do empregador no FGTS                                       | 30 dias  |

A CND estadual (ICMS) tem rota própria, por UF: [Consultar CND](/docs/cnd/consultar-cnd).

## ## Antes de começar

* Python 3.9 ou mais novo. O SDK oficial não tem dependências.
* A chave de API na variável de ambiente `FISCALAPI_API_KEY`.
* Um arquivo `fornecedores.csv` com a coluna `cnpj`. Use o CNPJ da matriz: a CND Federal é emitida para a matriz e vale para as filiais.

```bash
pip install fiscalapi-br
export FISCALAPI_API_KEY="fapi_sua_chave_aqui"
```

## ## O script

Salve como `certidoes.py`:

```python
"""CND Federal, CNDT e CRF do FGTS de uma lista de CNPJs, com os PDFs."""
import base64
import csv
import os
import sys
import time

from fiscalapi_br import (
    APIConnectionError,
    AuthenticationError,
    BadRequestError,
    FiscalAPI,
    InsufficientBalanceError,
    RateLimitError,
    ServerError,
)

ENTRADA = "fornecedores.csv"   # coluna "cnpj"
SAIDA = "certidoes.csv"        # uma linha por certidão; é também o checkpoint
PASTA_PDF = "pdfs"
COLUNAS = ["cnpj", "certidao", "status", "validade_iso", "numero", "pdf", "erro"]

# Segundos entre chamadas, pelo limite por minuto do plano.
PAUSA = {"lite": 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 ja_feitas() -> set[tuple[str, str]]:
    if not os.path.exists(SAIDA):
        return set()
    with open(SAIDA, encoding="utf-8", newline="") as f:
        return {(linha["cnpj"], linha["certidao"]) for linha in csv.DictReader(f)}


def gravar(linha: dict) -> None:
    novo = not os.path.exists(SAIDA)
    with open(SAIDA, "a", encoding="utf-8", newline="") as f:
        w = csv.DictWriter(f, fieldnames=COLUNAS)
        if novo:
            w.writeheader()
        w.writerow(linha)


def consultar(chamada, cnpj: str) -> dict:
    """Chama a rota e espera se a certidão ainda estiver sendo emitida."""
    for _ in range(4):
        resp = chamada(cnpj=cnpj)
        if resp["source_status"].get("error_code") != "EM_PROCESSAMENTO":
            return resp
        # O tempo sugerido vem no header Retry-After, que o SDK não expõe: 30 s cobre.
        time.sleep(30)
    return resp


def main() -> None:
    api = FiscalAPI()  # lê FISCALAPI_API_KEY; repete sozinho em 429 e 5xx
    certidoes = {
        "cnd_federal": api.consultar_cnd_federal,
        "cndt": api.consultar_cndt,
        "crf_fgts": api.consultar_crf_fgts,
    }
    os.makedirs(PASTA_PDF, exist_ok=True)
    with open(ENTRADA, encoding="utf-8-sig", newline="") as f:   # utf-8-sig: aceita CSV salvo pelo Excel
        cnpjs = list(dict.fromkeys(limpar(linha["cnpj"]) for linha in csv.DictReader(f)))
    feitas = ja_feitas()

    for cnpj in filter(None, cnpjs):
        for nome, chamada in certidoes.items():
            if (cnpj, nome) in feitas:
                continue
            inicio = time.monotonic()
            linha = {"cnpj": cnpj, "certidao": nome}
            try:
                resp = consultar(chamada, cnpj)
            except InsufficientBalanceError as e:
                print(f"Parei no {cnpj}: {e.message}. Rode de novo depois de recarregar.")
                sys.exit(2)
            except AuthenticationError as e:
                print(f"Chave recusada: {e.message}")
                sys.exit(3)
            except BadRequestError as e:
                gravar({**linha, "erro": e.code})          # pedido recusado: não repete
                continue
            except RateLimitError as e:
                time.sleep(e.retry_after or 60)             # fica para a próxima rodada
                continue
            except (ServerError, APIConnectionError):
                continue                                    # fica para a próxima rodada

            codigo = resp["source_status"].get("error_code") or ""
            r = resp.get("result")
            if codigo in ("CNPJ_INVALIDO", "CPF_INVALIDO"):
                # Vem em HTTP 200, sem exceção. Não é cobrado e não adianta repetir.
                gravar({**linha, "erro": codigo})
            elif not r or r["status"] == "erro":
                # O órgão não respondeu ou recusou o pedido. Não é cobrado e não é gravado:
                # entra de novo na próxima rodada. A mensagem diz o motivo.
                print(cnpj, nome, codigo or (r or {}).get("status_raw", ""))
            else:
                if r.get("pdf_base64"):
                    linha["pdf"] = os.path.join(PASTA_PDF, f"{cnpj}_{nome}.pdf")
                    with open(linha["pdf"], "wb") as f:
                        f.write(base64.b64decode(r["pdf_base64"]))
                gravar({**linha, "status": r["status"], "validade_iso": r.get("validade_iso", ""),
                        "numero": r.get("protocolo", "")})

            espera = PAUSA[PLANO] - (time.monotonic() - inicio)
            if espera > 0:
                time.sleep(espera)

    print("Fim. O que não entrou em certidoes.csv é consultado se você rodar de novo.")


if __name__ == "__main__":
    main()
```

Rode com `python certidoes.py`. Ajuste `PLANO` para o seu plano.

## ## Como ler o resultado

O campo `status` de cada certidão:

* `negativa`: regular, sem pendências. No CRF, empregador regular perante o FGTS.
* `positiva_com_efeitos_de_negativa`: há débitos suspensos ou garantidos. Vale como negativa.
* `positiva`: há pendências. No CRF, não existe certificado a emitir, e a validade vem vazia.
* `nao_contribuinte`: só na CND Federal, quando o CNPJ não está cadastrado na Receita.

`validade_iso` vem em `AAAA-MM-DD`, pronto para ordenar e filtrar. `numero` é o número da certidão ou do certificado, para conferir no site do órgão.

A coluna `erro` guarda só o que não adianta repetir: `CNPJ_INVALIDO`, quando o documento não tem o formato de um CNPJ. Esse caso chega em HTTP 200, sem exceção, e não é cobrado. Corrija o CNPJ em `fornecedores.csv`, apague a linha em `certidoes.csv` e rode de novo.

`status: "erro"` não entra na planilha. Ele quer dizer que o órgão não respondeu naquele momento ou recusou o pedido, e nas três certidões costuma ser passageiro. O script mostra a mensagem na tela, não cobra e consulta de novo na próxima rodada. Se a mensagem da CND Federal se repetir dizendo que o CNPJ é de filial, troque pelo CNPJ da matriz: a certidão sai para a matriz.

## ## Quando consultar de novo

* **CRF do FGTS:** vale 30 dias. Quem acompanha fornecedor consulta todo mês.
* **CND Federal e CNDT:** valem 180 dias. Filtre `validade_iso` e refaça as que vencem nas próximas semanas.
* **CND Federal:** a API devolve a certidão que ainda vale; se ela não existe ou vence em até 3 dias, emite uma nova na mesma chamada, o que pode levar até cerca de 60 segundos.
* **Renovar a CND Federal antes do vencimento:** refazer a consulta devolve a mesma certidão enquanto ela valer por mais de 3 dias. Para sair com uma nova, de 180 dias, chame `api.consultar_cnd_federal(cnpj=cnpj, emitir_nova=True)`.

Para refazer só uma parte, apague as linhas dela em `certidoes.csv` e rode de novo.

## ## Só a situação, numa chamada

Se você não precisa do PDF, `/api/certidoes-todas` consulta as três certidões em paralelo e conta como **1 consulta**:

```python
resp = api.consultar_certidoes_todas(cnpj="12345678000195", skip_estaduais=True)
for c in resp["certidoes_federais"]:
    if c["result"]:
        print(c["result"]["tipo"], c["result"]["status"], c["result"]["validade_iso"])
```

Sem `skip_estaduais`, a mesma chamada inclui a CND estadual nos 27 estados e pode levar mais de um minuto. Detalhes em [Consultar Todas as Certidões](/docs/certidoes-federais/certidoes-todas).

## ## Quanto custa

| Plano      | Uma certidão | As três, com PDF | Por minuto |
| ---------- | ------------ | ---------------- | ---------- |
| Lite       | R$ 0,67      | R$ 2,01          | 5          |
| Starter    | R$ 0,10      | R$ 0,30          | 20         |
| Pro        | R$ 0,065     | R$ 0,195         | 60         |
| Enterprise | R$ 0,025     | R$ 0,075         | 120        |

As três só com a situação, pela rota `certidoes-todas`, custam o mesmo que uma certidão. "Por minuto" é o número de consultas por minuto do plano.

Resposta com erro HTTP ou com `status: "erro"` não é cobrada. Veja [Planos e limites](/docs/referencia/plans-and-limits) e as comparações de APIs de [CND Federal](https://fiscalapi.com.br/comparar/apis-cnd-federal/), [CNDT](https://fiscalapi.com.br/comparar/apis-cndt/) e [CRF do FGTS](https://fiscalapi.com.br/comparar/apis-crf-fgts/).

## ## Perguntas frequentes

### ### Existe API para tirar a CND Federal, a CNDT e o CRF do FGTS?

Sim. A FiscalAPI tem uma rota para cada certidão e uma que consulta as três de uma vez. Todas pedem só o CNPJ e devolvem a situação, a validade e o número em JSON; as rotas individuais trazem também o PDF.

### ### Como automatizar as certidões de vários fornecedores?

Com uma lista de CNPJs e uma chamada por certidão. O script desta página grava a situação e a validade numa planilha e salva os PDFs numa pasta, e pode rodar todo mês.

### ### Precisa de certificado digital ou procuração?

Não. As três certidões são emitidas só com o CNPJ.

### ### Dá para consultar por CPF?

A CNDT e o CRF aceitam CPF. A CND Federal, por enquanto, só CNPJ.

### ### A API devolve o PDF da certidão?

Sim, em base64, no campo `pdf_base64` de cada rota individual. A rota que consulta as três de uma vez não traz os PDFs.
