Error Codes
When a request fails outright, the API returns a consistent error object with a machine-readable code and human-readable message. Note the distinction from a low-quality result: a page that was fetched and extracted but scored under 70 still returns HTTP 200 with success: false and no error field — that is not one of the codes below.
Error Format
All errors follow the same structure:
Error Response
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of what went wrong"
}
}Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| INVALID_REQUEST | 400 | The request body is missing required fields, has the wrong types, or exceeds a size limit (extract over 4,000 characters, schema over 10 KB, html over 5 MB). |
| INVALID_URL | 400 | The URL points at a private or internal address, including when reached through a redirect. Every redirect hop is checked. |
| UNAUTHORIZED | 401 | Missing or invalid API key. Sample URLs work without a key; any other URL needs one from /dashboard/keys. |
| FETCH_FAILED | 422 | The target URL could not be fetched: an HTTP error, a timeout, a response over 10 MB, or too many redirects. |
| RENDER_REQUIRED | 422 | The page is a JavaScript-only shell with no server-rendered content. Contrie does not run a browser in the hosted API. Render the page yourself and send the HTML to /api/v1/extract, or self-host apps/api's /v1/browser endpoint. |
| RATE_LIMITED | 429 | More than 10 requests in the current sliding one-minute window for this key. Check the Retry-After header (seconds) before retrying. |
| PAGE_LIMIT_REACHED | 429 | Your account has used its monthly credit quota (1,000 credits on the free plan). Resets on the 1st of the calendar month. |
| SERVICE_UNAVAILABLE | 503 | The authentication service is temporarily unreachable. Retry shortly. |
| MODELS_UNAVAILABLE | 503 | Every model in the fleet was rate-limited by its provider at the same time. Retry in a few minutes. |
| EXTRACTION_FAILED | 500 | An unexpected error in the extraction pipeline. Retry once; if it persists, the page or request is likely the cause. |
Handling Errors
- Always check the
successfield before accessingdata— a 200 response can still carrysuccess: falsewhen quality was too low - Use the
error.codefield for programmatic error handling, not the HTTP status alone - Use the
error.messagefield to display user-friendly error messages - For
RATE_LIMITED, back off for the number of seconds inRetry-After - For
MODELS_UNAVAILABLE, wait a few minutes before retrying — it is not the same as a per-key rate limit - For
RENDER_REQUIRED, don't retry as-is — render the page and call /api/v1/extract instead - For
EXTRACTION_FAILED, retry once — then report the issue