# Лимиты

Лимиты защищают систему лагеря от зациклившихся программ: обычная CRM в них не упирается. Но
ваш код должен правильно обрабатывать ответ `429` — особенно при первой загрузке базы и при
догонянии событий после простоя.

## Лимиты

| Что                                                     | Предел                                               | На что считается   |
| ------------------------------------------------------- | ---------------------------------------------------- | ------------------ |
| Чтение (`GET`)                                          | 10 в секунду, всплеск до 50                          | подключение        |
| Запись (`POST`, `PATCH`, `DELETE`)                      | 2 в секунду, всплеск до 10                           | подключение        |
| «Тяжёлые» запросы                                       | 1 в секунду                                          | подключение        |
| Одновременных запросов                                  | 10                                                   | подключение        |
| Одновременных записей с `Idempotency-Key`               | 2; лишние ждут своей очереди, а не получают отказ    | подключение        |
| Новых броней                                            | 30 в минуту (считаются только оформленные, не отказы) | отдел             |
| Проверок «можно ли оформить» (`POST /bookings/check`)   | 300 в час                                            | отдел              |
| Счетов Kaspi на одну бронь                              | 5 в час                                              | бронь              |
| Веб-сокетов                                             | 3 одновременно                                       | подключение        |
| Действующих вебхуков                                    | 5                                                    | подключение        |
| Неверный ключ                                           | 20 попыток за 15 минут, потом адрес блокируется на 15 минут | IP-адрес     |
| Размер тела запроса                                     | 1 МБ                                                 | запрос             |
| Время ответа                                            | 30 секунд, потом `503 timeout`                       | запрос             |

«Тяжёлые» запросы — это выгрузки и PDF: отчёты (`GET /reports/shifts`, `/reports/debts`,
`/reports/unpaid`), сверка (`GET /reconcile/bookings`), PDF путёвки, `GET /events` с `limit` больше
100, каждая порция догоняния в веб-сокете и проверка вебхука (`POST /webhooks/{id}/test`).

«Всплеск» значит: если вы какое-то время не делали запросов, можно сразу сделать до 50 чтений
подряд, а дальше — 10 в секунду.

Лагерь может поменять лимиты чтения и записи для вашего подключения. Ваши текущие лимиты — в ответе
`GET /me` (поле `limits`).

## Заголовки лимита

В ответах на запросы с действующим ключом есть заголовки — по тому виду лимита (чтение, запись или
тяжёлое), к которому относится запрос:

| Заголовок             | Что значит                                    |
| --------------------- | --------------------------------------------- |
| `RateLimit-Limit`     | Размер окна лимита                            |
| `RateLimit-Remaining` | Сколько запросов осталось сейчас              |
| `RateLimit-Reset`     | Через сколько секунд окно восстановится       |

В ответе на запрос без ключа или с неверным ключом этих заголовков нет.

## Ответ 429

Превышение — ответ `429` с кодом `rate_limited` и заголовком `Retry-After` — **через сколько секунд
повторить**:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 1
RateLimit-Limit: 10
RateLimit-Remaining: 0
RateLimit-Reset: 1
Content-Type: application/json

{"code":"rate_limited","message":"Слишком много запросов. Повторите через 1 с","request_id":"r8KfQ2mZx7LpT0aVn3Wd"}
```

Что делать:

1. Подождите **ровно `Retry-After` секунд** (не меньше).
2. Повторите тот же запрос. Если это `POST` — **с тем же `Idempotency-Key`**: отказ `429` не
   запоминается под ключом, повтор выполнится.
3. Не повторяйте мгновенно в цикле — так вы только продлеваете блокировку.

Пример — в [Повторе запроса](/partners/idempotency#как-устроить-у-себя): там `429` обрабатывается
вместе с обрывами связи.

## Как не упираться в лимиты

- **Не опрашивайте брони по кругу.** Узнавайте об изменениях из [событий](/partners/events) —
  лучше [вебхуками](/partners/webhooks).
- **Загружайте базу порциями по 200** (`limit=200`) и делайте запросы последовательно, а не 50 сразу.
- **Ограничьте параллельность** в своей CRM: 2–4 одновременных запроса к API хватает с запасом.
- **Не перечитывайте смены перед каждым показом.** Достаточно раз в минуту или по событию
  `shift.seats_changed`.
- **Отчёты — по расписанию**, например раз в час, а не на каждое открытие страницы менеджером.
