finstatdocs
API Entrar

Limites e novas tentativas

Limites

LimiteValorAo passar
Tamanho do PDF25 MiB413 pdf_too_large
Páginas100, cada uma até A2202, depois error com processing_failed
Idempotency-Key1 a 128 caracteres422 invalid_request
Envios ao mesmo tempo, por chave2429 too_many_requests
Envios ao mesmo tempo, no total3503 capacity_busy

Consultas GET têm fila própria e não esperam envios.

Retry-After

429 e 503 vêm com o cabeçalho Retry-After (segundos) e são respondidos antes de ler o corpo: o PDF não foi recebido. Espere ao menos o Retry-After e reenvie a requisição inteira com a mesma Idempotency-Key.

Quando repetir

SituaçãoRepetir?
429, 503Sim, depois do Retry-After, com a mesma Idempotency-Key.
Timeout, falha de rede, 500, 502, 504Sim, com a mesma Idempotency-Key e backoff.
GET em 429 ou 503Sim, com o mesmo backoff.
Demais 4xxNão; corrija a requisição antes.

Use backoff exponencial com jitter (por exemplo 2 s, 4 s, 8 s, até 60 s) e um limite de tentativas. Como o envio é idempotente, repetir nunca cria documento duplicado nem nova cobrança.

curl
# curl --retry já respeita Retry-After e reenvia o corpo.
curl --retry 5 --retry-max-time 120 \
  "https://finstat.com.br/v1/documents?cnpj=00000000000191&period_end=2025-12-31" \
  -H "Authorization: Bearer $FINSTAT_API_KEY" \
  -H "Idempotency-Key: lote-2025-12-0042" \
  -H "Content-Type: application/pdf" \
  --data-binary @balanco.pdf
Node
// O SDK repete sozinho em 429, 503, 5xx e falha de rede, com a mesma chave.
const finstat = new Finstat(process.env.FINSTAT_API_KEY!, { maxNetworkRetries: 4 });
Python
import random
import time

import httpx

RETRY = {429, 500, 502, 503, 504}


def send(request: httpx.Request, attempts: int = 5) -> httpx.Response:
    with httpx.Client(timeout=60) as client:
        for attempt in range(attempts):
            try:
                response = client.send(request)
            except httpx.TransportError:
                response = None
            if response is not None and response.status_code not in RETRY:
                return response
            retry_after = response.headers.get("Retry-After") if response else None
            delay = float(retry_after) if retry_after else min(60, 2 ** (attempt + 1))
            time.sleep(delay + random.uniform(0, 1))
    raise RuntimeError("finstat: tentativas esgotadas")

Consultas

Prefira o webhook a consultar a situação em laço. Sem webhook, consulte a cada minuto ou mais; com conferência humana, a liberação pode levar horas.