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

# Errors worth branching on

> Per-endpoint failure templates matching the { error, meta } envelope — what actually fires, what to retry, what to surface to the operator.

## Errors worth branching on

These five failures cover the message send (POST /api/v1/telegram/messages), hammered by every auto-response in the chat flow. Each block below is a full `{ error, meta }` envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the [error handling guide](/guides/error-handling-examples).

### 401 — Unauthorized

```json theme={null}
  {
    "error": {
      "code": "UNAUTHORIZED",
      "message": "The API key is invalid, expired, or lacks the required scope.",
      "status": 401
    },
    "meta": {
      "request_id": "req_telegrama1",
      "timestamp": "2026-09-03T12:00:00Z"
    }
  }
```

A `401` on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.

### 403 — Forbidden

```json theme={null}
  {
    "error": {
      "code": "FORBIDDEN",
      "message": "The key is valid but does not have the scope this operation requires.",
      "status": 403
    },
    "meta": {
      "request_id": "req_telegrama1f",
      "timestamp": "2026-09-03T12:00:00Z"
    }
  }
```

A `403` means the key authenticated but the operation is gated by scope — check the key's scopes on the developer page; a `403` is never a data-not-found shape.

### 422 — Schema

```json theme={null}
  {
    "error": {
      "code": "VALIDATION_ERROR",
      "message": "The request failed input validation.",
      "status": 422,
      "details": { "field": "chat_id", "value": "tg-0192", "expected": "a numeric chat id or @channel slug from the Telegram client" }
    },
    "meta": {
      "request_id": "req_telegramb2",
      "timestamp": "2026-09-03T12:00:00Z"
    }
  }
```

A `422` means the payload did not match the request schema — branch on `error.details.field` and resend with the numeric chat id or the tenant-registered channel slug instead of blind-retrying the same body.

### 429 — Rate

```json theme={null}
  {
    "error": {
      "code": "RATE_LIMITED",
      "message": "Too many requests in the current window.",
      "status": 429,
      "details": { "retry_after": 12 }
    },
    "meta": {
      "request_id": "req_telegramc3",
      "timestamp": "2026-09-03T12:00:00Z",
      "docs_url": "https://docs.orbit.devotel.io/errors/RATE_LIMITED"
    }
  }
```

The `Retry-After` header and `error.details.retry_after` are both set on every `429` — resend the SAME request after the lower of the two.

### 402 — Feature gate

```json theme={null}
  {
    "error": {
      "code": "TELEGRAM_BOT_TOKEN_REVOKED",
      "message": "The Telegram bot token for this channel has been revoked upstream.",
      "status": 402,
      "details": { "bot_id": "bot_0192", "revoked_at": "2026-09-03T11:59:00Z" }
    },
    "meta": {
      "request_id": "req_telegramd4",
      "timestamp": "2026-09-03T12:00:00Z"
    }
  }
```

Surface token renewal — resend only works after the re-auth webhook, not on replay.

### 60-second retry matrix

| Class                                               | Meaning                               | Branch response                                                                                          |
| --------------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **401 `UNAUTHORIZED`**                              | the bearer key itself fails           | **Surface.** Rotate the key or re-mint the scoped token; do not retry the same request.                  |
| **403 `FORBIDDEN`**                                 | the key lacks this operation's scope  | **Surface.** Fix the key's scope set; a retry with the same key never heals it.                          |
| **422 `VALIDATION_ERROR`**                          | the payload does not match the schema | **Fix, then resend intentionally.** Branch on `error.details.field`; a blind retry repeats the same 422. |
| **429 `RATE_LIMITED`**                              | the window quota is exhausted         | **Retry after `error.details.retry_after`** (or the `Retry-After` header) with the same request body.    |
| **`TELEGRAM_BOT_TOKEN_REVOKED`** (402 feature gate) | Surface token renewal                 | **Branch on `error.code`.** Resend only works after the re-auth webhook, not on replay.                  |
