Заголовки ответа
Каждый response от FourA API содержит небольшой набор кастомных headers. Они полезны для трассировки, поддержки, сверки биллинга и последующего анализа.
Headers, которые устанавливает FourA
| Header | Где устанавливается | Описание |
|---|---|---|
X-FourA-Request-Id |
Каждый response /api/*, включая ошибки и 401, за исключением body, который FourA не может прочитать вовсе (400 Invalid JSON in request body, 413), отклоняемый до назначения ID |
UUID, идентифицирующий этот request. Логируйте его на своей стороне. |
X-FourA-Credits |
Каждый response /api/*, дошедший до backend |
Кредиты, списанные за этот вызов. Возвращается как при успехе, так и при ошибке (работа была выполнена в любом случае). |
X-FourA-Limit |
Каждый 403 или 429, вызванный лимитами вашего тарифа |
Какой лимит отклонил вызов: plan_limit_, затем feature, premium, concurrency, rate, browser_daily, credits или bandwidth. |
Retry-After |
Вызовы 429 из-за лимитов тарифа, решаемые ожиданием: concurrency, rate, credits, bandwidth |
Время ожидания в секундах целым числом. Совпадает с retry_after_seconds в body. |
X-FourA-Exit-Class |
Каждый вызов /api/proxy/ с указанием exitClass, вернувший страницу, а также каждый вызов Single или Browser через премиум exit |
premium или standard: класс exit, через который был доставлен body. Неудачный вызов Proxy ничего не вернул и не содержит этот header. |
X-FourA-Check-Page |
Ответы Single, Proxy Finder и Browser, чей body с HTTP 200 является распознанной FourA страницей проверки на ботов | Название страницы проверки, например amazon-captcha. За такой request плата не взимается: смотрите Request Outcomes. |
Content-Type |
Каждый response | Всегда application/json для envelope. Content-type целевого ресурса возвращается внутри поля headers объекта envelope. |
X-FourA-Request-Id
Каждый вызов POST /api/auto/, POST /api/single/, POST /api/proxy/ или POST /api/browser/ помечается UUID. Этот header устанавливается даже при ошибке аутентификации, что позволяет сопоставлять некорректно настроенные вызовы.
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
X-FourA-Credits: 2
Content-Type: application/json
...
Когда использовать
- Тикеты в поддержку: укажите request ID, и мы сможем найти точный вызов в наших логах.
- Собственные логи: сохраняйте его рядом со строкой лога вашего приложения. Если клиент пожалуется, что «данные были неверными в 14:32», вы сможете воспроизвести именно этот request.
- Трассировка в панели управления: тот же ID отображается в Activity feed для управляемых вами ключей, поэтому вы можете открыть соответствующую строку и изучить сохраненные request и response.
Пример: логирование на вашей стороне
import logging
import requests
log = logging.getLogger(__name__)
def fetch(url, api_key):
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},
)
request_id = resp.headers.get("X-FourA-Request-Id", "no-id")
credits = resp.headers.get("X-FourA-Credits", "0")
log.info("foura request_id=%s url=%s status=%s credits=%s", request_id, url, resp.status_code, credits)
resp.raise_for_status()
return resp.json()
async function fetchPage(url, apiKey) {
const resp = await fetch('https://eu.api.foura.ai/api/single/', {
method: 'POST',
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({ method: 'GET', url })
});
const requestId = resp.headers.get('X-FourA-Request-Id') || 'no-id';
const credits = resp.headers.get('X-FourA-Credits') || '0';
console.log(`foura request_id=${requestId} url=${url} status=${resp.status} credits=${credits}`);
return resp.json();
}
X-FourA-Credits
X-FourA-Credits сообщает стоимость выполненного вызова в кредитах. Это счетчик, а не счет: заголовок отражает затраты на работу независимо от результата. Биллинг в панели управления учитывает в рамках вашего тарифного плана только тарифицируемые результаты (список тарифицируемых результатов см. в Request Outcomes).
Справочник стоимости
| Движок | Базовая | С unblocker |
|---|---|---|
| Single | 1 | 2 |
| Proxy | 2 | 4 |
| Browser | 5 | 10 (когда защита была пройдена) |
/api/auto/ считается как один request в вашей панели управления со стоимостью в кредитах, равной сумме внутренних подвызовов (одиночный повтор на прогретой цели может обойтись в 2; холодное решение на сложном сайте может потратить значительно больше). Значение X-FourA-Credits в ответе auto равно meta.credits в теле ответа и отражает полную стоимость всей цепочки.
Зачем нужны и заголовок, и поле в теле?
Заголовок удобен: его можно прочитать до парсинга тела, записать в лог рядом со строкой запроса или суммировать по множеству вызовов без разбора JSON. Поле meta.credits в теле (Auto) или метаданные конкретного движка (в дашбордах Single, Proxy, Browser) содержат то же число, но доступное внутри конверта ответа.
X-FourA-Limit
X-FourA-Limit появляется только тогда, когда вызов был отклонен из-за лимитов вашего тарифного плана. Общие rate limit платформы никогда его не устанавливают, поэтому данный заголовок является самым быстрым способом отличить ситуацию "мой тариф остановил это" от "FourA перегружен" без парсинга тела ответа.
HTTP/1.1 429 Too Many Requests
X-FourA-Limit: plan_limit_concurrency
Retry-After: 1
X-FourA-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
Content-Type: application/json
Два из семи значений возвращаются с кодом 403 вместо 429: plan_limit_feature (endpoint или параметр exitCountries не включены в ваш тариф) и plan_limit_premium (exitClass: premium не включен в ваш тариф). Ни один из них не устанавливает Retry-After, так как ожидание не изменит результат.
STOP_ON = {
"plan_limit_feature", "plan_limit_premium",
"plan_limit_browser_daily", "plan_limit_credits", "plan_limit_bandwidth",
}
resp = requests.post(url, headers=headers, json=payload)
limit = resp.headers.get("X-FourA-Limit")
if limit in STOP_ON:
stop_the_run(limit) # hours or days away, not seconds
elif limit:
time.sleep(int(resp.headers.get("Retry-After", 1)))
Все семь значений и соответствующие поля тела ответа описаны в разделе Rate Limits.
X-FourA-Exit-Class
X-FourA-Exit-Class указывает класс exit node, доставившего тело ответа: premium для премиум exit node, standard для стандартного пула. Он присутствует в ответе POST /api/proxy/ при успешной доставке страницы, если в запросе был указан exitClass (в теле передается то же значение), а также в ответе Single или Browser, если закрепленный вами proxy являлся премиум exit node (в теле ответа это поле отсутствует). Неудачный вызов Proxy ничего не вернул, поэтому он не содержит ни header, ни поля.
HTTP/1.1 200 OK
X-FourA-Exit-Class: premium
X-FourA-Credits: 2
X-FourA-Request-Id: 2c1d0f9e-4a7b-4c3e-9d2a-8b1f6e5c4d3a
Content-Type: application/json
Трафик через premium exit учитывается как в расходе premium-трафика, так и в общем объеме трафика. Он измеряется на уровне сети и включает неудачные попытки premium, не вернувшие целевую страницу. Поэтому запрос с standard все равно мог израсходовать часть premium-трафика во время попытки, завершившейся ошибкой до ответа стандартного пула. Этот заголовок указывает класс узла, выполнившего доставку, а не факт расхода premium-трафика: отметка premium в строке Activity и страница Usage & Limits показывают фактически учтенные данные. Подробнее о работе exitClass и условиях использования premium exit: exitClass.
Cache Behavior
API не устанавливает Cache-Control или ETag в ответах. Каждый вызов обращается к бэкенду. Если вам требуется кеширование, настройте его на своей стороне.
Target Response Headers
Заголовки, возвращенные целевым сайтом, отсутствуют в заголовках ответа FourA API. Они передаются внутри JSON-контейнера в поле headers. Для эндпоинтов Single и Proxy это массив объектов с заголовками для каждого перехода (по одной записи на каждый шаг редиректа). Для эндпоинта Browser это плоский объект с заголовками финального ответа.
{
"status": 200,
"headers": [
{ "Content-Type": "text/html; charset=utf-8", "Server": "..." }
],
"data": "<!doctype html>...",
"total_time": 0.42
}
Если вам нужен определенный целевой header, считывайте его из поля headers объекта envelope, а не из HTTP response самого вызова API.
Related
- API Endpoints: Структура envelope для request и response
- API Errors: Формат ответов с ошибками
- Request Outcomes: Какие результаты тарифицируются
- Activity Log: История по каждому request с ключом request ID
- Rate Limits: Что означает каждое значение
X-FourA-Limit