Лимиты запросов
Каждый API request в FourA проходит три проверки перед тем, как попасть в движок: лимиты вашего тарифного плана, затем общий лимит платформы для вызванного endpoint, затем общий лимит платформы для всего трафика. Каждая проверка может отклонить request самостоятельно и возвращает собственное тело ответа.
Три проверки по порядку
- Лимиты тарифного плана. То, что разрешено вашим планом: доступные endpoint и параметры, количество одновременных request на endpoint, лимит request в минуту, количество browser request в день, а также доступные кредиты и трафик за расчетный период.
- Глобальный лимит платформы. Все запросы, которые хост API обрабатывает в данный момент, независимо от целевого endpoint. Отказ на этом этапе возвращает
"service": "api". - Лимит платформы на endpoint. Трафик сервисов single, proxy или browser, к которым вы обратились.
Сначала проверяется ваш тарифный план. Этот порядок зафиксирован в контракте и не является деталью реализации. Общие лимиты платформы разделяются всеми пользователями, поэтому request, который в любом случае был бы отклонен, не должен расходовать общие ресурсы. Если аккаунт отправляет больше положенного по плану, он отсекается до того, как затронет ресурсы других пользователей.
Проверки 2 и 3 учитывают общий трафик FourA, а не ваш. Отказ на любом из этих этапов означает "FourA перегружен", а не "вы отправили слишком много". Проверка 1 относится исключительно к вашему аккаунту и не зависит от других процессов на платформе.
Отказ на любой из общих проверок возвращает вашему аккаунту все задействованные лимиты, включая поминутный лимит и дневной слот browser request, так как request не достиг бэкенда. Это также не учитывается в паузе повторных попыток, описанной в разделе Requests per minute: отказ произошел из-за емкости FourA, а не из-за вашего плана.
POST /api/auto/ не занимает отдельного слота. Вложенные вызовы Single, Proxy и Browser, которые он выполняет для вас, проходят все три проверки как стандартные request. Поэтому параллельный пакет вызовов auto расходует лимиты вашего плана через свои подзапросы. (В статистике ваших request и проценте успешности сам вызов auto учитывается один раз, а вложенные вызовы отображаются как его попытки.)
Лимиты тарифного плана
При срабатывании лимита плана возвращается header X-FourA-Limit с указанием конкретного лимита. Тот же код содержится в теле ответа в поле reason, что позволяет строить ветвление логики без чтения headers. Тело ответа при превышении любого лимита плана содержит error, reason и documentation; остальные поля зависят от типа лимита.
X-FourA-Limit |
Статус | Что исчерпано |
|---|---|---|
plan_limit_feature |
403 | Вызванный endpoint или параметр exitCountries не входит в ваш тариф |
plan_limit_premium |
403 | exitClass: premium не входит в ваш тариф |
plan_limit_concurrency |
429 | Одновременные запросы к этому endpoint |
plan_limit_rate |
429 | Запросы в минуту к этому endpoint |
plan_limit_browser_daily |
429 | Запросы браузера за день |
plan_limit_credits |
429 | Платные кредиты за расчетный период |
plan_limit_bandwidth |
429 | Трафик за расчетный период |
Значения лимитов определяются вашим тарифом. Во вкладке Limits & Features в Usage & Limits они указаны рядом с текущим использованием. Не хардкодьте их: каждый отказ содержит значение лимита, вызвавшего блокировку.
Отклоненный запрос ничего не расходует. Результат имеет статус rate_limit, а оплачивается только success.
Endpoint или параметр не входит в тариф
Код 403 с plan_limit_feature означает, что запрос требует функцию, не включенную в тариф. Проверка выполняется до подсчета, поэтому отклоненный вызов не влияет на счетчики rate limit или дневного расхода.
{
"error": "The browser endpoint is not included in your plan (Free). Upgrade to use it.",
"reason": "plan_limit_feature",
"documentation": "https://foura.ai/prices"
}
Те же код и статус возвращаются в ответ на вызов POST /api/proxy/, устанавливающий exitCountries на тарифе без геотаргетинга. Строка error указывает имя параметра:
{
"error": "Geo targeting (the exitCountries parameter) is not included in your plan (Free). Remove the parameter or upgrade.",
"reason": "plan_limit_feature",
"documentation": "https://foura.ai/prices"
}
plan_limit_premium имеет тот же формат для exitClass: premium на тарифе без премиум-выходов. FourA может вместо этого обработать такой request из стандартного пула и вернуть exitClass: standard в response, поэтому обрабатывайте оба варианта. Ни один из них не расходует премиум-выход. См. exitClass.
Ни один 403 не устанавливает Retry-After. Ожидание не изменит результат.
Simultaneous requests
Конкурентность считается отдельно для каждого endpoint: ваш тариф задает один лимит для Single, один для Proxy и один для Browser. Request, превышающий лимит, возвращается с кодом 429 и Retry-After: 1:
{
"error": "Concurrency limit reached: your plan allows 50 simultaneous proxy request(s). Retry when an in-flight request finishes.",
"reason": "plan_limit_concurrency",
"documentation": "https://foura.ai/prices",
"limit": 50,
"in_flight": 51,
"retry_after_seconds": 1
}
in_flight учитывает и отклоненный request, поэтому его значение как минимум на единицу больше, чем у limit.
Решение заключается в ограничении собственного параллелизма, а не в увеличении числа повторных попыток. Повторная немедленная отправка того же пакета в ответ на 429 вызовет еще один 429 для каждого вызова внутри него. См. готовый шаблон в Параллельное выполнение запросов.
Requests per minute
Для Single и Proxy действует лимит запросов в минуту, который рассчитывается по скользящему окну в одну минуту. Учитываются только принятые requests: отклоненный request исключается из подсчета, поэтому аккаунт, стабильно запрашивающий чуть больше установленного лимита, получает объем в рамках своей квоты, а не блокировку почти всех запросов.
{
"error": "Rate limit reached: your plan allows 600 single requests per minute. Cool down and retry.",
"reason": "plan_limit_rate",
"documentation": "https://foura.ai/prices",
"limit_per_minute": 600,
"current_rate": 613,
"retry_after_seconds": 17
}
retry_after_seconds показывает, через сколько времени будет разрешен еще один request, если между ними ничего не отправлять: минимум 1 секунда и максимум 120. Header Retry-After содержит то же самое значение.
Для повторной отправки отклоненных requests с меньшим интервалом действует отдельное правило. Когда количество отклоненных этим лимитом requests за скользящую минуту превышает лимит в два раза, вызов отклоняется с паузой в 30 секунд:
{
"error": "Rate limit cooldown: 1250 requests over your plan's 600 single requests per minute were refused in the last minute and kept arriving. Pause for 30 seconds.",
"reason": "plan_limit_rate",
"documentation": "https://foura.ai/prices",
"limit_per_minute": 600,
"current_rate": 540,
"refused_last_minute": 1250,
"cooldown": true,
"retry_after_seconds": 30
}
Отказы во время паузы не учитываются, поэтому пауза завершается сама по себе по истечении минуты, даже если клиент продолжает повторять запросы. Чтобы отличить паузу от обычного лимита, используйте cooldown, а не текст error.
Запросы браузера в день
Для Browser нет поминутного лимита. Лимит тарифного плана представляет собой количество запросов браузера в день, подсчитываемое с полуночи UTC, и счетчик учитывает каждый принятый запрос браузера, а не только успешные.
{
"error": "Daily browser limit reached: your plan allows 300 browser requests per day (resets at midnight UTC).",
"reason": "plan_limit_browser_daily",
"documentation": "https://foura.ai/prices",
"limit_per_day": 300,
"used_today": 301
}
Этот отказ не содержит retry_after_seconds и header Retry-After, так как ожидание составляет часы, а не секунды. Воспринимайте это как остановку и запланируйте следующий запуск на полночь UTC.
Кредиты за расчетный период
Учитываются только оплаченные кредиты, то есть только успешные request. Когда общая сумма списаний достигает лимита кредитов, доступных вам в этом периоде, последующие request отклоняются до сброса периода или покупки дополнительных кредитов.
{
"error": "Credit limit reached: 75,000 of 75,000 credits used this billing period. Upgrade your plan or wait for the reset.",
"reason": "plan_limit_credits",
"documentation": "https://foura.ai/prices",
"used": 75000,
"hard_stop": 75000,
"retry_after_seconds": 86400,
"resets_at": "2026-10-01T00:00:00.000Z"
}
hard_stop показывает количество оплаченных кредитов, при достижении которого запросы в текущем периоде блокируются. Считывайте это значение из тела ответа вместо самостоятельного вычисления: оно уже включает все дополнительные кредиты, купленные сверх тарифного плана.
Трафик за расчетный период
Тарифные планы с лимитом трафика отклоняют запросы, как только стандартный трафик за текущий период достигает этого ограничения. Для премиум-трафика предусмотрен отдельный лимит, и он не учитывается в этом ограничении. Купленный трафик учитывается так же, как и включенный в тариф, а строка error указывает общий доступный объем, а не только то, что входит в базовый тарифный план.
{
"error": "Bandwidth limit reached: 50 GB is available to you this billing period.",
"reason": "plan_limit_bandwidth",
"documentation": "https://foura.ai/prices",
"used_bytes": 53687091200,
"limit_bytes": 53687091200,
"retry_after_seconds": 86400,
"resets_at": "2026-10-01T00:00:00.000Z"
}
Для обоих периодических лимитов retry_after_seconds ограничен 24 часами; resets_at указывает точный момент смены периода.
Plan limit fields
| Field | Type | Present on | Description |
|---|---|---|---|
error |
string | all | Понятное для человека сообщение, включая лимитирующее число |
reason |
string | all | plan_limit_ и название лимита. То же значение, что и в заголовке X-FourA-Limit. |
documentation |
string | all | Ссылка на страницу тарифных планов |
retry_after_seconds |
number | concurrency, rate, credits, bandwidth | Время ожидания. То же значение, что и в заголовке Retry-After. |
limit |
number | concurrency | Разрешенное тарифным планом число одновременных requests к этому endpoint |
in_flight |
number | concurrency | Число requests, выполняемых на этом endpoint для вашего аккаунта, включая отклоненный |
limit_per_minute |
number | rate | Разрешенное тарифным планом число requests в минуту к этому endpoint |
current_rate |
number | rate | Число requests за скользящую минуту, включая отклоненный |
refused_last_minute |
number | rate pause | Число requests, отклоненных минутным лимитом за скользящую минуту. Только при 30-секундной паузе. |
cooldown |
boolean | rate pause | true при 30-секундной паузе из-за слишком частых повторных попыток. Отсутствует при обычном отказе по минутному лимиту. |
limit_per_day |
number | browser daily | Разрешенное тарифным планом число browser requests в день |
used_today |
number | browser daily | Число browser requests, учтенных за сегодня, включая отклоненный |
used |
number | credits | Израсходованные credits за текущий период |
hard_stop |
number | credits | Лимит credits, при достижении которого requests в текущем периоде блокируются |
used_bytes |
number | bandwidth | Стандартный трафик за текущий период, в байтах. Трафик Premium не включен. |
limit_bytes |
number | bandwidth | Доступный объем трафика в байтах на текущий период |
resets_at |
string | credits, bandwidth | Метка времени окончания периода в формате ISO 8601 |
Лимиты тарифного плана используют retry_after_seconds. Описанные ниже лимиты платформы используют retryAfter. Модуль повторных попыток должен считывать оба параметра или проверять заголовок Retry-After, который задается только лимитами тарифа.
Platform Limits
Проверки платформы отслеживают два параметра для каждого сервиса и еще один общий для всех:
- Concurrency: сколько requests FourA выполняет одновременно.
- RPM: сколько requests FourA принял за последние 60 секунд.
Оба счетчика являются общими для всех пользователей сервиса. Поля current и limits в приведенных ниже ответах описывают платформу, а не ваш аккаунт. Чтобы узнать собственные значения, используйте in_flight из ответа о лимитах тарифа или откройте раздел Usage & Limits в панели управления.
429: RPM Exceeded
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": {
"concurrency": 12,
"rpm": 3000
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
Сервис исчерпал лимит запросов за последнюю минуту. Подождите retryAfter секунд.
503: Concurrency Exceeded
{
"error": "Service at capacity",
"status": 503,
"service": "proxy",
"retryAfter": 2,
"current": {
"concurrency": 500,
"rpm": 1200
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
Сервис выполняет максимально допустимое количество одновременных запросов. Это проходит за несколько секунд.
Сервис отключен
Когда сервис временно недоступен из-за технического обслуживания, API возвращает 503 с другим сообщением об ошибке:
{
"error": "Service disabled",
"status": 503,
"service": "single",
"retryAfter": 60,
"current": { "concurrency": 0, "rpm": 0 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Это не rate limit. Сервис временно недоступен. Проверьте значение retryAfter и повторите попытку через указанное количество секунд. Обычно это решается в течение нескольких минут.
Оба формата 503 содержат одинаковые ключи, поэтому делайте ветвление по строке error, а не по наличию определенных полей. Service disabled означает техническое обслуживание, Service at capacity означает параллелизм.
Для формата технического обслуживания current.concurrency и current.rpm всегда равны 0: request был отклонен до проведения каких-либо измерений.
Platform Limit Fields
| Field | Type | Description |
|---|---|---|
error |
string | Читаемое сообщение об ошибке |
status |
number | HTTP status code (429 или 503) |
service |
string | Какой сервис отклонил вызов: single, proxy, browser или api |
retryAfter |
number | Рекомендуемое время ожидания в секундах перед повторной попыткой |
current.concurrency |
number | Requests, которые сервис выполнял на всей платформе в момент отказа |
current.rpm |
number | Requests, принятые сервисом на всей платформе за последние 60 секунд |
limits.maxConcurrency |
number | Лимит параллелизма сервиса на всей платформе |
limits.maxRpm |
number | Лимит сервиса в минуту на всей платформе |
Handling Every Refusal With One Helper
Retry-After задан для лимитов тарифа, которых имеет смысл подождать, retry_after_seconds находится в их телах, а retryAfter находится в телах платформы. Считывайте все три в указанном порядке и останавливайтесь на тех лимитах тарифа, которые ожидание не сбросит:
import time
import requests
# Plan limits that a short wait never clears.
STOP_ON = {
"plan_limit_feature",
"plan_limit_premium",
"plan_limit_browser_daily",
"plan_limit_credits",
"plan_limit_bandwidth",
}
def wait_seconds(resp, attempt):
header = resp.headers.get("Retry-After")
if header and header.isdigit():
return int(header)
try:
body = resp.json()
except ValueError:
return 2 ** attempt
return body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** attempt
def fetch(url, api_key, max_retries=5):
for attempt in range(max_retries):
resp = requests.post(
"https://eu.api.foura.ai/api/single/",
headers={"X-API-Key": api_key, "Content-Type": "application/json"},
json={"method": "GET", "url": url},
)
limit = resp.headers.get("X-FourA-Limit")
if limit in STOP_ON:
raise RuntimeError(f"stopped by plan limit {limit}: {resp.json().get('error')}")
if resp.status_code in (429, 503):
time.sleep(wait_seconds(resp, attempt))
continue
return resp
raise RuntimeError("Max retries exceeded")
Дневной лимит не восстанавливается часами, а лимит периода не восстанавливается днями, поэтому воспринимайте их как полную остановку, а не как ожидание. Прочтите resets_at из тела ответа, если хотите запланировать следующий запуск.
Советы
- Ограничивайте количество одновременных запросов in flight вместо повторной отправки отклоненной пачки. Шквал повторных попыток превращает одну ошибку 429 во множество.
- Сначала проверяйте
X-FourA-Limit. Этот параметр сразу показывает, относится ли лимит к вашему тарифу или к платформе, и ни один отказ платформы его не устанавливает. - Не прописывайте числа жестко в коде. Каждый ответ с ограничением тарифа содержит вызвавший отказ лимит, а раздел Usage & Limits отображает их все.
- Значение
retryAfterдля ограничений платформы фиксировано по типу: 2 секунды для concurrency, 5 для RPM, 60 для технического обслуживания. - Сопоставляйте по
error, чтобы различать два типа ошибок 503. Обе структуры содержатcurrentиlimits, поэтому простая проверка на наличие этих полей примет техническое обслуживание за проблему с concurrency. - Ошибка 403 с
X-FourA-Limitотносится к вашему тарифу, а не к целевому сайту. Целевой сайт вообще не отвечал.
Порт proxy имеет собственные лимиты
Все вышеперечисленное относится к JSON API. Трафик, отправляемый через proxy.foura.ai, регулируется отдельным набором лимитов тарифа в других единицах: одновременно открытые туннели, открытия туннелей в минуту и стандартный трафик за расчетный период. Эти отказы приходят в виде HTTP-статуса с заголовком X-Foura-Error, а не в виде JSON-тела, так как у CONNECT нет тела для передачи данных. Ознакомьтесь с Proxy Port для таблицы статусов и How Your Plan Is Metered, чтобы узнать, из какого пула списываются гигабайты порта.
Связанные разделы
- Run Requests in Parallel: Готовый шаблон с ограничением concurrency
- Usage & Limits: Все лимиты тарифа рядом с текущим расходом
- API Endpoints: Полный справочник параметров
- Error Handling: Все типы ошибок и ответов
- Response Headers:
X-FourA-Limit,Retry-Afterи остальные - Troubleshooting: Распространенные проблемы и их решения