# Rate limits and errors

> The FeatherPanel API response envelope, the common error codes, how rate limiting works, which limits are on by default and how admins change them.

Source: https://featherpanel.com/docs/api/rate-limits-and-errors/

## Response envelope

Every `/api` route answers with the same JSON shape. A success:

```json
{
  "success": true,
  "message": "OK",
  "data": { },
  "error": false,
  "error_message": null,
  "error_code": null
}
```

An error keeps the same keys and adds an `errors` array:

```json
{
  "success": false,
  "message": "Invalid API key",
  "data": [],
  "error": true,
  "error_message": "Invalid API key",
  "error_code": "INVALID_API_KEY",
  "errors": [{ "code": "INVALID_API_KEY", "detail": "Invalid API key", "status": 401 }]
}
```

Branch on `error_code`, not on `message`: messages can change, codes are what the code checks for. When a route
does not set a status, the panel uses 400.

## Common error codes

These come from the middleware that runs before every controller, so you can meet them on almost any route.

| Code | Status | When |
| --- | --- | --- |
| `NOT_AUTHENTICATED` | 401 | No session and no API key. |
| `INVALID_API_KEY` | 401 | The Bearer token matches no key. |
| `PUBLIC_API_KEY_NOT_ALLOWED` | 401 | A public key was sent while public-key auth is off. |
| `INVALID_ACCOUNT_TOKEN` | 400 | The session cookie is invalid or expired. |
| `API_KEY_IP_NOT_ALLOWED` | 403 | The key has an IP allow list and the request came from elsewhere. |
| `ACCOUNT_DELETED` | 403 | The account is deleted or scheduled for deletion. |
| `USER_BANNED` | 400 | The account is banned. |
| `USER_NOT_FOUND` | 404 | The key's owner no longer exists. |
| `NOT_AUTHORIZED` | 403 | Your role lacks the admin permission the route needs. |
| `SERVER_NOT_FOUND` | 404 | The server UUID or short ID does not exist. |
| `ACCESS_DENIED` | 403 | You do not own the server or VM and are not a subuser on it. |
| `SERVER_SUSPENDED` | 403 | The server is suspended. |
| `RATE_LIMITED` | 429 | See below. |

Controllers add their own codes for validation, for example `MISSING_REQUIRED_FIELDS`, `INVALID_DATA_TYPE` and
`INVALID_DATA_LENGTH`. The [endpoint index](https://featherpanel.com/docs/api/reference/) lists the routes, and the panel serves its full
OpenAPI document at `/api/openapi.json`.

## Rate limiting

When a limit is hit the panel answers 429:

```json
{
  "success": false,
  "message": "You are being rate limited! Retry after 42 seconds.",
  "error_code": "RATE_LIMITED",
  "data": { "error_code": "RATE_LIMITED", "retry_after": 42 }
}
```

The response also has a `Retry-After` header in seconds. Wait that long before retrying.

### How limits are applied

- Limits are counted per client IP in Redis. Without Redis the panel falls back to a file-based limiter.
- Rate limiting is on globally unless an admin turns it off.
- Each route ships with a suggested limit in code, such as 10 per minute on `/api/user/auth/login` and 5 per
  minute on `/api/user/auth/register`. The endpoint index shows the suggested limit of every route.
- Only the sign-in routes, the e-mail verification route, the API key routes and the public webhooks enforce
  their suggested limit by default. All other limits stay off until an admin enables them, so the UI's polling
  routes do not start returning 429 after an update.
- Users whose role has `admin.api.bypass_restrictions` are never rate limited.

### Changing limits

Open **Admin > Rate Limits** (needs `admin.settings.edit`). You can switch rate limiting off globally, and give
each route a limit per second, minute, hour or day. The page writes to `backend/storage/config/ratelimit.json`:

```json
{
  "_enabled": true,
  "routes": {
    "login": { "_enabled": true, "per_minute": 10 }
  }
}
```

Keys are route names (the login route is called `login`). A route entry with `"_enabled": false` turns that route's limit off even if it is one of the enforced defaults.
The same changes are available through `/api/admin/rate-limits`.

## Related

- [API overview](https://featherpanel.com/docs/api/)
- [API authentication](https://featherpanel.com/docs/api/authentication/)
- [Security tools in the admin area](https://featherpanel.com/docs/admin/security/)

## Frequently asked questions

### Which routes are rate limited out of the box?

Rate limiting is on globally, but only the authentication, API key and public webhook routes enforce their built-in limits by default. Every other route has a suggested limit that an admin can switch on.

### Can an integration skip rate limits?

Requests from a user whose role has the admin.api.bypass_restrictions permission are not rate limited.

### Where are the limits stored?

In backend/storage/config/ratelimit.json. The Rate Limits page in the admin area edits that file.
