Ошибки API
Как обрабатывать ошибки от API FourA.
Формат ответа с ошибкой
API возвращает плоские объекты JSON для всех ошибок. Здесь нет вложенного объекта error или кодов ошибок.
{
"error": "Invalid API key"
}
Некоторые ошибки включают дополнительные поля, такие как status, service, retryAfter, current или limits, на верхнем уровне:
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Отслеживание запроса
Каждый ответ API (успешный или с ошибкой) включает заголовок X-FourA-Request-Id с UUID для этого вызова. Логируйте его на вашей стороне. Если вам понадобится узнать в поддержке, что произошло с конкретным запросом, этот ID поможет нам его найти.
curl -i -X POST https://eu.api.foura.ai/api/single/ \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"method": "GET", "url": "https://example.com"}'
# HTTP/1.1 200 OK
# X-FourA-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
# Content-Type: application/json
# ...
Типы ошибок
400: Bad Request
Тело request не содержит обязательных полей, включает недопустимые значения или указывает цель, которую API отказывается получить.
{
"error": "Invalid request body format"
}
Тот же код 400 также включает защиту от SSRF. Если ваш url разрешается в частный, loopback или иной зарезервированный диапазон IP-адресов (RFC 5735, RFC 6598, зарезервированные блоки IPv6), запрос отклоняется до того, как он покинет сеть FourA:
{
"error": "Target <ip> resolves to a private/reserved IP"
}
Некорректный JSON в теле отклоняется таким же образом, до чтения каких-либо полей:
{
"error": "Invalid JSON in request body"
}
Поля proxy и ignoreProxies имеют собственные ошибки серии 400. Оба принимают непрозрачные ID прокси, возвращенные в предыдущих ответах, поэтому декодировать что-либо другое не удастся:
| Сообщение | Что произошло |
|---|---|
Invalid proxy format |
Значение proxy не является ID прокси, выданным FourA. Сюда попадает необработанный адрес прокси. |
Invalid ignoreProxies format |
Одна из записей в ignoreProxies не является ID прокси. |
Proxy not found |
ID успешно декодирован, но больше не ведет на активный узел. Выберите новый. |
Исправление: Убедитесь, что ваш request содержит все обязательные поля, URL используют http:// или https://, хост разрешается в публичный адрес, а любое значение proxy является ID, скопированным без изменений из предыдущего ответа.
401: Unauthorized
Ваш API ключ отсутствует или недействителен.
Отсутствующий ключ:
{
"error": "Missing API key. Include X-API-Key header."
}
Неверный ключ:
{
"error": "Invalid API key"
}
Решение: Убедитесь, что ваш заголовок X-API-Key содержит действительный ключ. При необходимости сгенерируйте новый ключ в панели управления.
429: Rate Limited
Вы отправили слишком много запросов за короткий промежуток времени.
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": { "concurrency": 12, "rpm": 3000 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Решение: Подождите количество секунд, указанное в retryAfter, прежде чем отправлять новые запросы. Подробнее см. rate limits.
500: Ошибка сервера
На нашей стороне что-то пошло не так.
Решение: Повторите запрос через небольшую паузу. Если ошибка сохраняется, проверьте страницу статуса или обратитесь в поддержку, предоставив X-FourA-Request-Id из неудачного ответа.
502: Upstream недоступен
FourA связался со своим движком, но не смог использовать полученный ответ.
{
"error": "Upstream unavailable",
"details": "..."
}
Решение: Повторите попытку с небольшой задержкой. Проблема на нашей стороне, поэтому это бесплатно: результат имеет статус service_error и тарифицируется только success.
504: Upstream Timeout
Движок не завершил работу в рамках бюджета времени для этого запроса.
{
"error": "Upstream timeout",
"details": "the backend did not finish inside the time budget for this request"
}
Ошибка 504 связана с тем, сколько времени заняла работа, а не с вашим ключом, параметрами или proxy. Медленные целевые сайты, холодное решение проверок и большие страницы являются обычными причинами.
Исправление: Увеличьте timeout_ms в request (Single принимает до 120000, Browser до 120000, Auto до 180000) или повторите попытку. FourA ожидает в течение указанного вами бюджета времени плюс небольшой запас, поэтому запрос дополнительного времени действительно дает больше времени.
503: Сервис отключен или перегружен
Ошибка 503 означает, что сервис временно недоступен для технического обслуживания, или вы достигли лимита параллельных запросов. Оба ответа включают поле retryAfter. Форма ответа для параллельных запросов также включает current и limits.
{
"error": "Service disabled",
"status": 503,
"retryAfter": 60
}
Решение: Подождите retryAfter секунд, затем повторите попытку. На странице статуса указаны активные окна технического обслуживания.
Третий вариант 503 не содержит retryAfter. Это означает, что движок вашего endpoint перезапускался в момент поступления запроса:
{
"error": "Backend service unavailable",
"backend_status": 503
}
Повторите попытку через одну-две секунды.
Чтение ошибок из /api/auto/
POST /api/auto/ отвечает статусом HTTP 200 при любом выполнении цепочки, даже если каждый шаг завершился ошибкой. Фактический результат находится в теле:
{
"status": 0,
"error": "all attempts failed",
"attempts": 7,
"meta": { "rung": "fail", "solved": false, "attempts": 7, "credits": 47 }
}
Поэтому не используйте ветвление логики на основе статуса транспорта для Auto. Вместо этого читайте status и error из тела ответа. Настоящий статус, отличный от 200, от /api/auto/ означает, что FourA отклонил вызов до запуска цепочки: 401, 400, 429 или 503, как описано выше.
Ошибки на стороне целевого сервера внутри 200 OK
Не каждая ошибка проявляется как HTTP-статус, отличный от 2xx. Если целевой сайт возвращает HTTP 200 с полезной нагрузкой ошибки, FourA все равно передает вам тело, но классифицирует запрос как application_error. Если цель возвращает не 2xx, который не принимается вашими правилами validate, результатом будет application_fail, а тело приходит без изменений.
Оба случая тарифицируются так, как если бы запрос успешно выполнился на сетевом уровне. В справочнике Outcomes описана полная таксономия.
Кодировка ответа
FourA автоматически декодирует тела ответов в UTF-8. Если цель отдает windows-1251, gbk, shift_jis, iso-8859-* или любую другую кодировку, заявленную в заголовке Content-Type или HTML-теге <meta charset>, вы получаете чистую строку UTF-8 в поле data (single, proxy) или body (browser).
Для бинарных данных (изображения, protobuf, сырое аудио) установите returnBuffer: true в запросе. Тело возвращается как буфер base64 без применения перекодировки символов.
Стратегия повторных попыток
Практическая политика повторных попыток:
import time
import requests
def make_request(url, payload, api_key, max_retries=3):
for attempt in range(max_retries):
resp = requests.post(
url,
headers={"X-API-Key": api_key, "Content-Type": "application/json"},
json=payload,
)
if resp.status_code == 200:
return resp.json()
body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
retry_after = body.get("retryAfter", 2 ** attempt)
request_id = resp.headers.get("X-FourA-Request-Id", "?")
if resp.status_code in (429, 503):
time.sleep(retry_after)
continue
if resp.status_code >= 500: # 500, 502, 503, 504 are all ours to fix
time.sleep(2 ** attempt)
continue
# 400/401/404 won't fix themselves
raise RuntimeError(f"{resp.status_code} (request {request_id}): {body.get('error')}")
raise RuntimeError(f"Exhausted {max_retries} retries")
Связанные материалы
- Rate Limits: подробности параллелизма и RPM
- Результаты запросов: описание семи возможных значений
- Частые проблемы: симптомы, причины, решения
- Защита от ботов: когда body содержит страницу challenge вместо ошибки