# Errors

One JSON error shape with error, message and retryable; every code with its HTTP status; when to retry.

Source: https://magistermarketing.com/docs/api/errors

Every error the API answers is JSON with the same shape, the one Magister's MCP tools use:

```json
{
  "error": "rate_limited",
  "message": "Rate limit of 60 requests a minute exceeded for this organization.",
  "retryable": true,
  "retry_after_seconds": 12,
  "reason": "rate_limited"
}
```

- `error` is a stable code (below); branch on it, not on `message`, which is for people.
- `retryable` says whether the same request may succeed later. Retry only when it is `true`, and after `retry_after_seconds` when it is given (a 429 also sends `Retry-After`). Otherwise fix the request, your balance or your access first.
- Some errors add details: `reason`, `required_scope`, `available_credits`, `top_up_url`, `estimated_credits`, `request_id`, or `fields` for a body that does not fit the schema.
- A request that fails on Magister's side after it started (500 `upstream_failed` with `request_id`) is not retryable: the work may have run and been charged. Look it up in **Settings → Developers → Requests** before sending it again. A path that does not exist answers 404 `not_found`, and a wrong method 405 `unsupported_operation`.

```json
{
  "error": "validation_error",
  "message": "domain: Field required",
  "retryable": false,
  "fields": [{ "field": "domain", "message": "Field required" }]
}
```

### HTTP statuses

- **401**: Missing, unknown or revoked API key.
- **402**: Not enough API credits (`limit_reached`, `credits_exhausted`, with `top_up_url`), over `max_credits`, or a hold above the key's whole daily cap (`key_daily_cap_too_low`).
- **403**: The key lacks a scope, or the endpoint is not enabled.
- **404**: Unknown job; or the API is not enabled.
- **409**: Not ready yet: the report of a job that has not finished.
- **422**: Invalid input (`validation_error`, with `fields` when the body does not fit the schema).
- **429**: 60 requests a minute or 5 running jobs per organization, or the key's daily cap; see `Retry-After`.
- **500**: The request failed unexpectedly (`upstream_failed`): retryable when it failed before it started; after, `retryable` is false and the error carries its `request_id`.
- **502**: An upstream provider failed. Billed only what it used before failing.
- **503**: The request could not start (`transport_unavailable`).

### Error codes

| Code | HTTP | When | Retry |
| --- | --- | --- | --- |
| `not_authenticated` | 401 | No key, an unknown or revoked key, or a key whose creator left the organization. | no |
| `budget_exhausted` | 402 | Passed through from the tool behind the endpoint. | varies |
| `limit_reached` | 402 | Not enough API credits (`reason: credits_exhausted`, with `available_credits` and `top_up_url`), the hold is above your `max_credits` (`reason: max_credits_exceeded`, with `estimated_credits`), or the hold is above the whole daily cap of the key, so that key can never start it (`reason: key_daily_cap_too_low`, with `estimated_credits` and `daily_cap_credits`). Nothing ran and nothing was charged. | no |
| `payment_required` | 402 | Passed through from the tool behind the endpoint. | varies |
| `entitlement_unavailable` | 403 | The API is not open to your organization yet, the endpoint is not available yet, or an AI engine you asked for is not enabled. | no |
| `forbidden` | 403 | Passed through from the tool behind the endpoint. | varies |
| `not_authorized` | 403 | The key lacks the scope the endpoint needs (`required_scope`). | no |
| `not_found` | 404 | The API is switched off, or no such job or set (in this project). | no |
| `project_not_found` | 404 | No such brand in this organization. | no |
| `approval_required` | 409 | Passed through from the tool behind the endpoint. | varies |
| `browser_unavailable` | 409 | Passed through from the tool behind the endpoint. | varies |
| `conflict` | 409 | Passed through from the tool behind the endpoint. | varies |
| `needs_connection` | 409 | Passed through from the tool behind the endpoint. | varies |
| `not_ready` | 409 | The report of a job that has not succeeded. | no |
| `plan_missing` | 409 | Passed through from the tool behind the endpoint. | varies |
| `asset_invalid` | 422 | Passed through from the tool behind the endpoint. | varies |
| `needs_media` | 422 | Passed through from the tool behind the endpoint. | varies |
| `unsupported_operation` | 422 | Passed through from the tool behind the endpoint. | varies |
| `validation_error` | 422 | The input is invalid. A body that does not fit the schema lists each problem in `fields`. | no |
| `quota_exceeded` | 429 | Passed through from the tool behind the endpoint. | varies |
| `rate_limited` | 429 | `reason: rate_limited` (60 requests a minute per organization), `jobs_limit` (5 running jobs per organization) or `key_daily_cap_reached` (the key's daily credit cap, reset at 00:00 UTC). Wait `retry_after_seconds` (also the `Retry-After` header). | yes |
| `upstream_failed` | 502 | A provider behind the endpoint failed (502), or the request failed unexpectedly (500; not retryable once it had started, with `request_id`). Billed only what it used. | varies |
| `transport_unavailable` | 503 | The request could not start. | varies |

Codes marked "passed through" come from the Magister tool behind an endpoint, exactly as its MCP tool returns them. Where **Retry** says "varies", read `retryable` in the error itself.
