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

# Errors and idempotency

> One error shape everywhere, what each status means, and how to retry safely.

Every failure has the same shape, and every response — success or not — carries an
`x-request-id` header. Email it to [support@creatorline.io](mailto:support@creatorline.io)
and we can find the exact request.

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_parameter",
    "message": "Invalid value for \"aspect_ratio\": \"99:99\". Allowed: 1:1, 9:16, 16:9.",
    "param": "params.aspect_ratio"
  },
  "request_id": "req_8fQ2mRxK1pLd"
}
```

<Note>
  Errors are written to be **actionable**: a bad enum echoes the legal values, an unknown
  tool lists the real ones, and `param` points at the exact field. If you are writing an
  agent, surfacing `error.message` verbatim is usually enough for it to fix itself.
</Note>

## Statuses

| Status | `type`                       | What it means                                                        | Retry?               |
| ------ | ---------------------------- | -------------------------------------------------------------------- | -------------------- |
| `400`  | `invalid_request_error`      | Bad input. `param` names the field.                                  | Only after fixing it |
| `401`  | `authentication_error`       | Missing, malformed, revoked or expired key.                          | No                   |
| `402`  | `insufficient_credits_error` | Not enough credits. Carries `required_credits` and `credit_balance`. | After topping up     |
| `403`  | `permission_error`           | A `read` key tried to write.                                         | No                   |
| `404`  | `not_found_error`            | Unknown id — **or** an id in another organization.                   | No                   |
| `429`  | `rate_limit_error`           | Over 120 req/min. Honour `Retry-After`.                              | Yes, with backoff    |
| `5xx`  | `api_error`                  | Our fault.                                                           | Yes, with backoff    |

<Note>
  A `5xx` that keeps repeating, or any response you cannot explain, is worth an email to
  [support@creatorline.io](mailto:support@creatorline.io) with the `request_id`. That id is
  how we find your exact call in our logs.
</Note>

<Warning>
  A resource belonging to another organization returns `404`, never `403`. We will not
  confirm that an id exists somewhere else.
</Warning>

## Retrying safely

`GET` is safe to retry. For `POST /v1/generations` — the one call that spends money —
send an `Idempotency-Key`:

```bash theme={null}
curl https://api.creatorline.io/v1/generations \
  -H "Authorization: Bearer $CREATORLINE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "tool": "text-to-photo", "prompt": "…" }'
```

A replay with the same key returns the **original** generation, with
`idempotent-replay: true`, and charges nothing more. Generate one UUID per logical
operation and reuse it across that operation's retries. Keys are scoped to your API key
and kept for 24 hours.

<Accordion title="Why a network timeout is not a lost run">
  If your request times out, the run may well have started — the charge happens server
  side, before your response is written. Retrying with the same `Idempotency-Key` is how
  you find out which: you get the original job handle back instead of paying twice.
</Accordion>

## The 402 you should expect

```json theme={null}
{
  "error": {
    "type": "insufficient_credits_error",
    "code": "insufficient_credits",
    "message": "This request costs 30 credits and the workspace has 12."
  },
  "request_id": "req_8fQ2mRxK1pLd",
  "required_credits": 30,
  "credit_balance": 12
}
```

Nothing was charged and nothing was started. Call
[`POST /v1/generations/cost`](/api-reference/generations/estimate-a-generation-s-cost)
first if you want to avoid it, or watch
[`GET /v1/credits`](/api-reference/credits/balance-and-ledger).


## Related topics

- [Start a generation](/api-reference/generations/start-a-generation.md)
- [Finish an upload](/api-reference/assets/finish-an-upload.md)
- [Start an upload](/api-reference/assets/start-an-upload.md)
- [Publish a post](/api-reference/posts/publish-a-post.md)
- [Create a post](/api-reference/posts/create-a-post.md)
