Reliability Contract
Three behaviours you can rely on when a request fails, when a batch runs against one domain, and when a domain is paused.
One Retry on a Failed Browser Request
When you force browser rendering (mode: "js", render_js: true or a forced tier) and the page comes back as a verification screen or times out, the error carries a hint that names the setting to change. The platform can apply that hint for you once: it retries the same job a single time through the standard route, with a fresh identity.
- The retry happens at most once per job and reuses the job id.
- You are billed only for a page that was delivered, at the price of the route that returned it. A failed retry costs nothing.
- It never moves a request to a more expensive route than the one you asked for.
Gradual rollout
Pacing
Batches are paced from what the platform observes, not from fixed per-site numbers. For each domain in your batch, the number of jobs in flight starts at your plan's limit. If challenges or timeouts rise among your own jobs on that domain, the window shrinks; when they clear, it grows back. It never drops below 1, and a healthy domain is never slowed.
To cap a batch yourself, set max_in_flight_per_domain. It can only lower the window, never raise it. The live value for each domain is returned in the batch status as dispatch_windows:
{
"dispatch_windows": [
{ "domain": "example.com", "window": 8, "limit": 25, "in_flight": 8, "throttled": true }
]
}Domain Pauses and Reopen Time
After repeated failures on a domain, automatic attempts on it pause for a short time. A pause caused only by requests where you forced the strategy, from a single account, does not pause the domain for other accounts. Every request rejected by a pause returns the same fields, on single scrapes (HTTP 422) and on each batch item (error_detail), and no credits are charged:
| Field | Meaning |
|---|---|
code | Always domain_circuit_open |
retryable | Whether the request is worth sending again |
retry_after_seconds | Seconds until the domain reopens |
reopen_at | The same moment as an ISO 8601 timestamp |
scope | transient for a short pause, degraded when the domain has paused repeatedly and is under review |
trip_count | How many times the domain has paused |
next_action | { "type": "wait", "retry_after": <seconds> } |
{
"message": "Domain 'example.com' is temporarily unavailable — too many consecutive scrape failures. Retry after 90s. No credits were charged.",
"code": "domain_circuit_open",
"retryable": true,
"retry_after_seconds": 90,
"reopen_at": "2026-11-10T12:31:30+00:00",
"scope": "transient",
"trip_count": 1,
"next_action": { "type": "wait", "retry_after": 90 }
}What to do
reopen_at and resubmit. A degraded scope is not a short wait; check back later. See Error Codes for the other error responses.