> ## 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.

# Limiti di frequenza API: header, errori 429 e backoff

> Limiti di frequenza dell'API Didit, header X-RateLimit, backoff Retry-After e gestione degli errori 429 per pianificare il traffico.

Didit applica più livelli di limitazione della frequenza per mantenere l'API stabile e consentire comunque picchi di traffico legittimi. I limiti si applicano **per identificatore**: la tua `x-api-key` oppure, se non viene inviata alcuna chiave API, l'IP del client. Ogni ambito mantiene un contatore indipendente con una finestra scorrevole di 60 secondi.

## Identificatore ed esenzioni

Il middleware sceglie l'identificatore per la limitazione della frequenza nell'ordine seguente:

1. Intestazione `x-api-key` → contatore per chiave.
2. Primo hop di `X-Forwarded-For` → contatore per IP.
3. `REMOTE_ADDR` → contatore per IP.

Le chiamate seguenti **bypassano** completamente la limitazione della frequenza:

* La `DIDIT_WEBAPP_API_KEY` interna (usata solo dalla console di Didit).
* Gli endpoint protetti dal permesso `IsValidSession` (il traffico delle sessioni integrate e dell'SDK).
* `GET /system/healthcheck` (servito da `HealthMiddleware` prima di questo stack).
* I webhook dei provider: Stripe, Screening AML, callback di verifica facciale e modifiche alle liste KYC.

## Limiti globali

Ogni richiesta autenticata viene inoltre associata, in base al metodo HTTP, a un ambito generico, così qualsiasi nuova route eredita un valore predefinito ragionevole:

| Ambito | Metodo/i HTTP | Limite | Finestra |
| - | - | - | - |
| `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 |

La creazione di transazioni e l'acquisizione di eventi vengono conteggiate nell'ambito `ingest-write` **invece che** in `generic-write`: un'integrazione con volumi elevati di acquisizione ottiene 600 richieste al minuto per chiave API senza consumare il budget delle altre scritture.

I limiti specifici per endpoint (sezione successiva) si applicano **in aggiunta** al limite globale. Il primo ambito che supera il proprio contatore è quello che restituisce `429`.

## Limiti specifici per endpoint

Il middleware definisce ambiti più restrittivi per le route con l'impatto maggiore:

| Ambito | Endpoint | Limite | Costante di riferimento |
| - | - | - | - |
| `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/` è servito da `SessionV3RetrieveView` e **non** rientra nell'ambito `session-decision`. È regolato solo dal limite generale `generic-get` di 600/min. La limitazione di 100/min per la decisione si applica ai percorsi di decisione v1 e v2.

> [!WARNING]
>
> Il codice definisce anche `FREE_SESSION_RATE_LIMIT = 10` e `PAID_SESSION_RATE_LIMIT = 600`. Queste costanti **non sono attualmente applicate** a `POST /v3/session/`: questo endpoint usa il singolo limite `session-v2-create` di 600/min per ogni applicazione. Non pianificare la capacità in base a una limitazione per workflow del piano gratuito finché non sarà documentata come attiva.

## Struttura della risposta 429

Quando superi un qualsiasi ambito ricevi un HTTP `429` con questo corpo e queste intestazioni:

```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."
}
```

| Intestazione | Significato |
| - | - |
| `X-RateLimit-Limit` | Numero massimo di richieste consentite nella finestra corrente per l'ambito che ha fatto scattare il limite. |
| `X-RateLimit-Remaining` | Richieste rimanenti prima che la finestra si reimposti. Azzerato a `0` quando superi il limite. |
| `X-RateLimit-Reset` | Secondi dell'epoca Unix in cui il contatore si azzera. |
| `Retry-After` | Secondi da attendere prima del tentativo successivo, arrotondati per eccesso, in modo che il tempo di attesa porti sempre alla finestra successiva. Presente **solo nelle risposte `429`**, non in ogni richiesta. |

Le intestazioni `X-RateLimit-*` vengono inviate solo nella risposta `429`: oggi le risposte riuscite non le includono. Usa il valore di `Retry-After` (oppure `X-RateLimit-Reset - now`) come ritardo prima del tentativo successivo.

## Linee guida per il client

* **Rispetta `Retry-After`** come valore minimo del backoff. A questo, aggiungi un backoff esponenziale con jitter (`5s → 10s → 20s → 40s ± random`) in modo che due client che ricevono `429` nello stesso momento non si sincronizzino.
* **Interrompi i tentativi** dopo un limite ridotto (ad esempio 5 tentativi). Restituisci l'errore al chiamante e avvisa il tuo team: 429 ripetuti indicano di solito un loop incontrollato, non un picco temporaneo.
* **Usa un unico identificatore per ogni carico di lavoro.** Condividere una `x-api-key` tra molti backend li fa confluire nello stesso contatore, e può far sì che un vicino rumoroso lasci gli altri senza risorse. Crea un'applicazione separata (e quindi un `api_key` separato) per ambiente, marchio o cliente: vedi [Registrazione programmatica](https://docs.didit.me/it/integration/programmatic-registration.md#gestione-delle-applicazioni).
* **Metti in cache le letture delle decisioni.** Gli endpoint `/decision/` non sono progettati per cicli di polling serrati; se ti servono aggiornamenti in tempo reale, usa i [Webhook](https://docs.didit.me/it/integration/webhooks.md) e chiama `GET /v3/session/<id>/decision/` solo per il recupero dei dati arretrati o per l'audit.
* **Genera i PDF offline.** Il rendering dei PDF è limitato dalla CPU (tetto di 50/min). Avvialo da una coda una volta che la sessione raggiunge uno stato finale, non a ogni visualizzazione di pagina.

## Esempio di client con gestione dei 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")
```

## Hai bisogno di più capacità?

Se 600 sessioni al minuto non bastano, ad esempio per un lancio di marketing o un recupero dei dati arretrati, scrivi a [support@didit.me](mailto:support@didit.me) indicando il tuo UUID di `application` e le frequenze sostenute e di picco previste. Le eccezioni vengono configurate per applicazione.


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