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

# Errors

> The Samsa API error envelope, every error code, and how to handle each one.

Every error the Samsa API returns — for any endpoint, at any status — uses one
consistent JSON **envelope**. Parse the machine-readable `code`, not the human
`message` (messages may change; codes are stable).

## The error envelope

```json theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The provided API key is invalid, expired, or revoked.",
    "request_id": "req_8f14e45fceea167a"
  }
}
```

| Field              | Description                                                                                                                 |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `error.type`       | Broad category, e.g. `authentication_error`, `credit_error`, `rate_limit_error`.                                            |
| `error.code`       | Stable, specific code you branch on (the table below).                                                                      |
| `error.message`    | Human-readable explanation. For display and logs — do not parse it.                                                         |
| `error.request_id` | Correlation id for this request, also returned as the `X-Request-ID` response header. **Quote it when contacting support.** |
| `error.param`      | Present on validation and scope errors — names the offending field or `"scope"`.                                            |

<Note>
  Successful responses never contain an `error` object. Branch on the HTTP status
  first, then on `error.code`.
</Note>

## Error codes

| HTTP | `code`                  | `type`                  | Meaning                                                  |
| ---- | ----------------------- | ----------------------- | -------------------------------------------------------- |
| 401  | `invalid_api_key`       | `authentication_error`  | Missing, malformed, unknown, expired, or revoked key.    |
| 403  | `missing_scope`         | `permission_error`      | Valid key lacks the endpoint's scope.                    |
| 402  | `insufficient_credits`  | `credit_error`          | Organization credit pool is below the action cost.       |
| 402  | `subscription_inactive` | `credit_error`          | No usable organization subscription.                     |
| 404  | `not_found`             | `invalid_request_error` | Unknown id, or a resource owned by another organization. |
| 422  | `validation_error`      | `invalid_request_error` | Request body or parameters failed validation.            |
| 429  | `rate_limited`          | `rate_limit_error`      | Per-key request-rate window exceeded.                    |
| 429  | `too_many_active_jobs`  | `rate_limit_error`      | Organization's concurrent-job cap reached.               |
| 500  | `internal_error`        | `api_error`             | Unexpected server error.                                 |

***

### `invalid_api_key`

**HTTP 401.** The `Authorization` header is missing or malformed, or the key is
unknown, expired, or revoked — or the key creator is no longer a member of the
organization. Expired and unknown keys are intentionally indistinguishable.

```json theme={null}
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The provided API key is invalid, expired, or revoked.",
    "request_id": "req_8f14e45fceea167a"
  }
}
```

**How to handle.** Check the `Authorization: Bearer samsa_sk_…` header. If the key
was revoked or expired, [create a new one](/guides/authentication#rotating-a-key).
Do not retry — the outcome will not change.

### `missing_scope`

**HTTP 403.** The key is valid but lacks the [scope](/guides/authentication#scopes)
the endpoint requires. `param` is `"scope"` and the message names the missing scope.

```json theme={null}
{
  "error": {
    "type": "permission_error",
    "code": "missing_scope",
    "message": "The API key is missing the required scope: images.generate.",
    "request_id": "req_1c9a3b7d2e5f4a80",
    "param": "scope"
  }
}
```

**How to handle.** An admin edits the key's scopes (or issues a new key) to grant the
named scope. Do not retry without changing the key.

### `insufficient_credits`

**HTTP 402.** The organization's spendable credit pool (subscription plus valid
top-ups) is below the action's cost. See [Pricing](/guides/pricing).

```json theme={null}
{
  "error": {
    "type": "credit_error",
    "code": "insufficient_credits",
    "message": "Insufficient credits available.",
    "request_id": "req_2d5f4a801c9a3b7d"
  }
}
```

**How to handle.** Top up or upgrade the organization's plan in the app, then retry.
Nothing was charged and no job was created.

### `subscription_inactive`

**HTTP 402.** The organization has no usable subscription (none active, in grace, or
holding spendable top-ups). Distinct from `insufficient_credits`, where a subscription
exists but the pool is too low.

```json theme={null}
{
  "error": {
    "type": "credit_error",
    "code": "subscription_inactive",
    "message": "No active subscription for this organization.",
    "request_id": "req_4a801c9a3b7d2d5f"
  }
}
```

**How to handle.** Reactivate billing for the organization in the app, then retry.

### `not_found`

**HTTP 404.** The id is unknown, or it belongs to another organization. The two cases
are indistinguishable by design, so existence is never disclosed across organizations.

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "not_found",
    "message": "The requested resource was not found.",
    "request_id": "req_7d2d5f4a801c9a3b"
  }
}
```

**How to handle.** Verify the id, and that the key's organization owns the resource.
Do not retry.

### `validation_error`

**HTTP 422.** The request body or a parameter failed validation. `param` names the
offending field; `message` explains the constraint.

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_error",
    "message": "aspect_ratio must be one of: 1:1, 4:3, 4:5, 16:9, 21:9, 9:16",
    "request_id": "req_3b7d2d5f4a801c9a",
    "param": "aspect_ratio"
  }
}
```

**How to handle.** Fix the request per `message` and `param`, then resubmit. This is a
client error — retrying the same request will fail identically.

### `rate_limited`

**HTTP 429.** The key exceeded its per-key request-rate window. The response carries
`Retry-After` and `X-RateLimit-*` headers. See [Rate limits](/guides/rate-limits).

```json theme={null}
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "API rate limit exceeded. Slow down and retry after the rate-limit window resets.",
    "request_id": "req_5f4a801c9a3b7d2d"
  }
}
```

**How to handle.** Back off and retry after the `Retry-After` interval. Use
exponential backoff for repeated 429s.

### `too_many_active_jobs`

**HTTP 429.** The organization has reached its cap on concurrent in-flight jobs. The
message includes the current count and the limit, and a `Retry-After` header is set.

```json theme={null}
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_active_jobs",
    "message": "Too many active jobs for this organization (5/5). Wait for in-flight jobs to finish before submitting more.",
    "request_id": "req_801c9a3b7d2d5f4a"
  }
}
```

**How to handle.** Wait for in-flight jobs to reach a terminal status (poll their
`GET` endpoint or use a [webhook](/guides/webhooks)) before submitting more, then
retry after `Retry-After`.

### `internal_error`

**HTTP 500.** An unexpected error on Samsa's side. The response never leaks internal
details — the `request_id` is your handle for support.

```json theme={null}
{
  "error": {
    "type": "api_error",
    "code": "internal_error",
    "message": "An internal error occurred. Contact support with the request_id.",
    "request_id": "req_9a3b7d2d5f4a801c"
  }
}
```

**How to handle.** Retry with backoff — 500s are often transient. If it persists,
contact [support@samsa.ai](mailto:support@samsa.ai) with the `request_id`.

## Using `request_id` for support

Every error (and every success) carries a `request_id`, also returned as the
`X-Request-ID` response header. It ties your client-side error, the response header,
and Samsa's server logs to one request. Log it, and quote it when you contact
[support@samsa.ai](mailto:support@samsa.ai) — it is the fastest way for us to find
exactly what happened.

<Tip>
  New error codes may be added over time (for example, additive per-endpoint codes).
  Treat an unrecognized `code` the same as its HTTP status class, and always branch on
  `code` rather than matching `message` text.
</Tip>
