# Error codes

The error shape used everywhere, the codes the management API returns, and the ingest-specific responses.

Source: https://docs.webhooker.eu/reference/errors/

Errors carry a machine-readable code and a human-readable message:

```json
{
  "error": {
    "code": "validation_error",
    "message": "timeout_ms must be between 1 and 300000"
  }
}
```

Match on `code`. Messages are written for people and may be reworded.

## Management API

| Code | HTTP | Meaning | What to do |
| --- | --- | --- | --- |
| `unauthorized` | 401 | Missing or invalid credentials. | Check the bearer token. |
| `forbidden` | 403 | Authenticated, but not permitted — wrong role, or an API key on a session-only endpoint. | Use a session, or a member with the right role. |
| `plan_limit_exceeded` | 403 | A plan cap would be exceeded. | Remove something, or upgrade. |
| `not_found` | 404 | No such object in this workspace. | Check the id and the workspace. |
| `conflict` | 409 | The object already exists — for example a second connection between the same source and destination. | Reuse the existing one. |
| `validation_error` | 422 | The request body is malformed or out of range. | Read the message; it names the field. |
| `rate_limited` | 429 | Over the per-minute API budget. | Wait `Retry-After` seconds. |
| `unavailable` | 503 | A dependency the request needs is unavailable. | Retry later. |
| `internal_error` | 500 | Something broke on our side. | Retry; if it persists, tell us the time and the request. |

A `404` is also returned for an object that exists in a different workspace —
the API never reveals that someone else's id is valid.

## Ingest

| Code | HTTP | Meaning |
| --- | --- | --- |
| — | 200 | Accepted and stored. |
| `signature_invalid` | 401 | Inbound verification failed. The event is stored as `failed` and never delivered. |
| `quota_exceeded` | 402 | The workspace's monthly event quota is used up. |
| — | 404 | No such ingest token, or the source is in the trash. |
| — | 413 | Payload over 1 MiB. |
| — | 429 | Over the source's per-minute ingest budget. `Retry-After` says when to retry. |
| — | 500 | The event could not be stored. Safe to retry. |

Full details in [the ingest URL](/receive/ingest/).

## Delivery outcomes

Not errors from Webhooker, but the statuses your endpoint's responses produce:

| Status | Cause |
| --- | --- |
| `succeeded` | `2xx`. |
| `failed` | A `4xx` other than 408 and 429. Not retried. |
| `exhausted` | Every retry in the schedule failed. |
| `filtered` | A connection filter did not match. Nothing was sent. |

See [retries and replay](/deliver/retries-and-replay/).
