Send your key on every request: Authorization: Bearer ak_YOUR_KEY.
Every successful metered response carries X-Credits-Remaining —
your live balance after that request.
| Code | Meaning | What to do |
|---|---|---|
| 400 | Invalid input — e.g. a non-public target URL (private
ranges, localhost, cloud metadata are always refused) or a
force_tier/max_tier your key cannot use. No
credit is charged for a 400. | Fix the request. |
| 401 | invalid or missing API key. |
Check the header; rotate your key from the dashboard if leaked. |
| 422 | Request body failed validation (missing/mistyped field). | Fix the field named in detail. |
| 429 | Three distinct app-level cases, told apart by
detail:
rate limit exceeded (per-key rps cap; includes
Retry-After: 1), insufficient credits (balance
too low; includes X-Credits-Remaining), or
search credit cap reached (your plan's monthly search
sub-cap; general credits may still remain). |
Back off, or upgrade / wait for the monthly reset. |
| 429 (no JSON) | A fourth case, from the edge: the nginx
per-IP burst limiter can also return 429 ahead of the app, with an HTML
body — no JSON detail, no Retry-After. Any 429
response that fails to parse as JSON is this case, not one of the three
above. |
Treat any 429 without a JSON body as "back off briefly" and retry. |
| 503 | A dependency (key store, search provider) is unavailable. Nothing was charged unless a body was served. | Retry with backoff. |
No 402: this API does not use HTTP 402 — running out of
credits is a 429 with detail: "insufficient credits", so one
retry-after-backoff code path covers both throttling and balance exhaustion.
/v1/fetch and /v1/extract return HTTP 200 with a
structured envelope even when the target could not be retrieved — check
blocked and error in the body. You decide
raise-vs-retry; we report honestly what happened per attempt.
render: true) run a real browser and take
seconds. Concurrency is bounded; sustained heavy render load queues.