halfoff.devДокументация
Получить ключ
Models API

Лимиты запросов и переключение

Лимиты ключа на запросы и параллелизм, короткие очереди ожидания мощности и автоматическое переключение между каналами. Какие коды статуса ожидать и как безопасно повторять запросы.

Дешёвые токены полезны, только если запросы проходят. Между вашим запросом и моделью стоят три вещи: лимиты, которые вы задаёте для ключа, ёмкость каналов за моделью и то, насколько эти каналы здоровы. Шлюз сам справляется с большинством проблем с ёмкостью и здоровьем: ненадолго ждёт и повторяет запрос в другом месте. Если не получается, вы видите короткий повторяемый 429 или 502.

Автоматическое переключение#

Когда канал отказывает, запрос повторяется на другом канале той же группы каналов, всего до трёх попыток. Повтор происходит, когда канал:

  • истекает по таймауту, недоступен или отвечает 408, 409, 425, 429 либо любым 5xx;
  • отклоняет запрос по причине на своей стороне, а не на вашей;
  • отказывает посреди потока до первого токена (см. Потоковая передача).

Новые разговоры распределяются по каналам, обслуживающим модель. Канал, который выдаёт больше ошибок, чем обычно, или работает заметно медленнее своей нормы, получает меньше новых разговоров, пока не восстановится. Канал, который продолжает отказывать, на время выводится из ротации, а закреплённые за ним разговоры переходят на здоровый канал.

Два случая никогда не повторяются:

  • Ваш запрос некорректен. Если модель отклоняет его с 400, 404, 413 или 422, другой канал отклонил бы его так же. Вы получаете статус и причину.
  • Вывод уже начался. После первого токена запрос привязан к своему каналу. Более поздний сбой приходит как событие ошибки внутри потока.

Ожидание мощности#

Каждый канал обрабатывает ограниченное число запросов одновременно. Если канал, который занял бы запрос, заполнен, шлюз пробует другие каналы, обслуживающие модель. Если заполнены все, запрос встаёт в очередь к тому каналу, который должен освободиться первым.

Общее время ожидания ограничено 10 секундами. Принятый запрос сообщает своё ожидание в x-halfoff-queued-ms. Непринятый завершается ошибкой 429 с сообщением All upstream capacity for this model is busy. Retry shortly. и заголовком retry-after.

Ожидание ничего не стоит; тарификация начинается, только когда запрос выполняется, а запрос, отклонённый с 429, не тарифицируется никогда.

Лимиты на ваших ключах#

Для каждого ключа можно задать ограничение Requests per minute и Max concurrent requests в разделе Limits & restrictions при создании или редактировании ключа в API-ключах. По умолчанию ни одно не задано.

ЛимитЧто считается
Requests per minuteЗапросы, начатые за последние 60 секунд, в скользящем окне.
Max concurrent requestsЗапросы в работе, включая открытые потоки до их завершения.

Запрос, превысивший лимит, ждёт свободный слот до 2 секунд. Если слот не освободился, он завершается ошибкой 429 с сообщением This API key has reached its rate or concurrency limit. и retry-after в секундах. Если выделить каждой нагрузке свой ключ со своими лимитами, одно задание не будет вытеснять другое. Остальные настройки ключей описаны в разделе API-ключи.

Коды статуса#

СтатусПричинаЧто делать
429Лимит ключа на RPM или параллелизм. Отправляется retry-after.Подождите retry-after секунд или увеличьте лимит.
429Вся ёмкость для модели оставалась занятой 10 секунд. Отправляется retry-after.Подождите retry-after секунд, затем повторите.
429Каждый испробованный канал вернул лимит запросов. Сообщение Upstream capacity for this model is busy. Retry shortly.Повторите с экспоненциальной задержкой.
502Каждый испробованный канал отказал. Сообщение The model provider returned an error. Please retry.Повторите с экспоненциальной задержкой.
500Непредвиденная ошибка шлюза.Повторите один-два раза; если не проходит, обратитесь в поддержку с x-halfoff-request-id.
402Баланс равен нулю или ниже, либо достигнут лимит расходов ключа.Пополните баланс или поднимите лимит. Не повторяйте.
400, 404, 413, 422Некорректный или слишком большой запрос либо неизвестный id модели.Исправьте запрос. Не повторяйте.
401, 403Ключ отсутствует, отозван или просрочен, либо ему не разрешена эта модель.Исправьте ключ. Не повторяйте.

Тип ошибки соответствует вашему API: rate_limit_error (Anthropic), rate_limit_exceeded (OpenAI) или RESOURCE_EXHAUSTED (Gemini) для 429 и api_error (UNAVAILABLE у Gemini) для 502. Все коды перечислены в разделе Ошибки.

Повторы в вашем коде#

К тому моменту, когда вы видите 429 или 502, шлюз уже перепробовал несколько каналов. Повторите ещё несколько раз с экспоненциальной задержкой и джиттером и учитывайте retry-after, если он отправлен.

Anthropic SDK и OpenAI SDK по умолчанию уже дважды повторяют 408, 409, 429 и 5xx. Для длинных пакетных прогонов разрешите больше:

Python
import os
from openai import OpenAI

client = OpenAI(base_url="https://halfoff.dev/v1", api_key=os.environ["HALFOFF_API_KEY"], max_retries=6)

При обычном HTTP применяйте ту же политику самостоятельно:

# --retry handles 429 and 5xx and respects retry-after
curl --retry 6 --retry-max-time 180 https://halfoff.dev/v1/chat/completions \
  -H "Authorization: Bearer $HALFOFF_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model": "gpt-5.6-luna", "messages": [{"role": "user", "content": "Classify: \"the app crashes on login\""}]}'

С потоками повторяйте, только если ошибка пришла до какого-либо содержимого. Поток, оборвавшийся на полпути, уже оплачен за частичный вывод, поэтому решите, оставить ли этот вывод или запросить весь ответ заново.

Баланс и лимиты расходов#

Перед выполнением каждый запрос проверяет ваш баланс и лимит расходов ключа. Если баланс равен нулю или ниже либо ключ исчерпал свой лимит, вы получите 402 с Insufficient balance. Top up at the dashboard. или This API key has reached its spend limit. Тип ошибки — insufficient_quota (OpenAI), billing_error (Anthropic) или RESOURCE_EXHAUSTED (Gemini).

Проверка выполняется в начале запроса, а списание проводится через несколько секунд после его завершения. Запрос, который стартовал при наличии средств на счёте, всегда доходит до конца, поэтому баланс может чуть уйти ниже нуля; ваше следующее пополнение покроет разницу. См. Биллинг.