# Обмеження швидкості

MoreLogin застосовує обмеження на шлюзі для стабільності API. Підтверджена виробнича конфігурація для API та Open API: 200 запитів за хвилину і burst 10.

## Поточний контракт реалізації

| Параметр | Поведінка у продакшені |
|  --- | --- |
| Алгоритм | GCRA (Generic Cell Rate Algorithm) |
| Налаштування API | `rate=200`, `burst=10`, `period=1m` |
| Налаштування Open API | `rate=200`, `burst=10`, `period=1m` |
| Постійне відновлення | Один дозвіл кожні 0,3 секунди, приблизно 3,33 дозволи на секунду |
| Burst | До 10 дозволів можуть бути доступні відразу |
| Ключ області Open API | Шлях запиту + ID команди |
| Ключ області API | Шлях запиту + ID команди; якщо ID команди недоступний, використовується ID API, потім IP клієнта |
| Перевизначення під час роботи | Правила API для маршруту або команди можуть перевизначити налаштування за замовчуванням |
| Пакетні запити | Один HTTP-запит витрачає один дозвіл шлюзу; кількість елементів обмежувач не враховує |


These are the confirmed production gateway values, not the Java fallback (`rate=1`, `burst=1`, `period=1s`). At `rate=200` over 60 seconds, one permit is restored every 0.3 seconds (approximately 3.33 per second), and up to 10 permits can accumulate. The localhost Local API does not traverse this public cloud gateway.

- `rate`: permits restored during `period`
- `burst`: maximum permits immediately available
- `period`: restoration interval


## Відповідь при обмеженні

```json
{
  "code": 35000,
  "msg": "API requests are too frequent. Please try again later.",
  "data": null,
  "requestId": "request-trace-id"
}
```

- The current response writer does not explicitly set HTTP `429`; inspect body `code` even when HTTP status is `200`.
- No `Retry-After`, `RateLimit-*`, or `X-RateLimit-*` headers are currently emitted.
- Handle HTTP `429` defensively for future gateway or edge-proxy changes.
- The message language can vary; branch on `code`, not `msg`.


## Безпечні повтори

Retry reads with exponential backoff and jitter. For writes, query current state before retrying. A general public idempotency-key header is not currently documented.

```python
import random
import time
import requests

def api_request_with_retry(url, payload, headers=None, max_retries=4):
    for attempt in range(max_retries):
        response = requests.post(url, json=payload, headers=headers, timeout=30)
        try:
            body = response.json()
        except ValueError:
            body = {}

        limited = response.status_code == 429 or body.get("code") == 35000
        if not limited:
            return response

        retry_after = response.headers.get("Retry-After")
        delay = float(retry_after) if retry_after and retry_after.isdigit() else min(2 ** attempt, 30) + random.uniform(0, 0.5)
        time.sleep(delay)

    raise RuntimeError("Rate limit retry budget exhausted")
```

## Зменшення кількості запитів

- Prefer batch endpoints when their semantics match the operation.
- Кешуйте довідкові дані: часові пояси, мови, ядра та моделі пристроїв.
- Poll asynchronous operations with increasing intervals and stop at a terminal state.
- Do not blindly retry create, purchase, upload-registration, or schedule-creation requests.