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

# Errors & rate limits

> Error shape, HTTP codes, and rate limiting.

## Error shape

Errors carry a typed `error` object with a `trace_id` to quote to support:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "missing_fields",
    "message": "At least a name or an identifier is required.",
    "trace_id": "req_…"
  }
}
```

The same `trace_id` is in the **`X-Request-Id`** header of every response.

## Categories (`type` → HTTP)

| `type`                  | HTTP | When                                         |
| ----------------------- | ---- | -------------------------------------------- |
| `invalid_request_error` | 400  | Invalid body/parameters                      |
| `authentication_error`  | 401  | Missing token or invalid/revoked/expired     |
| `permission_error`      | 403  | Token lacks the scope (`insufficient_scope`) |
| `not_found_error`       | 404  | Resource doesn't exist in your workspace     |
| `conflict_error`        | 409  | Conflict (e.g. identifier already in use)    |
| `rate_limit_error`      | 429  | You exceeded the rate limit                  |
| `api_error`             | 500  | Internal error                               |

The `code` refines the `type` (e.g. `identifier_taken`, `invalid_status`, `campaign_not_draft`).

## Rate limits

The limit is applied **per Application**. Every response carries standard headers:

```
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1721669580
```

When exceeded you get **429** `rate_limit_error` with `Retry-After` (seconds). Retry with backoff.

<Tip>`at_test_` and `at_live_` share their Application's limit model. Cache the token (it lasts
\~1 h) instead of requesting one per call.</Tip>
