> ## 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 pedidos da API: Limites, Cabeçalhos e Erro 429

> Limites de pedidos da API Didit, cabeçalhos X-RateLimit, Retry-After, escopos por endpoint e erro 429. Planeie o tráfego em produção.

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

## Identificador e exceções

O middleware escolhe um identificador de limitação de pedidos por esta 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 seguintes **ignoram** por completo a limitação de pedidos:

* A `DIDIT_WEBAPP_API_KEY` interna (usada apenas pela consola do Didit).
* Endpoints protegidos pela permissão `IsValidSession` (tráfego de sessões incorporadas e do SDK).
* `GET /system/healthcheck` (servido pelo `HealthMiddleware` antes desta pilha).
* Webhooks de fornecedores: Stripe, triagem AML, retornos de chamada de verificação facial e alterações a listas KYC.

## Limites globais

Cada pedido autenticado é também agrupado por método HTTP num âmbito genérico, para que qualquer nova rota herde um valor por defeito razoável:

| Âmbito | Método(s) HTTP | Limite | Janela |
| - | - | - | - |
| `generic-get` | `GET` | 600 / min | 60 s |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / min | 60 s |
| `ingest-write` | `POST /v3/transactions/`, `POST /v3/events/`, `POST /v3/events/batch/` | 600 / min | 60 s |

As criações de transações e a ingestão de eventos contam para `ingest-write` **em vez de** `generic-write`: uma integração de ingestão de grande volume obtém 600 pedidos por minuto por chave de API sem consumir o orçamento das suas outras escritas.

Os limites específicos de endpoints (secção seguinte) aplicam-se **para além** do limite global. O primeiro âmbito a exceder o respetivo contador é o que devolve `429`.

## Limites específicos de endpoints

O middleware define âmbitos mais restritivos para as rotas de maior impacto:

| Âmbito | 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/` é servido por `SessionV3RetrieveView` e **não** está no âmbito `session-decision`. Está sujeito apenas ao teto de 600/min de `generic-get`. O limite de 100/min aplica-se apenas aos caminhos de decisão v1 e v2.

> [!WARNING]
>
> O código também define `FREE_SESSION_RATE_LIMIT = 10` e `PAID_SESSION_RATE_LIMIT = 600`. Estas constantes **não estão atualmente aplicadas** a `POST /v3/session/`: esse endpoint usa o único limite `session-v2-create`, de 600/min, para todas as aplicações. Não planeie a capacidade com base num limite por fluxo para o plano gratuito enquanto não estiver documentado como ativo.

## Formato da resposta 429

Ao exceder qualquer âmbito, recebe um `429` HTTP 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` | Número máximo de pedidos permitidos na janela atual para o âmbito que foi atingido. |
| `X-RateLimit-Remaining` | Pedidos restantes até que a janela seja reposta. O valor fica limitado a `0` assim que o limite for ultrapassado. |
| `X-RateLimit-Reset` | Segundos desde a época Unix em que o contador volta a zero. |
| `Retry-After` | Segundos a aguardar antes da próxima tentativa, arredondados por excesso para que esperar sempre leve à janela seguinte. Presente **apenas nas respostas `429`**, e não em todos os pedidos. |

Os cabeçalhos `X-RateLimit-*` só são enviados na resposta `429`; as respostas bem-sucedidas não os incluem atualmente. Use o valor de `Retry-After` (ou `X-RateLimit-Reset - now`) como atraso antes da próxima tentativa.

## Orientações para clientes

* **Respeite `Retry-After`** como o mínimo do seu tempo de espera. Sobre esse mínimo, aplique um backoff exponencial com variação aleatória (jitter) (`5s → 10s → 20s → 40s ± random`), para que dois clientes que recebam `429` ao mesmo tempo não se sincronizem.
* **Deixe de tentar novamente** após um limite reduzido (por exemplo, 5 tentativas). Devolva o erro ao seu chamador e alerte a sua equipa: respostas 429 persistentes costumam indicar um ciclo descontrolado, e não um pico pontual.
* **Use um identificador por carga de trabalho.** Partilhar um `x-api-key` entre vários backends junta-os no mesmo contador, o que pode fazer com que um vizinho ruidoso deixe os restantes sem recursos. Crie uma aplicação separada (e, por conseguinte, um `api_key` separado) por ambiente, marca ou cliente; veja [Registo programático](https://docs.didit.me/pt/integration/programmatic-registration.md#gerir-aplicações).
* **Guarde em cache as leituras de decisão.** Os endpoints `/decision/` não foram concebidos para ciclos de polling apertados. Se precisar de atualizações em tempo real, use [Webhooks](https://docs.didit.me/pt/integration/webhooks.md) e chame `GET /v3/session/<id>/decision/` apenas para preenchimento retroativo ou auditoria.
* **Gere os PDF offline.** A geração de PDF está limitada pela CPU (limite de 50/min). Acione-a a partir de uma fila depois de a sessão atingir um estado final, e não em cada visualização de página.

## Cliente de exemplo com tratamento de 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 para um lançamento de marketing ou um preenchimento retroativo, envie um e-mail para [support@didit.me](mailto:support@didit.me) com o UUID da sua `application` e as taxas esperadas, sustentadas e de pico. As substituições são configuradas por aplicação.


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