# Errors

Every failure has the same shape and a stable `code`. Branch on the code - the message is written for people and may be reworded.

```
{ "error": { "code": "invalid_key", "message": "That API key does not exist." } }
```

Some errors carry extra fields alongside those two: `parameter` for the one that was wrong, `retry_after` for how long to wait, `limit` and `used` for a spent quota.

## Every code

| Status | Code | When |
| --- | --- | --- |
| 400 | `missing_query` | `query` was empty or absent. |
| 400 | `unknown_format` | `format` is not one of the six. |
| 400 | `unknown_column` | `columns` names a field that does not exist. |
| 400 | `format_not_available` | A flat format was asked for where rows are not what is being returned. |
| 400 | `per_page_too_large` | `per_page` above your plan's row limit. The limit is in the error. |
| 400 | `invalid_json` | The POST body is not valid JSON. |
| 401 | `missing_key` | No `Authorization: Bearer` header. |
| 401 | `invalid_key` | The key does not name an account. |
| 403 | `plan_required` | The account has no paid plan. |
| 404 | `unknown_endpoint` | No such path. The known ones are listed in the error. |
| 405 | `method_not_allowed` | Read-only API. Use GET, or POST a JSON body. |
| 429 | `too_many_requests` | Arriving faster than ten requests per minute (API and MCP together). |
| 429 | `quota_exceeded` | The day's search allowance is spent. |
| 429 | `snippet_quota_exceeded` | The day's snippet allowance is spent. Searching without snippets still works. |

## What to do about each

- **400** - your request is wrong and repeating it will not help. The `parameter` field says which one.
- **401, 403** - your key or your plan. Not worth retrying until something changes.
- **429 `too_many_requests`** - sleep `retry_after` seconds and repeat. Nothing was consumed.
- **429 `quota_exceeded`** - the allowance returns at the next UTC midnight; `retry_after` says how far off that is. Retrying sooner will not help.
- **5xx** - ours. Retry with a widening delay.

## Errors and formats

Errors come back as JSON, or as XML when `format=xml` was asked for. The flat formats have no shape for an error, so a failed request that asked for `csv` gets JSON - which means a client reading CSV should check the status code rather than assume every 200-shaped body is rows.

## Reading the codes without reading this page

`GET /` lists every code above, with its meaning, as JSON. It needs no key, so a client can be built against the whole set without anyone opening a browser.

```
curl https://api.publicwww.com/
```

Source: https://publicwww.com/docs/api/errors/
