> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Limite de requisições da API: cabeçalhos e backoff 429

> Limites de requisições da API Didit, cabeçalhos X-RateLimit, backoff com Retry-After, escopos por endpoint e tratamento do erro 429.

A Didit aplica várias camadas de limite de requisições para manter a API estável e, ao mesmo tempo, permitir picos de tráfego saudáveis. Os limites são aplicados **por identificador**: sua `x-api-key` ou, se nenhuma chave de API for enviada, o endereço IP do seu cliente. Cada escopo mantém um contador independente com uma janela deslizante de 60 segundos.

## Identificador e isenções

O middleware escolhe o identificador do limite de requisições nesta ordem:

1. Cabeçalho `x-api-key` → contador por chave.
2. Primeiro salto de `X-Forwarded-For` → contador por IP.
3. `REMOTE_ADDR` → contador por IP.

As chamadas a seguir **ignoram** totalmente o limite de requisições:

* A `DIDIT_WEBAPP_API_KEY` interna (usada apenas pelo console da Didit).
* Endpoints protegidos pela permissão `IsValidSession` (o tráfego de sessões incorporadas e de SDK).
* `GET /system/healthcheck` (atendido pelo `HealthMiddleware` antes desta pilha).
* Webhooks de provedores: Stripe, análise AML, callbacks de verificação facial e alterações de listas de KYC.

## Limites globais

Toda requisição autenticada também é agrupada por método HTTP em um escopo genérico, para que qualquer rota nova herde um padrão razoável:

| Escopo | Método(s) HTTP | Limite | Janela |
| - | - | - | - |
| `generic-get` | `GET` | 600 / min | 60 s |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / min | 60 s |

Os limites específicos específicos de cada endpoint (próxima seção) se aplicam **além** do limite global. O primeiro escopo que exceder seu contador é o que retorna `429`.

## Limites específicos por endpoint

O middleware define escopos mais rígidos para as rotas de maior impacto:

| Escopo | Endpoint(s) | Limite | Constante de origem |
| - | - | - | - |
| `session-v2-create` | `POST /v2/session/`, `POST /v3/session/` | 600 / min | `SESSION_CREATE_RATE_LIMIT` |
| `session-decision` | `GET /v1/session/<id>/decision/`, `GET /v2/session/<id>/decision/` | 100 / min | `SESSION_DECISION_RATE_LIMIT` |
| `session-generate-pdf` | `GET /v1/session/<id>/generate-pdf/`, `GET /v3/session/<id>/generate-pdf/` | 50 / min | `SESSION_PDF_RATE_LIMIT` |
| `session-add-images` | `POST`/`PATCH /session/<id>/add-images/` | 10 / min | `SESSION_ADD_IMAGES_RATE_LIMIT` |
| `session-update-kyc` | `POST`/`PATCH /session/<id>/update-data/` | 10 / min | `SESSION_UPDATE_KYC_RATE_LIMIT` |
| `session-update-poa` | `POST`/`PATCH /session/<id>/update-poa-data/` | 10 / min | `SESSION_UPDATE_POA_RATE_LIMIT` |

> [!NOTE]
>
> `GET /v3/session/<id>/decision/` é atendido pela `SessionV3RetrieveView` e **não** faz parte do escopo `session-decision`. Ele está sujeito apenas ao teto de 600/min do `generic-get`. O limite de 100/min para decisões se aplica aos endpoints de decisão v1 e v2.

> [!WARNING]
>
> O código também define `FREE_SESSION_RATE_LIMIT = 10` e `PAID_SESSION_RATE_LIMIT = 600`. Essas constantes **não são aplicadas atualmente** ao `POST /v3/session/`: esse endpoint usa o limite único de 600/min do `session-v2-create` para todas as aplicações. Não planeje sua capacidade com base em um limite do plano gratuito por fluxo de verificação (workflow) até que ele esteja documentado como ativo.

## Formato da resposta 429

Quando você excede o limite de qualquer escopo, recebe um HTTP `429` com este corpo e estes cabeçalhos:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1762534870
Retry-After: 37

