> ## Documentation index
> Fetch the complete documentation index at: https://rankfield.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Read Rankfield API errors: the HTTP status codes, the JSON error body of each endpoint family, and which errors to retry.

## Status codes

| Status | Meaning | What to do |
|---|---|---|
| `200` | Success. | Read the JSON. |
| `202` | Accepted: a job started, or a page is still being fetched. | Read the result from `resultsUrl` or `statusUrl`. |
| `400` | A parameter is missing or invalid. | Fix the request; the message says what is wrong. |
| `401` | No valid API key. | See [Authentication](/docs/get-started/authentication). |
| `403` | Scrape, Bot View, Brand and Site Map: the site's robots.txt disallows Rankfield-User, or the site is excluded. | Don't retry. |
| `404` | Not found: the job id is unknown or expired. A domain that isn't in our link graph yet is not an error: it answers `200` with `"inGraph": false`. | Don't retry. |
| `409` | Conflict: a download of a job that is not finished, or an `Idempotency-Key` reused with a different body. | Wait for the job, or use a new key. |
| `410` | Gone: a page job's results expired (they are kept for 24 hours). | Start a new job. |
| `413` | Too many URLs in one job. | Split the list. |
| `415` | Scrape, Bot View, Brand and Site Map: the page is not HTML or text. | Don't retry. |
| `422` | The website answered with an error or timed out, or its address is not public. | Retry only when `error.retryable` is `true`. |
| `429` | The server is busy, or (Scrape, Bot View, Brand and Site Map) the shared batch queue is full when you start a job. | Wait for the `Retry-After` header, then retry. |
| `500` | Scrape, Bot View, Brand and Site Map: our bug. | Retry. |
| `502` | A lookup behind the API failed, or the website could not be reached. | Retry later. |
| `503` | The service is busy or paused. | Wait for `Retry-After`, then retry. |
| `504` | The website did not answer within `timeout`, or the call waited its turn for that website (`sitePace`). | Retry, or allow a longer `timeout`. |

A `404` or `500` from a website you asked us to fetch is not an error from us: the page's own status is in the answer's `status` field.

## Error bodies

Every error is JSON. The shape depends on the endpoint family:

| Endpoints | Body |
|---|---|
| Site Strength, Referring Domains, exports, Link Extraction | `{"error": {"message": "..."}}`. A page that failed adds `code` (such as `SOURCE_HTTP_404`) and `retryable`. |
| Scrape, Bot View, Brand and Site Map | `{"error": {"code": "...", "message": "...", "details": {...}}}`. `code` is stable, such as `robots_disallowed` or `busy`. |
| Suggest (Bing, DuckDuckGo, Yahoo) | `{"error": "..."}`: the message is a string. |

To handle all of them in one place, read the message like this:

```javascript
const body = await response.json();
const message = typeof body.error === "string" ? body.error : body.error?.message;
```

## Retries

- Retry `429`, `503` and `504` after the number of seconds in `Retry-After` (or 2 seconds when it is missing), and back off if it happens again.
- Retry `502` and a `422` with `"retryable": true` a few times at most.
- Never retry `400`, `401`, `403`, `404`, `413` or `415` unchanged.
- Repeat a job submission with the same `Idempotency-Key` and body: you get the same job back, not a second one.

Every answer carries an `x-request-id` header. Quote it when you report a problem.
