# Errors

Every error is JSON with one required field:

```json
{ "error": "Send a valid API key as `Authorization: Bearer <key>`." }
```

`error` is a sentence meant for a person. It never repeats a value you sent, so it is safe to log. Some errors add fields:

| Field | When | Meaning |
| --- | --- | --- |
| `fields` | `400` | The request fields to fix, e.g. `["domain"]` or `["seedPrompts"]`. |
| `retryAfterSeconds` | `429` | How long to wait, when that is knowable. The `Retry-After` header says the same. Absent for the `concurrent` plan limit. |
| `limit` | `402`, `429` on a start | Which [Agent plan](/agent-plan/) limit refused it: `plan`, `projects`, `reportsPerMonth`, `perDay` or `concurrent`. |
| `status` | `409` | The report's current status, when that is the reason. |

Match on the status code and these fields, not on the wording of `error`, which may change.

## Status codes

| Code | Meaning | What to do |
| --- | --- | --- |
| `200` | OK. On a start: an earlier start with the same idempotency key, returned again (`reused: true`). | — |
| `202` | Report started. | Poll its `statusUrl`. |
| `400` | Invalid request: a missing or malformed field, a seed question that names the product, an engine outside the plan, or provider keys sent with `funding: "credits"`. | Fix the `fields` and resend. |
| `401` | Missing, malformed, unknown or revoked key, or the key's account no longer exists. | Check the key. See [Authentication](/authentication/). |
| `402` | No funding: no agency credit left, or no active Agent plan for a start on your own keys. | Buy credits or start the plan in your account. |
| `403` | Not allowed: unverified email, own-key reports not enabled, or a kit for an unpaid report. | Read `error`. |
| `404` | No such ranking or report — or a report in another account, which answers the same. | Check the slug and the key. |
| `409` | Not yet possible: the kit before the report is `COMPLETE`, or a retried credit start whose credit is already back in your balance (the report could not be queued, or it ran, failed and was refunded). | Wait for the kit; for a start, send a new start with a new idempotency key. |
| `413` | Body larger than 32 KB. | Send less. |
| `429` | Too many requests (with `Retry-After`), or an Agent plan limit (with `limit`). | See [the two kinds of 429](/rate-limits/#when-you-hit-one). |
| `503` | A dependency is briefly unavailable. On a report start the outcome is **unknown**: see below. | Retry after `Retry-After` seconds. On a start, retry with the **same** idempotency key. |

## Refused starts cost nothing

A `4xx` refusal of `POST /v1/reports` — validation, funding, or a limit — happens before anything is spent or queued.

## A 503 on a start is an unknown outcome

A `503` (or a timeout, or a dropped connection) on `POST /v1/reports` does **not** prove that nothing happened: the start may have gone through and the report may still be running. Treat it as unknown:

1. Retry the start with the **same** `Idempotency-Key` and the same body. If the first attempt went through, you get it back (`200`, `reused: true`) and nothing new is spent.
2. Or check `GET /v1/reports` for the report before deciding.

**Never retry an unknown outcome with a new idempotency key**: that can start, and pay for, a second report. See [idempotency](/rate-limits/#idempotency-retry-a-start-safely).

## When a running report fails

If a credit-funded report starts and then fails, its credit normally returns to your balance automatically. Automatic returns are limited to 3 per account in any 30 days for reports that started; past that, the failed report's credit is held for review and support decides. Reports that never started cost nothing and do not count toward the limit.