{
  "detail": "Session creation rate limit exceeded. You can make up to 600 requests per minute."
}
```

| Cabeçalho | Significado |
| - | - |
| `X-RateLimit-Limit` | Máximo de requisições permitidas na janela atual para o escopo que foi excedido. |
| `X-RateLimit-Remaining` | Requisições restantes antes de a janela reiniciar. Fixado em `0` assim que você ultrapassa o limite. |
| `X-RateLimit-Reset` | Segundos desde a época Unix em que o contador é redefinido para zero. |
| `Retry-After` | Segundos de espera antes da próxima tentativa. Presente **apenas em respostas `429`**, não em todas as requisições. |

Os cabeçalhos `X-RateLimit-*` são emitidos apenas na resposta `429`: hoje, as respostas bem-sucedidas não os incluem. Use o valor de `Retry-After` (ou `X-RateLimit-Reset - now`) como o intervalo de espera antes da próxima tentativa.

## Orientações para o cliente

* **Respeite o `Retry-After`** como o valor mínimo para o backoff. Sobre ele, aplique um backoff exponencial com jitter (`5s → 10s → 20s → 40s ± random`) para que dois clientes que recebam `429` ao mesmo tempo não se sincronizem.
* **Pare de tentar novamente** após um limite baixo (por exemplo, 5 tentativas). Repasse o erro a seu chamador e alerte sua equipe: 429s persistentes geralmente indicam um loop descontrolado, não um pico passageiro.
* **Use um identificador por carga de trabalho.** Compartilhar uma `x-api-key` entre vários backends coloca todos no mesmo contador, o que pode fazer com que uma aplicação que consome muitos recursos esgote a capacidade dos demais. Crie uma aplicação separada (e, portanto, uma `api_key` separada) por ambiente, marca ou cliente. Consulte [Registro programático](https://docs.didit.me/pt-br/integration/programmatic-registration.md#gerenciamento-de-aplicações).
* **Armazene em cache as leituras de decisão.** Os endpoints `/decision/` não foram projetados para loops de polling intensos; se você precisa de atualizações em tempo real, use [Webhooks](https://docs.didit.me/pt-br/integration/webhooks.md) e chame `GET /v3/session/<id>/decision/` apenas para preenchimento retroativo ou auditoria.
* **Gere PDFs de forma assíncrona.** A renderização de PDF consome muita CPU (teto de 50/min). Dispare-a a partir de uma fila depois que a sessão atingir um status final, e não a cada visualização de página.

## Exemplo de cliente que trata 429

```javascript theme={null}
async function postSession(body) {
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch("https://verification.didit.me/v3/session/", {
      method: "POST",
      headers: {
        "x-api-key": process.env.DIDIT_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    if (res.status !== 429) return res;

    const retryAfter = Number(res.headers.get("Retry-After") ?? "1");
    const jitter = Math.random() * 1000;
    await new Promise((r) => setTimeout(r, retryAfter * 1000 + jitter));
  }
  throw new Error("Didit: too many 429s, giving up");
}
```

```python theme={null}
import os
import random
import time

import httpx

def post_session(body: dict) -> httpx.Response:
    with httpx.Client(timeout=15) as client:
        for _ in range(5):
            resp = client.post(
                "https://verification.didit.me/v3/session/",
                headers={
                    "x-api-key": os.environ["DIDIT_API_KEY"],
                    "Content-Type": "application/json",
                },
                json=body,
            )
            if resp.status_code != 429:
                return resp
            wait_s = float(resp.headers.get("Retry-After", "1")) + random.random()
            time.sleep(wait_s)
    raise RuntimeError("Didit: too many 429s, giving up")
```

## Precisa de mais capacidade?

Se 600 sessões por minuto não forem suficientes, por exemplo em um lançamento de marketing ou em um backfill, envie um e-mail para [support@didit.me](mailto:support@didit.me) com o UUID da sua `application` e as taxas esperadas, tanto a sustentada quanto a de pico. Os ajustes de limite são configurados por aplicação.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.