# Chesly API errors

> Every code the Chesly API and the chesly CLI answer with, what it means and what to do. Start a trial and make keys at https://web.chesly.app/api. Agent setup: https://agents.chesly.app/agents.md

## Problem details

Every error from the API is a problem details object ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)), sent as `application/problem+json` with the HTTP status:

```json
{
  "type": "https://agents.chesly.app/docs/errors#rate_limited",
  "title": "Too many requests.",
  "status": 429,
  "detail": "This API key made more than 600 requests in one minute. Retry in 4 s.",
  "code": "rate_limited",
  "request_id": "571d003e-ad60-4a08-858a-b7b5353f39db",
  "retry_after": 4
}
```

- `type` links to the code's section on this page.
- `title` is fixed for each of the API's codes, and `detail` explains this occurrence.
- `code` never changes: branch on it, never on `title` or `detail`.
- `request_id` is the request's `X-Request-ID`. Include it when you write to us.
- `retry_after`, in seconds, comes with most 429 and 503 answers, along with a `Retry-After` header.
- A 400 `invalid_request` also lists each problem in `errors`, with a JSON Pointer to it.

The MCP server refuses a tool call with the same codes, as a tool error whose text starts with the code: `chat_not_found: …`. The CLI prints the API's problem as it came, and exits with the code each section names. Its own errors come in the same shape; they're under [CLI errors](https://agents.chesly.app/docs/errors#cli-errors).

## 400 Bad request

### idempotency_key_invalid

**400** · The Idempotency-Key header is not valid. · CLI exit code 1

Use 1 to 255 characters from `A-Za-z0-9._:-`, such as a UUID. The quoted form `"…"` works too.

### invalid_cursor

**400** · The cursor is not valid. · CLI exit code 1

Pass `next_cursor` from the page before, exactly as it came, with the same filters. A cursor of `GET /v1/messages?since=` expires 15 minutes after its first page: start again without one.

### invalid_reply_to

**400** · reply_to must be a message in this chat. · CLI exit code 1

`reply_to` must be the ID of a message in the same chat. Leave it out to send a plain message.

### invalid_request

**400** · The request is not valid. · CLI exit code 2

A parameter or the body is missing, unknown or out of range. `detail` names the first problem, and `errors` lists each one with a JSON Pointer to it. Sending the same request again fails the same way.

### invalid_webhook_url

**400** · This webhook URL can't be used. · CLI exit code 1

A webhook URL must be a public `https://` address of at most 2,048 characters, with no user name or password, whose host doesn't resolve to a private, loopback or link-local address.

### media_too_large

**400** · The media is too large. · CLI exit code 1

The API serves and takes files of up to 50 MB (50,000,000 bytes), one per message, and the CLI refuses a bigger one before uploading it. Open a bigger file in the Chesly app.

### not_a_voice_note

**400** · This message is not a voice note. · CLI exit code 1

Only voice notes can be transcribed, and a voice note's `type` is `audio`.

### text_too_long

**400** · The text is too long for this network. · CLI exit code 1

Each network takes text up to its own length, in UTF-16 code units: Instagram 1,000, Discord 2,000, Telegram 4,096, email 100,000 and every other network 10,000. Split the text into several messages.

### unsupported_chat

**400** · Chesly can't send to this chat. · CLI exit code 1

This chat can't take a message from the API, and `detail` says why. Answer it in the Chesly app instead.

### webhook_limit_reached

**400** · This account has the most webhooks allowed. · CLI exit code 1

Your plan's webhooks are used: 25 on Personal, 100 on Pro. Delete one you don't use, send several event types to one URL, or switch to Pro.

## 401 Unauthorized

### invalid_api_key

**401** · The API key is missing or not valid. · CLI exit code 3

Send `Authorization: Bearer ck_live_…` with a key that is still active. A revoked key fails from its next request: make a new one with `chesly login` or in the dashboard.

## 402 Payment required

### api_plan_required

**402** · An API plan is required. · CLI exit code 6

Calls need an API plan. Start the 7-day trial at [web.chesly.app/api](https://web.chesly.app/api); `GET /v1/me` answers without one. The CLI exits with 6.

### transcription_limit_reached

**402** · This period's transcription minutes are used up. · CLI exit code 6

This month's transcription minutes are used: 600 on Personal, 3,000 on Pro. Transcripts work again when the next month starts, and everything else keeps working. Switch to Pro at [web.chesly.app/api](https://web.chesly.app/api) for more.

## 403 Forbidden

### forbidden

**403** · This request is not allowed. · CLI exit code 1

Something other than the key's scope refused the request, and the same request will be refused again: an API key turning back on a webhook that a leaked key's revoke turned off, say, which only the dashboard can do. Write to us with the `request_id` if you think it should work.

### insufficient_scope

**403** · This API key does not allow this request. · CLI exit code 1

A read-only key can only make GET requests. Sending, marking chats read, transcribing and changing webhooks need a full-access key.

### signing_key_missing

**403** · The account signing key is missing. · CLI exit code 1

Your account's signing key has to be restored before Chesly can read your chats. Open the Chesly app and sign in again, then retry.

## 404 Not found

### account_not_found

**404** · Account not found. · CLI exit code 4

None of your connected accounts has this ID. `GET /v1/accounts` lists them.

### chat_not_found

**404** · Chat not found. · CLI exit code 4

None of your chats has this ID: chat IDs belong to one user, so take one from `GET /v1/chats`. The CLI raises it too, when a chat name matches nothing; `chesly chats` lists the names.

### key_not_found

**404** · API key not found. · CLI exit code 4

None of your API keys has this ID. `GET /v1/keys` lists them.

### media_not_found

**404** · Media not found. · CLI exit code 4

No media has this ID. Use a message's `media.id` as it came.

### message_not_found

**404** · Message not found. · CLI exit code 4

No message of yours has this ID. Use message IDs as the API gave them, in answers and events.

### not_found

**404** · Not found. · CLI exit code 4

No endpoint matches this method and path. IDs go in the path, filters in the query.

### webhook_not_found

**404** · Webhook not found. · CLI exit code 4

None of your webhooks has this ID. `GET /v1/webhooks` lists them.

## 408 Request timeout

### upload_timeout

**408** · The upload took too long to arrive. · CLI exit code 5

The file didn't arrive in time: an upload has 60 seconds, and must keep up 50 KB a second once its first 10 are over. Your next upload can start in 60 seconds; send it again over a faster connection.

## 409 Conflict

### account_reconnect_required

**409** · This account needs to be reconnected. · CLI exit code 1

This account was disconnected on its network. Reconnect it in the Chesly app, then retry.

### already_subscribed

**409** · You already have an API plan. · CLI exit code 1

You already have an API plan. Manage it at [web.chesly.app/api](https://web.chesly.app/api).

### idempotency_in_progress

**409** · A request with this Idempotency-Key is still running. · CLI exit code 5

The first request with this `Idempotency-Key` hasn't finished. Wait for `Retry-After` (1 second), then send the same request with the same key: you get its answer once it's done.

### message_request

**409** · This chat is a message request. · CLI exit code 1

The API reads message requests but never answers them, because a reply would accept the request on the network. Accept it in the network's own app first.

### plan_change_in_progress

**409** · A change to your plan is already under way. · CLI exit code 1

Another request is changing your plan right now, such as a second click on Keep plan in the dashboard. Wait a second and look again: the change is usually done.

### terms_changed

**409** · The API Terms changed. · CLI exit code 1

The API Terms changed since you opened them. Read and accept the current version, then try again.

## 410 Gone

### events_expired

**410** · These events are no longer kept. · CLI exit code 1

Events are kept for 7 days on Personal and 30 on Pro, and this `after` or `Last-Event-ID` is older. Start again without one, and catch up on what you missed with `GET /v1/catch_up`. `chesly watch` does this by itself, with an `events_expired` warning.

### media_expired

**410** · The media has expired. · CLI exit code 1

The file is no longer stored, and asking again won't bring it back.

## 413 Payload too large

### payload_too_large

**413** · The request body is too large. · CLI exit code 1

The request body is over its limit: 10 MB for a request, 1 MB for an MCP message and 4 KB for `chesly login`'s calls. Send a file to `POST /v1/media` instead, up to 50 MB (50,000,000 bytes).

## 422 Unprocessable content

### idempotency_key_reused

**422** · This Idempotency-Key was used for a different request. · CLI exit code 1

This `Idempotency-Key` went with another method, path or body in the last 24 hours. Use a new key for a new request; reuse a key only to retry the same request.

### transcription_failed

**422** · This voice message could not be transcribed. · CLI exit code 1

This voice note's audio can't be transcribed: it may be damaged, or in a format the transcription doesn't read. Asking again gets the same answer.

## 429 Too many requests

### rate_limited

**429** · Too many requests. · CLI exit code 5

A key, all of your keys together, an account or the API as a whole went over a limit: the [limits](https://agents.chesly.app/docs#limits) list them. Wait `Retry-After` seconds (also in `retry_after`), then retry. `GET /v1/me` shows your limits.

### send_limit_reached

**429** · This account's send limit is reached. · CLI exit code 5

This connected account reached its send limit: 60 an hour and 250 a day on WhatsApp, 30 an hour and 150 a day on every other network. Wait `Retry-After` seconds. `GET /v1/me` shows where each account stands.

### too_many_streams

**429** · Too many open event streams. · CLI exit code 5

You can keep 10 event streams open at once on Personal and 25 on Pro. Close one, or poll `GET /v1/events` instead.

## 500 Internal server error

### internal_error

**500** · Something went wrong on our side. · CLI exit code 1

Something failed on Chesly's side, logged under the `request_id`. Retry later, and if it keeps happening, write to us with the `request_id`. The CLI raises it too, for a failure it didn't expect.

## 502 Bad gateway

### email_send_failed

**502** · The email provider refused the message. · CLI exit code 5

Your email provider refused the message. Check the account in the Chesly app, then retry.

## 503 Service unavailable

### api_paused

**503** · The Chesly API is paused. · CLI exit code 5

Chesly has paused the API for a moment. Retry after `retry_after` seconds.

### feed_unavailable

**503** · The feed is temporarily unavailable. · CLI exit code 5

The since feed can't page right now. Retry in a moment, or ask for a stretch of time that fits one page.

### media_unavailable

**503** · The media is temporarily unavailable. · CLI exit code 5

The file couldn't be fetched just now. Retry after `retry_after` seconds when it's there, or in a moment.

### network_unavailable

**503** · This network is temporarily unavailable. · CLI exit code 5

Chesly has paused sending and marking read on this network to protect your accounts. Reads still work. Retry later, or do it in the network's own app.

### plan_unavailable

**503** · Your API plan can't be checked just now. · CLI exit code 5

Chesly couldn't read your plan just now, so it makes nothing your plan limits: a new key or a new webhook. Everything else goes on. Retry after `retry_after` seconds, about 5; `chesly login` keeps polling by itself.

### search_unavailable

**503** · Search is temporarily unavailable. · CLI exit code 5

Search can't answer right now. Retry in a moment; reading chats and catching up still work.

### transcription_unavailable

**503** · Transcription is temporarily unavailable. · CLI exit code 5

Transcription can't answer right now. Retry in a moment.

### upstream_unavailable

**503** · Your messages are temporarily unavailable. · CLI exit code 5

Chesly couldn't reach your messages just now. Retry after `retry_after` seconds, about 5.

## CLI errors

The CLI raises these itself, in the same shape, with a `type` on this page and a `code` that never changes. Its problems carry their message as `title`, so branch on `code`; the titles below describe each code. In JSON mode it prints them to standard error as one line, and it exits with one of these codes:

| Exit code | Meaning |
|---|---|
| `0` | Done |
| `1` | An error |
| `2` | A usage error: a missing argument or an unknown option, or a request the API refused as `invalid_request` (400) |
| `3` | Not signed in: no key, a malformed one, or one the API refused (401) |
| `4` | Not found (404), or a chat name that fits more than one chat |
| `5` | Not final, come back to it: a limit (429), the API or a gateway briefly away (502, 503 or 504), a first attempt still running (409 `idempotency_in_progress`), or a send the network didn't confirm (`delivery_unconfirmed`: check the chat before you send it again). `retry_after`, when there is one, says when. |
| `6` | Payment required (402): no API plan, or one of its limits reached |

When something in front of the API answers without problem details, such as the gateway during a Chesly deploy, the CLI names the error after the HTTP status: `http_400`, `http_404`, `http_413`, `http_429`, `http_500`, `http_502`, `http_503` or `http_504`, and `http_error` for any other status.

### access_denied

**CLI** · The sign-in was denied.

Someone chose Deny on the approval page, so nothing was stored. Run `chesly login` again.

### ambiguous_chat

**CLI** · The chat name matches more than one chat.

The error lists the chats that match as `candidates`. Use one of their chat IDs instead of the name.

### credentials_file_error

**CLI** · The credentials file couldn't be read or written.

`chesly logout` couldn't remove `~/.config/chesly/credentials.json`. Check the file's permissions, or delete it yourself.

### delivery_failed

**CLI** · The network did not take the message.

`chesly send --wait` saw the network refuse the message for certain (`delivery.error.certain` is true), and the error says why. Fix what it names before you send again. The CLI exits with 1.

### delivery_unconfirmed

**CLI** · The network didn't confirm the message, so it may have been delivered.

`chesly send --wait` saw the send fail without the network confirming it (`certain: false`: a `timeout`, or an `unknown` error), so the message may have been delivered. Check the chat before you send it again. The CLI exits with 5.

### expired_token

**CLI** · The sign-in code expired.

A sign-in link lasts 10 minutes. Run `chesly login` again and approve the new link.

### file_unreadable

**CLI** · The file can't be read.

The CLI can't read the file `--file` names. Check its path and its permissions.

### http_400

**CLI** · HTTP 400 · Bad Request, without details.

Something in front of the API refused the request without details. Check `CHESLY_API_URL` if you set it, then retry.

### http_404

**CLI** · HTTP 404 · Not Found, without details.

The request reached something other than the API, which answered 404 without details. Check `CHESLY_API_URL` if you set it.

### http_413

**CLI** · HTTP 413 · Payload Too Large, without details.

Something in front of the API found the request too large. A file can be up to 50 MB (50,000,000 bytes).

### http_429

**CLI** · HTTP 429 · Too Many Requests, without details.

Too many requests, answered without details, as the sign-in's own limit does. Wait a minute, then retry.

### http_500

**CLI** · HTTP 500 · Internal Server Error, without details.

A server error without details. Retry in a moment, and if it keeps happening, write to us.

### http_502

**CLI** · HTTP 502 · Bad Gateway, without details.

The gateway in front of the API got no answer from it, as happens for a few seconds during a Chesly deploy. Retry in a few seconds.

### http_503

**CLI** · HTTP 503 · Service Unavailable, without details.

The gateway in front of the API answered that it is unavailable. Retry in a few seconds.

### http_504

**CLI** · HTTP 504 · Gateway Timeout, without details.

The gateway in front of the API gave up waiting for it. Retry in a few seconds.

### http_error

**CLI** · An HTTP error without details.

An HTTP error without details, with a status the codes above don't name: `status` says which. Check `CHESLY_API_URL` if you set it, then retry later.

### invalid_api_url

**CLI** · CHESLY_API_URL is not a usable API URL.

`CHESLY_API_URL` must be an `http://` or `https://` URL, such as `https://api.chesly.app`. Fix it, or unset it to use Chesly's.

### invalid_key_format

**CLI** · The API key is not well formed.

A key is `ck_live_` and 48 letters, digits, `_` or `-`. Check `CHESLY_API_KEY`, the stored key or the key you gave `chesly login --key -`, or run `chesly login` again. A malformed `CHESLY_API_KEY` or stored key exits with 3, and one given to `--key -` with 2.

### invalid_response

**CLI** · The API's answer is not what the CLI expects.

Something other than the Chesly API answered, such as a proxy or a wrong `CHESLY_API_URL`. Check the URL, then retry.

### keychain_error

**CLI** · The OS keychain refused.

The OS keychain refused to read or change the key. Unlock it, or set `CHESLY_API_KEY` instead.

### keychain_timeout

**CLI** · The OS keychain didn't answer in time.

The keychain didn't answer within 10 seconds: it may be locked, or waiting for someone to answer a dialog. Unlock it or answer the dialog, then retry, or set `CHESLY_API_KEY`.

### login_not_started

**CLI** · No sign-in is waiting to finish.

`chesly login --wait` found no sign-in waiting to finish. Run `chesly login --no-wait` first, then `chesly login --wait` within 10 minutes.

### network_error

**CLI** · The CLI couldn't reach the API.

The request got no answer: no connection, a DNS failure or a timeout. Check your connection, and `CHESLY_API_URL` if you set it, then retry.

### not_signed_in

**CLI** · Not signed in.

Run `chesly login`, or set `CHESLY_API_KEY`. The CLI exits with 3.

### usage_error

**CLI** · The command is not valid.

An argument is missing or an option is unknown. Run the command with `--help`. The CLI exits with 2.

## CLI warnings

The CLI prints a warning on standard error and goes on: a warning never changes the exit code. In JSON mode each is one line, `{"warning": "<code>", "message": "…"}`.

### delivery_wait_failed

**Warning** · The message was sent, but following its delivery failed.

The message went out, but following its delivery failed: a 401 or a 402 on a check, say. The command still exits with 0, and the warning carries the `idempotency_key` that asks the API for its answer again.

### env_key_set

**Warning** · CHESLY_API_KEY wins over the key login stored.

`CHESLY_API_KEY` is set, so the CLI uses it rather than the key `chesly login` stored. Unset it to use the stored key.

### event_too_large

**Warning** · An event too large to read was skipped.

An event too large to read ended the stream twice in a row, so `chesly watch` went on after it. The warning names its ID.

### events_expired

**Warning** · The resume point is no longer kept, so watching starts from now.

`chesly watch` was asked to resume from a point older than your plan keeps events (7 days on Personal, 30 on Pro), so it starts from new events. `chesly catchup` shows what you missed.

### invalid_event

**Warning** · An event the CLI could not read was skipped.

`chesly watch` skipped an event it couldn't read, and goes on.

### key_details_unavailable

**Warning** · The new key's details didn't load.

`chesly login` stored the new key, but its details didn't load, so `key` is null. `chesly whoami` shows them.

### key_still_active

**Warning** · A key this CLI no longer uses is still active.

A key this CLI no longer uses still works. The warning names it by its ID, first 12 and last 4 characters: revoke it with `chesly keys revoke <key_id>`, or in the dashboard.

### reconnecting

**Warning** · The event stream dropped and is reconnecting.

The event stream dropped. `chesly watch` reconnects by itself, after 3 seconds and then longer, up to 30, and resumes after the last event it had.
