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

> ## Agent Instructions
> The OpenAPI document at /api-reference/openapi.yaml defines the target contract. Its x-reflections-availability field and each operation's availability notice identify supported test and live forms. Do not infer implementation from a schema or code sample. Live keys support account details, reads of the licenses the calling account holds as licensee or issued as talent (GET /v1/licenses?role=issuer), and GET /v1/generations?license=… for the state of outputs under such a license (summaries only: no prompt, reference, bytes or metadata). Live image checks, submissions and receipts are built but not activated: until activation, a live POST /v1/checks or /v1/generations returns 403 live_not_activated, which must not be retried. Discovery and JWKS are at the origin root (https://app.reflections.ai/.well-known/...), not under /v1.
> Three rules hold everywhere: a decision is never an error (deny and escalate are 200 responses, and a live check still evaluating is a 202 with status checking); generate nothing for a named talent without an allow; deliver nothing until the generation is allow.
> The sandbox accepts personal rk_test_ keys. Persist a separate Idempotency-Key and body for each logical /v1 POST; retry an unknown outcome with the same key and body. OAuth and Talent API MCP remain planned.

# Errors

> The problem details format, and every error code with its HTTP status and what to do.

An error means the request could not be evaluated at all. Every error is an
[RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem detail, sent as
`application/problem+json`, with a stable `code` you can branch on.

<Note>
  A decision is never an error. `deny` and `escalate` are `200` responses that carry a `decision`,
  `reasons` and sometimes a `remedy`. Their codes are listed in [Reason codes](/api-reference/reason-codes).
</Note>

## The problem format

```json theme={null}
{
  "type": "https://docs.reflections.ai/errors/parameter_invalid",
  "title": "A parameter is invalid",
  "status": 400,
  "code": "parameter_invalid",
  "param": "use.territories[1]",
  "detail": "\"UK\" is not an ISO 3166-1 alpha-2 code. Use \"GB\".",
  "request_id": "req_8f2k4m6p8r0t2v4x6z8b0d2f4h"
}
```

| Field | Always present | Meaning |
| - | - | - |
| `type` | Yes | A URL for this error, `https://docs.reflections.ai/errors/<code>`, which opens the code's entry below. |
| `title` | Yes | A short summary. It can change; do not match on it. |
| `status` | Yes | The HTTP status, repeated. |
| `code` | Yes | The stable error code. Branch on this. |
| `request_id` | Yes | The same value as the `Request-Id` header. Include it when you contact [support](/production/support). |
| `detail` | No | What went wrong in this request. Log it; do not show it to end users. |
| `param` | No | The field at fault, as a path such as `use.territories[1]`. |
| `doc_url` | No | A link to the documentation for this error. |

The [OAuth endpoints](/api-reference/oauth/create-an-access-token) are the exception: their `400`
and `401` responses use the format their RFCs define, such as
`{"error": "invalid_grant", "error_description": "…"}`, so OAuth libraries can read them. Each
endpoint lists its `error` values. Their `429` and `5xx` responses are problem details.

## Handling errors

* Branch on `code`, then on `status`. Treat an unknown `code` by its status.
* Retry only the codes marked below, and always with the same `Idempotency-Key`. A new key on an
  unknown outcome can run the request twice. See [Idempotency](/api-reference/idempotency).
* When an error stops a check, do not generate a named talent. When it stops a generation, do not
  deliver the output. See [Failure modes](/concepts/failure-modes).

## Error codes

### 400 Bad request

| Code | Meaning | What to do |
| - | - | - |
| <span id="invalid_request">`invalid_request`</span> | The body is not valid JSON, or its shape is wrong. | Fix the request. Do not retry as is. |
| <span id="parameter_missing">`parameter_missing`</span> | A required field is absent. `param` names it. | Add the field. |
| <span id="parameter_invalid">`parameter_invalid`</span> | A field has an invalid value. `param` names it. | Fix the value; `detail` says what is accepted. |
| <span id="unsupported_modality">`unsupported_modality`</span> | The modality is not offered for this use, such as a session for `image`. | Use a supported modality or endpoint. |
| <span id="unsupported_media_type">`unsupported_media_type`</span> | The file type is not accepted for this purpose. | Convert the file, or use the right `purpose`. |
| <span id="media_unreadable">`media_unreadable`</span> | A file or inline media could not be decoded. | Check the bytes and `media_type`, then send again. |
| <span id="version_unsupported">`version_unsupported`</span> | `Reflections-Version` names an unknown version. | Send a version listed in [Versioning](/api-reference/versioning). |
| <span id="authorization_code_invalid">`authorization_code_invalid`</span> | An OAuth authorization code is unknown, expired or used, or its `code_verifier` or `redirect_uri` does not match. | Send the licensee through the authorization page again. |

### 401 Unauthorized

| Code | Meaning | What to do |
| - | - | - |
| <span id="authentication_required">`authentication_required`</span> | No credentials were sent. | Send `Authorization: Bearer rk_…`. |
| <span id="invalid_api_key">`invalid_api_key`</span> | The key is unknown or revoked. | Use a current key from the [dashboard](https://app.reflections.ai/developers/keys). |
| <span id="token_invalid">`token_invalid`</span> | An authorization or session token failed verification: its signature, `aud` or `exp`. | Run a new check, or renew the session. |

### 403 Forbidden

| Code | Meaning | What to do |
| - | - | - |
| <span id="insufficient_scope">`insufficient_scope`</span> | A restricted key lacks the scope this call needs. `detail` names it. | Add the scope to the key. See [Authentication](/api-reference/authentication#restricted-keys). |
| <span id="account_not_connected">`account_not_connected`</span> | `Reflections-Account` names an account with no active connection to yours, or the connection's scopes do not cover this call. | Ask the licensee to connect your platform. Stop sending calls for them. |
| <span id="mandate_required">`mandate_required`</span> | A talent-side call names a talent your account holds no active mandate for, or the mandate lacks the power the call needs. `detail` names the power. | Ask the talent to add the power in the Talent Portal. Stop acting for a talent whose mandate ended. |
| <span id="livemode_mismatch">`livemode_mismatch`</span> | A test object was used with a live key, or a live object with a test key. | Use the key for the object's mode. |
| <span id="live_not_activated">`live_not_activated`</span> | A live check or generation was sent before Reflections activated live signing. Nothing was evaluated or reserved. | Do not retry: the answer stays the same until activation. Use a test key, and contact support for activation. |
| <span id="platform_not_permitted">`platform_not_permitted`</span> | The request names a `license` explicitly, and that license excludes your platform. | Omit `license` so the check chooses one, or ask the licensee to add your platform. |

`platform_not_permitted` applies only when you name a `license`. Without one, the check is decided
instead: when no license the licensee holds covers the talent on your platform, the result is a
`200` with `decision: "deny"` and the reason code
[`platform_not_licensed`](/api-reference/reason-codes#license-and-window).

### 404 Not found

| Code | Meaning | What to do |
| - | - | - |
| <span id="resource_not_found">`resource_not_found`</span> | No such object for this account. | Check the ID, the key's mode, and `Reflections-Account`. |

### 409 Conflict

| Code | Meaning | What to do |
| - | - | - |
| <span id="idempotency_key_in_use">`idempotency_key_in_use`</span> | The first request with this key is still running. A live check still evaluating is not this error: it returns `202` with `status: "checking"`. | Retry with the same key after a short wait. |
| <span id="generation_already_submitted">`generation_already_submitted`</span> | This check's candidate already has a generation. | [List generations](/api-reference/generations/list-generations) with `check` and use the existing one. |
| <span id="authorization_consumed">`authorization_consumed`</span> | Every generation the check allowed (`max_generations`) was already submitted. | Run a new check for further outputs. |
| <span id="check_not_allowed">`check_not_allowed`</span> | The generation names a check whose decision is not `allow`. | Do not submit. Handle the check's decision. |
| <span id="check_expired">`check_expired`</span> | The check's authorization expired before this call. | Run a new check. |
| <span id="escalation_closed">`escalation_closed`</span> | The escalation was already resolved, expired or cancelled. | Retrieve the check or generation for its outcome. |
| <span id="license_draft_closed">`license_draft_closed`</span> | The draft was already signed, declined, discarded or expired. | Retrieve the draft. Create a new one to change terms. |
| <span id="invalid_state_transition">`invalid_state_transition`</span> | The object's status does not allow this action, such as resuming a license that is not suspended or disputing a paid statement. `detail` names the status. | Retrieve the object and act on its current status. |
| <span id="session_not_active">`session_not_active`</span> | The session ended or was terminated. | Stop output now. Start a new session only if a new check would allow it. |

### 413 Payload too large

| Code | Meaning | What to do |
| - | - | - |
| <span id="payload_too_large">`payload_too_large`</span> | Inline media is over 10 MB, or a multipart upload is over 100 MB. | [Upload the file](/api-reference/files/upload-a-file) and send its ID. For files over 100 MB, use the JSON upload URL, up to 5 GB. |

### 422 Unprocessable

| Code | Meaning | What to do |
| - | - | - |
| <span id="idempotency_key_reused">`idempotency_key_reused`</span> | This key was used with a different body or endpoint. | Use a new key for a new request. |
| <span id="artifact_digest_mismatch">`artifact_digest_mismatch`</span> | The bytes do not match the `sha256` you declared. | Recompute the digest over the exact bytes you send. |

### 429 Too many requests

| Code | Meaning | What to do |
| - | - | - |
| <span id="rate_limited">`rate_limited`</span> | You exceeded a rate limit. | Wait `Retry-After` seconds, then retry with the same key. See [Rate limits](/api-reference/rate-limits). |

### 5xx Server errors

| Status | Code | Meaning | What to do |
| - | - | - | - |
| 500 | <span id="internal_error">`internal_error`</span> | An unexpected failure on our side. | Retry with the same key, with backoff. |
| 503 | <span id="service_unavailable">`service_unavailable`</span> | Reflections is temporarily unavailable. | Do not generate a named talent. Retry with the same key after `Retry-After`. |
| 504 | <span id="evaluation_timeout">`evaluation_timeout`</span> | A verification did not finish in time. Only verifications return it; checks escalate instead. | Retry, or verify by receipt instead of by file. |

<Warning>
  A `503` or a timeout on a check is not permission. Without an `allow` and an unexpired
  authorization, do not generate a named talent. See [Caching and outages](/build/caching-and-outages).
</Warning>

## Related

<Columns cols={2}>
  <Card title="Reason codes" icon="scale-balanced" href="/api-reference/reason-codes">
    Why a use was denied or escalated, and what to show.
  </Card>

  <Card title="Idempotency" icon="key" href="/api-reference/idempotency">
    Retry safely with the same key.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.