Errors
One error format everywhere, with stable codes you can program against.
Errors use RFC 9457 problem details, with
Content-Type: application/problem+json:
{
"type": "urn:typesearch:error:invalid_request",
"title": "Bad request",
"status": 400,
"detail": "max_results: Too big: expected number to be <=50",
"code": "invalid_request",
"request_id": "req_8fKq2mZr1xYt",
"errors": [{ "path": "max_results", "message": "Too big: expected number to be <=50" }]
}Use code in your code — it is stable. title, detail and message are for people and can change.
title and detail come in English; send Accept-Language: es to get them in Spanish. Every response,
successful or not, carries an X-Request-Id header: include it when you contact support.
Codes
| Status | code | What to do |
|---|---|---|
| 400 | invalid_json, invalid_request | Fix the request. errors lists each invalid field. Unknown fields are rejected too. |
| 400 | invalid_url, invalid_site, site_not_found, unsupported | Fix the URL or site. |
| 401 | missing_api_key, invalid_api_key, revoked_api_key | See Authentication. |
| 402 | budget_too_small | Raise max_tokens. |
| 402 | insufficient_credits | No credit left on your account. Top up in the dashboard. |
| 402 | spend_limit_reached | The key reached its monthly spend limit. Raise it in the dashboard. |
| 403 | robots_disallowed | The site’s robots.txt disallows it, or it couldn’t be read (we retry after 10 minutes). |
| 403 | source_unavailable | The source isn’t available right now. We don’t say why, and it may be temporary. Try another source. |
| 404 | job_not_found | The job does not exist for this key, or it expired (jobs last a day). |
| 404 | chart_not_found | No chart with that id for your organization: it was deleted or it expired. See Charts. |
| 422 | insufficient_data | A chart from a query found no articles about the topic in the period (with index or questions: not enough data for the chart). Not billed. Try more days or a broader query. |
| 429 | rate_limited | Retry after Retry-After seconds. |
| 429 | quota_exceeded | Daily token quota used. It resets at 00:00 UTC. |
| 499 | cancelled | The search stopped because the client closed the connection or aborted the stream. Nothing to fix; send it again if you still need it. |
| 500 | internal_error | Something failed on our side. Retry; if it keeps happening, contact support with the request_id. |
| 502 | site_unreachable, invalid_redirect, bot_protection | The site failed. Try again later or another site. |
| 503 | upstream_unavailable, browser_unavailable, browser_busy | Temporary. Retry with backoff; browser_busy says when in Retry-After. |
| 503 | shutting_down | The server is restarting. Retry after Retry-After seconds. |
| 503 | spend_cap_reached | The service reached its daily spend cap. Retry-After says when it resets (00:00 UTC). |
| 503 | job_interrupted | In a job’s error (GET /v1/jobs/{id}): the server restarted before the job finished. Request it again. |
| 504 | timeout, site_timeout | Temporary. Retry, or use a lighter mode. |
In POST /v1/contents each URL has its own status: a page from a source that isn’t
available comes back with source_unavailable in results[].error.code, and the rest of the request
succeeds.
Retries
The SDKs retry connection errors, timeouts, 429 rate_limited and 5xx twice, with exponential backoff
and jitter, honouring Retry-After. They never retry quota_exceeded. Calling the API directly, do the
same.
Warnings are not errors
Things that don’t stop a request — a domain that is not in the index, a budget reached — come back in
the response’s warnings array, each with a code and a message (in English, or in Spanish with
Accept-Language: es).