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

# Лимиты запросов API: лимиты, заголовки и повтор при 429

> Лимиты запросов Didit API, заголовки X-RateLimit, задержка по Retry-After, области по endpoint и обработка 429. Планируйте продакшн-трафик уверенно.

Didit применяет несколько уровней ограничения частоты запросов (rate limiting), чтобы сохранять стабильность API и при этом допускать оправданные всплески трафика. Лимиты применяются **для каждого идентификатора**: это ваш `x-api-key` или, если API-ключ не передан, IP-адрес клиента. Каждая область ведёт независимый счётчик со скользящим окном 60 секунд.

## Идентификатор и исключения

Промежуточное ПО выбирает идентификатор для ограничения частоты в следующем порядке:

1. Заголовок `x-api-key` → счётчик, привязанный к ключу.
2. Первый хоп `X-Forwarded-For` → счётчик, привязанный к IP-адресу.
3. `REMOTE_ADDR` → счётчик, привязанный к IP-адресу.

Следующие вызовы **полностью обходят** ограничение частоты:

* Внутренний `DIDIT_WEBAPP_API_KEY` (используется только консолью Didit).
* Эндпоинты, защищённые разрешением `IsValidSession` (трафик встроенных сессий и сессий SDK).
* `GET /system/healthcheck` (обрабатывается `HealthMiddleware` до этого стека).
* Webhook'и провайдеров: Stripe, AML-скрининг, callback-вызовы верификации лиц, изменение списков KYC.

## Глобальные лимиты

Каждый аутентифицированный запрос также помещается в общую область в зависимости от HTTP-метода, поэтому любой новый маршрут получает разумное значение по умолчанию:

| Область | HTTP-метод(ы) | Лимит | Окно |
| - | - | - | - |
| `generic-get` | `GET` | 600 / мин | 60 с |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / мин | 60 с |
| `ingest-write` | `POST /v3/transactions/`, `POST /v3/events/`, `POST /v3/events/batch/` | 600 / мин | 60 с |

Создание транзакций и приём событий учитываются в области `ingest-write`, **а не** в `generic-write`: интеграция с высоким объёмом приёма данных получает 600 запросов в минуту на каждый API-ключ и не расходует бюджет своих остальных операций записи.

Лимиты для отдельных endpoint'ов (следующий раздел) применяются **в дополнение** к глобальному лимиту. Первая область, в которой превышен лимит, вызывает ответ `429`.

## Лимиты для отдельных endpoint'ов

Middleware определяет более строгие области для самых критичных маршрутов:

| Область | Endpoint(ы) | Лимит | Константа в исходном коде |
| - | - | - | - |
| `session-v2-create` | `POST /v2/session/`, `POST /v3/session/` | 600 / мин | `SESSION_CREATE_RATE_LIMIT` |
| `session-decision` | `GET /v1/session/<id>/decision/`, `GET /v2/session/<id>/decision/` | 100 / мин | `SESSION_DECISION_RATE_LIMIT` |
| `session-generate-pdf` | `GET /v1/session/<id>/generate-pdf/`, `GET /v3/session/<id>/generate-pdf/` | 50 / мин | `SESSION_PDF_RATE_LIMIT` |
| `session-add-images` | `POST`/`PATCH /session/<id>/add-images/` | 10 / мин | `SESSION_ADD_IMAGES_RATE_LIMIT` |
| `session-update-kyc` | `POST`/`PATCH /session/<id>/update-data/` | 10 / мин | `SESSION_UPDATE_KYC_RATE_LIMIT` |
| `session-update-poa` | `POST`/`PATCH /session/<id>/update-poa-data/` | 10 / мин | `SESSION_UPDATE_POA_RATE_LIMIT` |

> [!NOTE]
>
> `GET /v3/session/<id>/decision/` обслуживается `SessionV3RetrieveView` и **не** входит в область `session-decision`. Для него действует только общий потолок `generic-get` 600 в минуту. Ограничение 100 в минуту по решению распространяется только на пути решений v1 и v2.

> [!WARNING]
>
> В кодовой базе также определены `FREE_SESSION_RATE_LIMIT = 10` и `PAID_SESSION_RATE_LIMIT = 600`. Эти константы **сейчас не применяются** к `POST /v3/session/`: для этого endpoint'а для всех приложений действует единый лимит `session-v2-create` в 600 в минуту. Не планируйте мощности, опираясь на ограничение бесплатного тарифа для каждого сценария, пока оно не будет описано как работающее.

## Формат ответа 429

Если вы превысили лимит в любой области, вы получите HTTP-ответ `429` с таким телом и заголовками:

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

| Заголовок | Значение |
| - | - |
| `X-RateLimit-Limit` | Максимальное число запросов, разрешённых в текущем окне для области, в которой был превышен лимит. |
| `X-RateLimit-Remaining` | Количество запросов, оставшихся до сброса окна. Становится равным `0`, как только вы превысили лимит. |
| `X-RateLimit-Reset` | Время в секундах эпохи Unix, когда счётчик сбрасывается в ноль. |
| `Retry-After` | Количество секунд до следующей попытки, округлённое вверх, чтобы ожидание всегда приходилось на следующее окно. Присутствует **только в ответах `429`**, а не в каждом запросе. |

Заголовки `X-RateLimit-*` возвращаются **только в ответе `429`**: успешные ответы сейчас их не содержат. Используйте значение `Retry-After` (или `X-RateLimit-Reset - now`) как задержку перед следующей попыткой.

## Рекомендации для клиента

* **Учитывайте `Retry-After`** как минимальную задержку перед повторной попыткой. Поверх неё добавьте экспоненциальную задержку с джиттером (`5s → 10s → 20s → 40s ± random`), чтобы два клиента, получившие `429` одновременно, не синхронизировались.
* **Прекращайте повторные попытки** после небольшого предела (например, 5 попыток). Передайте ошибку вызывающему коду и оповестите свою команду: постоянные ответы 429 обычно означают неконтролируемый цикл, а не кратковременный всплеск.
* **Используйте один идентификатор на каждую нагрузку.** Если один `x-api-key` используется сразу многими бэкендами, они попадают в один счётчик, и один «шумный» сосед может лишить остальных доступа к лимиту. Создавайте отдельное приложение (а значит, и отдельный `api_key`) для каждой среды, бренда или клиента. См. [Программная регистрация](https://docs.didit.me/ru/integration/programmatic-registration.md#управление-приложениями).
* **Кэшируйте результаты запросов решений.** Endpoint'ы `/decision/` не предназначены для частого опроса в тесных циклах. Если нужны обновления в реальном времени, используйте [webhook](https://docs.didit.me/ru/integration/webhooks.md), а `GET /v3/session/<id>/decision/` вызывайте только для догрузки данных или аудита.
* **Генерируйте PDF офлайн.** Рендеринг PDF нагружает процессор и ограничен 50 запросами в минуту. Запускайте его из очереди после того, как сессия перейдёт в конечный статус, а не при каждом просмотре страницы.

## Пример клиента с обработкой 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")
```

## Нужен больший запас?

Если 600 сессий в минуту недостаточно, например при маркетинговом запуске или догрузке данных, напишите на [support@didit.me](mailto:support@didit.me), указав UUID вашего `application` и ожидаемые постоянную и пиковую интенсивности запросов. Переопределения настраиваются для каждого приложения.


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