Skip to main content
Платформа ограничивает частоту запросов на двух уровнях. При превышении возвращается 429 Too Many Requests с кодом RATE_LIMITED в конверте ошибки.

Два уровня ограничений

Глобальный (по IP)

Базовый лимит уровня приложения — 120 запросов в минуту на исходящий IP (скользящее окно 60 секунд). Защищает инстанс от всплесков с одного адреса.

Per-site (по API-ключу)

Индивидуальный счётчик на каждый сайт обменника — «шумный» клиент не расходует лимит остальных. Окно — фиксированные 60 секунд, лимит по умолчанию — 120 запросов в минуту.
Per-site лимит настраивается оператором: либо персональный override для вашего сайта, либо глобальный дефолт инстанса. Значение 0 означает «без per-site лимита» (остаётся только глобальный лимит по IP). Уточните действующее значение при подключении.

Ответ при превышении

При срабатывании per-site лимита платформа возвращает 429 и проставляет заголовки:
ЗаголовокЗначение
Retry-AfterЧерез сколько секунд повторить (до сброса окна)
X-RateLimit-LimitДействующий лимит запросов в минуту
X-RateLimit-RemainingОстаток в текущем окне (при 429 всегда 0)
{
  "ok": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded for this site (120 req/min). Retry after 37s."
  }
}
Заголовки ответа
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0

Стратегия повторов

1

Уважайте Retry-After

Получив 429, дождитесь количества секунд из Retry-After, прежде чем повторить.
2

Применяйте экспоненциальный backoff с джиттером

Если Retry-After отсутствует — повторяйте с растущей паузой (например, 1s, 2s, 4s, 8s) и небольшим случайным джиттером, чтобы не синхронизировать повторы.
3

Ограничьте число попыток

Задайте максимум попыток (например, 5) и переходите к алертингу, если лимит держится долго.
async function withRateLimitRetry(fn, maxAttempts = 5) {
  for (let attempt = 1; ; attempt++) {
    const res = await fn();
    if (res.status !== 429) return res;
    if (attempt >= maxAttempts) throw new Error('Rate limit: исчерпаны попытки');

    const retryAfter = Number(res.headers.get('Retry-After'));
    const waitMs = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter * 1000
      : Math.min(2 ** attempt * 1000, 30_000) + Math.random() * 250; // backoff + джиттер
    await new Promise((r) => setTimeout(r, waitMs));
  }
}

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

Не опрашивайте статус депозита или выплаты в тугом цикле. Подпишитесь на webhooks — они доставляют изменения статуса мгновенно, а polling оставьте редким запасным механизмом (раз в несколько секунд, не чаще).
  • Кэшируйте справочники (GET /v1/public/networks, GET /v1/public/assets) — они меняются редко.
  • Группируйте проверки балансов вместо запроса на каждую операцию.
  • Соблюдайте webhook-first подход: реагируйте на события, а не опрашивайте.

Частые вопросы

Если на сервере обменника несколько процессов делят один исходящий IP, они складываются в глобальный лимит по IP (120 req/min). Также проверьте, не запущен ли где-то цикл polling.
По умолчанию 120 req/min на сайт, но оператор может задать персональное значение или отключить per-site лимит (0). Действующий лимит виден в заголовке X-RateLimit-Limit ответа 429. Точное значение уточняйте у оператора инстанса.
Per-site счётчик работает в режиме fail-open: при сбое инфраструктуры лимитирования запрос пропускается, а не отклоняется. Тем не менее закладывайте обработку 429 с повтором — это штатное поведение под нагрузкой.
Связанные страницы: Ошибки, Webhooks, Частые вопросы.