Errors
Every error has the same JSON shape, an HTTP status and a stable code.
When a request fails, the API answers with an HTTP error status and this body:
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Not enough credits for this run."
}
}Use code in your program; it stays stable. message is meant for people and can change.
Error codes
| Status | Code | What happened | What to do |
|---|---|---|---|
| 400 | INVALID_INPUT | The body is not valid JSON, or it does not match the tool's input fields. The message names the field. | Fix the input. Check the fields in the tool reference. Nothing was charged. |
| 401 | UNAUTHORIZED | The x-api-key header is missing, or the key is unknown or revoked. | Send a valid key. See Authentication. |
| 402 | INSUFFICIENT_CREDITS | Your balance cannot cover the credits this run reserves. | Lower maxResults so the reservation fits your balance. See Credits. |
| 404 | NOT_FOUND | The tool ID does not exist, or the run does not exist in your organization. | Check the ID. GET /api/v1/tools lists all tool IDs. |
| 429 | RATE_LIMITED | This key used up its burst of 120 requests and its 60 per minute. | Wait the seconds in the Retry-After header (also retryAfterSeconds in the body), then retry. See Authentication. |
| 500 | INTERNAL_ERROR | Something broke on our side. If a run had already started, the body also contains runId. | Retry later. With a runId, fetch the partial results that were charged: GET /api/v1/runs/{runId}/results. |
| 503 | SERVICE_UNAVAILABLE | A part of the service is temporarily not available. | Retry later. |
| 503 | TOOL_UNAVAILABLE | Our latest automatic checks of this tool failed, so runs are paused. Nothing was reserved or charged. | Retry later. The status page shows when the tool works again. |
Runs that stop early
A run that stops early is not an HTTP error. A sync run that hits its deadline still answers 200: the results it collected are in the body, and run.error explains why it stopped, for example:
{ "status": "succeeded", "resultsCount": 7, "error": "Stopped at the 25 s deadline. Partial results were charged and saved." }If the target website blocks a run, run.error names the reason code. When nothing could be fetched at all, the run is failed (not an empty success) and nothing is charged:
{ "status": "failed", "resultsCount": 0, "error": "No results: 3 items could not be fetched (BLOCKED). The target site blocked our requests, so this is not an empty result. Nothing was charged." }When only some items were blocked, the run is succeeded, the results you got are charged, and run.error says how many items could not be fetched. See Runs for all statuses.