Response Headers

Every response from the FourA API includes a small set of custom headers. They're useful for tracing, support, billing reconciliation, and post-hoc analysis.

Headers FourA Sets

Header Set on Description
X-FourA-Request-Id Every /api/* response, including errors and 401s, except a body FourA can't read at all (400 Invalid JSON in request body, 413), which is refused before an ID is assigned A UUID identifying this request. Log it on your side.
X-FourA-Credits Every /api/* response that reached the backend Credits spent on this call. Returned on success and on failure (the work was done either way).
X-FourA-Limit Every 403 or 429 raised by one of your plan's limits Which limit refused the call: plan_limit_ followed by feature, premium, concurrency, rate, browser_daily, credits, or bandwidth.
Retry-After Plan-limit 429s that a wait clears: concurrency, rate, credits, bandwidth Seconds to wait, as an integer. Matches retry_after_seconds in the body.
X-FourA-Exit-Class Every /api/proxy/ call that named an exitClass and delivered a page, and every Single or Browser call served through a premium exit premium or standard: the class of exit that delivered the body. A failed Proxy call delivered nothing and carries none.
X-FourA-Check-Page Single, Proxy Finder and Browser responses whose HTTP 200 body is a bot-check page FourA recognises The check page's name, for example amazon-captcha. Such a request isn't billed: see Request Outcomes.
Content-Type Every response Always application/json for the envelope. The target's content-type comes back inside the envelope's headers field.

X-FourA-Request-Id

Each call to POST /api/auto/, POST /api/single/, POST /api/proxy/, or POST /api/browser/ is tagged with a UUID. The header is set even when authentication fails, so you can correlate misconfigured calls too.

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
...

When to use it

  • Support tickets: include the request ID and we can find the exact call in our records.
  • Your own logs: store it next to your application log line. If a customer complaint says "the data was wrong at 14:32", you can replay the exact request.
  • Dashboard tracing: the same ID appears in the Activity feed for keys you manage, so you can open the matching row and inspect the captured request and response.

Example: log on your side

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 reports the credit cost of the call you just made. It's a meter, not a bill: the header reflects what the work spent regardless of outcome. The dashboard's billing layer only counts billable outcomes against your plan (see Request Outcomes for which outcomes are billable).

Cost reference

Engine Base With unblocker
Single 1 2
Proxy 2 4
Browser 5 10 (when a defense was solved)

/api/auto/ is one request on your dashboard, with a credit cost that is the sum of the sub-calls it made internally (a single replay on a warm target can finish at 2; a cold solve on a hard site can spend much more). The X-FourA-Credits value on the auto response equals meta.credits in the body and tracks the full ladder cost.

Why both a header and a body field?

The header is convenient: you can read it before parsing the body, log it next to your request line, or sum it across many calls without JSON parsing. The body's meta.credits (Auto) or per-engine metadata (Single, Proxy, Browser dashboards) holds the same number, but readable inside the response envelope.

X-FourA-Limit

X-FourA-Limit appears only when one of your plan's limits refused the call. The platform's shared rate limits never set it, so the header is the fastest way to tell "my plan stopped this" from "FourA is busy" without parsing the body.

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

Two of the seven values come with a 403 rather than a 429: plan_limit_feature (the endpoint or the exitCountries parameter isn't in your plan) and plan_limit_premium (exitClass: premium isn't in your plan). Neither sets Retry-After, because waiting doesn't change the answer.

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)))

The seven values and the body fields that come with each are in Rate Limits.

X-FourA-Exit-Class

X-FourA-Exit-Class names the class of exit that delivered the body: premium when a premium exit did, standard when the standard pool did. It appears on a POST /api/proxy/ response that delivered a page whenever the request named an exitClass, where the body carries the same value, and on a Single or Browser response whenever the proxy you pinned was a premium exit, where the body has no field for it. A failed Proxy call served nothing, so it carries neither the header nor the field.

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

Traffic through a premium exit counts toward your premium traffic as well as your total bandwidth. It's measured on the network and includes premium attempts that didn't return your page, so a request answered with standard can still have used some premium traffic, on an attempt that failed before the standard pool answered. This header names the class that delivered, not whether premium traffic was used: the premium mark on an Activity row and the Usage & Limits page show what was counted. What exitClass does and when a premium exit is used: exitClass.

Cache Behavior

The API does not set Cache-Control or ETag on responses. Every call hits the backend. If you need caching, add it on your side.

Target Response Headers

The headers the target site returned are not on the FourA API response. They come back inside the JSON envelope as the headers field. For the Single and Proxy endpoints, this is an array of per-hop header objects (one entry per redirect step). For the Browser endpoint, it's a flat object of the final response headers.

{
  "status": 200,
  "headers": [
    { "Content-Type": "text/html; charset=utf-8", "Server": "..." }
  ],
  "data": "<!doctype html>...",
  "total_time": 0.42
}

If you need a specific target header, read it from the envelope's headers field, not from the HTTP response of the API call itself.

Last updated: September 30, 2026