> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.morphiaone.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.morphiaone.ai/_mcp/server.

# Status codes

Statuses here are never collapsed. An authentication failure is `401`, a
permission failure `403`, an exhausted balance `402`, a limit `429` and a
dependency `503` -- none of them is reported as a generic `400`, because the
action each one needs is different and a single status would hide it.

| Status                       | Retry?        | Means                                                                         | Do                                                                                                                               |
| ---------------------------- | ------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `400` Bad Request            | no            | the request is wrong and will stay wrong                                      | fix the request; a retry repeats the same mistake at the same cost                                                               |
| `401` Unauthorized           | no            | we could not authenticate the key presented                                   | check the header and the value; a missing, unknown, revoked or expired key, or a disabled account, all answer this; do not retry |
| `402` Payment Required       | no            | the account is out of credits                                                 | alert an operator; this clears when someone tops up, not on a retry                                                              |
| `403` Forbidden              | no            | the key is real and is not allowed to do this                                 | add the scope to the key, or call from an address its allowlist names                                                            |
| `404` Not Found              | no            | no such job or asset for this account -- including one that expired           | treat as terminal; it also answers a job belonging to another account                                                            |
| `409` Conflict               | one code only | an idempotency key conflicts with an earlier request                          | retry `IDEMPOTENCY_IN_PROGRESS` after `Retry-After`; never retry the reuse                                                       |
| `410` Gone                   | no            | an input asset this request names has expired                                 | upload the image again and submit with the new asset id and a new key                                                            |
| `413` Content Too Large      | no            | the image exceeds the accepted size                                           | downscale before sending; full-resolution capture is not needed                                                                  |
| `415` Unsupported Media Type | no            | the image is not JPEG, PNG or WebP, or is not the type it declares            | send a supported image with a Content-Type that matches its bytes                                                                |
| `422` Unprocessable Content  | no            | the image is a supported type but is too large in pixels or cannot be decoded | send a smaller or re-encoded image; the same bytes fail the same way                                                             |
| `429` Too Many Requests      | yes           | a rate, quota or queue limit of yours is full                                 | honour `Retry-After`, then back off; sustained 429 wants concurrency control                                                     |
| `500` Internal Server Error  | yes           | we failed in a way we did not classify                                        | retry with backoff, keep the idempotency key, record `request_id`                                                                |
| `503` Service Unavailable    | yes           | a dependency of ours is not ready                                             | retry with backoff; on a poll this never means the job is gone                                                                   |

## Which codes arrive under each status

**`400` Bad Request** — `IDEMPOTENCY_KEY_REQUIRED`, `INVALID_CURSOR`, `INVALID_IDEMPOTENCY_KEY`, `INVALID_REQUEST`, `INVALID_USAGE_RANGE`

**`401` Unauthorized** — `INVALID_API_KEY`

**`402` Payment Required** — `INSUFFICIENT_CREDITS`

**`403` Forbidden** — `API_KEY_IP_NOT_ALLOWED`, `INSUFFICIENT_SCOPE`

**`404` Not Found** — `ASSET_CONTENT_UNAVAILABLE`, `ASSET_NOT_FOUND`, `JOB_NOT_FOUND`

**`409` Conflict** — `ASSET_OWNED_BY_JOB`, `IDEMPOTENCY_IN_PROGRESS`, `IDEMPOTENCY_KEY_REUSED`, `JOB_IN_PROGRESS`, `JOB_NOT_CANCELLABLE`

**`410` Gone** — `ASSET_EXPIRED`, `JOB_DELETED`

**`413` Content Too Large** — `PAYLOAD_TOO_LARGE`

**`415` Unsupported Media Type** — `UNSUPPORTED_MEDIA_TYPE`

**`422` Unprocessable Content** — `UNPROCESSABLE_IMAGE`

**`429` Too Many Requests** — `QUOTA_EXCEEDED`, `RATE_LIMITED`, `TENANT_QUEUE_LIMIT_EXCEEDED`

**`500` Internal Server Error** — `INTERNAL_ERROR`

**`503` Service Unavailable** — `MAINTENANCE_MODE`, `QUEUE_CAPACITY_EXCEEDED`, `SERVICE_UNAVAILABLE`

## Statuses that are not errors

| Status | When                                                                               |
| ------ | ---------------------------------------------------------------------------------- |
| `200`  | a poll, a result fetch, a usage report -- **and a failed job**                     |
| `202`  | a submission accepted; the body is the job, `id` included, and `Location` names it |
| `304`  | your `If-None-Match` matched; the job has not changed                              |

The `200` row is the one that costs people a day. A failed analysis is a
successful request -- the HTTP layer did its job and the work did not.
[Asynchronous jobs](/concepts/jobs), [Error reference](/api-reference/errors).

## What a status never tells you

It does not tell you whether you were charged: an accepted submission that
fails during analysis is a `202` followed by a `200`, and
[Credits and usage](/concepts/credits) is where that is written down. It also
does not tell you whether the job survived -- a `503` on a poll is about the
poll, never about the job.