Ошибки 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
В теле запроса отсутствуют обязательные поля, оно содержит недопустимые значения или указывает целевой ресурс, который 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"
}
Решение: Убедитесь, что ваш запрос содержит все обязательные поля, URL используют http:// или https://, а хост разрешается в публичный адрес.
401: Unauthorized
Ваш API-ключ отсутствует или недействителен.
Отсутствует ключ:
{
"error": "Missing API key. Include X-API-Key header."
}
Недействительный ключ:
{
"error": "Invalid API key"
}
Решение: Проверьте, что ваш заголовок X-API-Key содержит валидный ключ. При необходимости сгенерируйте новый ключ в Dashboard.
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: Server Error
Что-то пошло не так на нашей стороне.
Решение: Повторите запрос после небольшой паузы. Если ошибка повторяется, проверьте страницу статуса или обратитесь в поддержку, указав X-Foura-Request-Id из неудавшегося ответа.
503: Service Disabled or At Capacity
Статус 503 означает, что сервис временно недоступен из-за технического обслуживания либо вы достигли лимита параллельных запросов. Оба ответа содержат поле retryAfter. Вариант с лимитом параллельных запросов также включает current и limits.
{
"error": "Service disabled",
"status": 503,
"retryAfter": 60
}
Решение: Подождите retryAfter секунд, затем повторите попытку. На странице статуса указаны активные периоды технического обслуживания.
Ошибки на стороне целевого ресурса внутри 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:
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
- Request Outcomes: описание семи возможных результатов запроса
- Типичные проблемы: симптомы, причины, решения