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

# REST API errors

> Every failure is one envelope with a stable type, so a client needs exactly one branch for things going wrong.

Every non-2xx response from the REST API is the same shape, whether the problem was caught at the door or came back from the backend:

```json Error envelope theme={null}
{
  "error": {
    "type": "invalid_request",
    "message": "unknown area \"vibes\". Valid areas are: visibility, prompt, page, source, competitor, topic, platform, bot. Use \"visibility\" for the overall picture, \"prompt\"/\"page\" for what to fix, \"competitor\"/\"platform\"/\"source\" for where you stand",
    "status": 400
  }
}
```

There is no second shape and no plain-text response — a `404` for a URL that does not exist at all is still this envelope. One failure branch is enough.

## The fields

| Field     | Use it for                                                                                                      |
| --------- | --------------------------------------------------------------------------------------------------------------- |
| `type`    | Branching. Stable and machine-readable; a value is never renamed.                                               |
| `message` | Showing a human, or handing to an agent to correct itself. Wording changes without notice — never switch on it. |
| `status`  | The HTTP status, repeated in the body so a logged payload is self-describing.                                   |

## Types

| `type`            | Status       | Meaning                                                                                                     | Retry?                |
| ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------- | --------------------- |
| `invalid_request` | `400`, `413` | The request was wrong: a missing parameter, an unknown enum value, an unknown body field, a body too large. | No — fix the request. |
| `unauthorized`    | `401`        | Missing, malformed, revoked or expired key. See [Authentication](/api/authentication).                      | No.                   |
| `forbidden`       | `403`        | The key is valid but lacks the scope this endpoint needs. `GET /v1/account` lists the key's scopes.         | No.                   |
| `not_found`       | `404`        | No such prompt, page, automation, session — or no such endpoint.                                            | No.                   |
| `conflict`        | `409`        | The change collides with the current state.                                                                 | No, not unchanged.    |
| `rate_limited`    | `429`        | Too many requests for this key.                                                                             | Yes, after a backoff. |
| `server_error`    | `5xx`        | Something failed on our side.                                                                               | Yes.                  |

## Validation errors name the valid values

An error from this API is written to be actionable, not merely correct. Where an enum is wrong, the message lists the accepted values; where a required field is missing, it says what a real value looks like.

```json 400 — bad trigger theme={null}
{
  "error": {
    "type": "invalid_request",
    "message": "trigger is required and must be one of: manual, once, daily, weekly. \"manual\" and \"once\" never fire on a clock; \"daily\" and \"weekly\" fire at run_at_minute",
    "status": 400
  }
}
```

That is deliberate: the caller is often an agent that can fix its own request in one step if it is told how, and a human reading a `400` in a terminal wants the same sentence.

## What is safe to retry

`429` and `5xx` are the retryable failures. Everything in the `4xx` range below `429` will fail identically until the request changes.

Retry with exponential backoff and jitter. A tight retry loop against a `429` extends the window you are limited for.

<Warning>
  Three endpoints spend credits: `POST /v1/prompts`, `POST /v1/automations/{id}/runs` and `POST /v1/ask`. Send an `Idempotency-Key` header on an automation run so a retry after a timeout cannot start — or bill — a second run.
</Warning>

A `5xx` never echoes an internal message. The body says `temporary server error, retry`, because an internal fault is not something the caller can act on, and the internals of a failure are not theirs to read. The `X-Request-Id` on the response is what identifies it — quote that in a support request.

## Timeouts are not errors

`POST /v1/ask` and `POST /v1/automations/{id}/runs` start work that can outlive the request. They answer `200` with `status: "running"` and a `session_id`; that is the success case, not a failure.

Wait `poll_after_ms`, then poll `GET /v1/sessions/{id}` until `status` is `complete` or `failed`. Re-sending the original `POST` instead starts a second billed run.

<Note>
  Still stuck? [Troubleshooting](/reference/troubleshooting) covers empty results, unexpected zeros and keys that stopped working.
</Note>
