# Errors and limits

> Error codes, rate limits and plan limits for the KickBot API and MCP server, and what your code or agent should do when it gets each one.

Source: https://kickbot.com/docs/api/start/errors-and-limits

Every KickBot API error has a stable `code`, a readable `message` and a `request_id`. The same codes come back from the REST API and from MCP tools. Normal use stays far below the rate limits: 120 requests per minute and 3,000 per hour for each key or app.

## Error format

REST errors use the HTTP status code and this body:

```json
{
  "error": {
    "code": "invalid_input",
    "message": "Invalid value for user_cooldown: Must be a number",
    "fields": { "user_cooldown": "Must be a number" },
    "request_id": "req_Ab12Cd34"
  }
}
```

The response also has the request id in the `X-Request-Id` header. MCP tools return the same `error` object in a result with `isError: true`. Include the `request_id` when you contact support.

## Error codes

| Code | HTTP | What it means | What to do |
|---|---|---|---|
| `unauthenticated` | 401 | The key or token is missing, wrong, expired or revoked. | Check the key. Apps reconnect with OAuth. |
| `forbidden` | 403 | You do not have the team permission, or the key is read-only. | Ask the owner for the permission, or use a read and write key. |
| `not_verified` | 403 | The Kick channel is not connected to KickBot yet. | Finish the setup in the dashboard. |
| `limit_reached` | 403 | A plan limit blocks the change (for example, enabled commands on the Free plan). | Turn off or delete an item first. Do not retry. |
| `premium_required` | 403 | The field or action is only on Premium. | Leave the field out. Do not retry. |
| `invalid_input` | 400 | A field is missing or has a wrong value. `fields` says which. | Fix the input. |
| `not_found` | 404 | The item or endpoint does not exist on this channel. | List the items again. |
| `method_not_allowed` | 405 | The REST path exists, but not with this HTTP method. | Use a method from the `Allow` header. |
| `conflict` | 409 | The change conflicts with the current state. | Read the item again and retry. |
| `rate_limited` | 429 | Too many requests. | Wait `retry_after_seconds` (also in the `Retry-After` header). |
| `upstream_error` | 502 | A service KickBot depends on (for example Kick) failed. | Try again later. |
| `internal_error` | 500 | Something went wrong at KickBot. | Try again later. Contact support if it continues. |

A 401 response also has a `WWW-Authenticate` header that points MCP clients to the OAuth metadata. See [Permissions and security](https://kickbot.com/docs/api/start/permissions-and-security).

## Rate limits

Limits are per key or connected app. The extra limits below also apply per channel, shared by all keys and apps on it, so many keys cannot multiply them.

| Kind of request | Limit |
|---|---|
| All requests | 120 per minute, 3,000 per hour |
| Tests and checks: test alerts, test AI images, tip replays, Kick data refresh, moderator check | 20 per minute |
| Clip downloads, VOD downloads and VOD editor clips | 10 per minute, 100 per day |
| Voice cloning | 5 per minute, 30 per day |

The [API reference](https://kickbot.com/docs/api) shows the extra limit on each action that has one.

Successful REST responses have `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers. A `429` response has a `Retry-After` header with the number of seconds to wait.

## Plan limits

The API follows the same plan limits as the dashboard. `get_account_overview` returns the limits for your channel in `limits`:

| Field | Premium | Free plan |
|---|---|---|
| `enabled_custom_commands` | `null` (no limit) | 5 |
| `timed_messages` | `null` (no limit) | 3 |
| `vod_downloads_per_day` | `null` (no limit) | 2 |
| `vod_editor_max_clip_seconds` | 10800 (3 hours) | 1200 (20 minutes) |

Field limits are the same as in the dashboard too, for example 500 characters for a command reply. Each field's limit is in its description in the API reference.
