# Crossword Generator API — error codes

Every failure is an RFC 9457 problem document (`application/problem+json`): `type` (a URL into https://crossword.texs.org/developers/errors#CODE), `title`, `status`, `detail`, and a stable `code`. Branch on `code`. Problems may carry extra members: `limit`, `remaining`, `maxGridSize`, `requiredScope`, `field`, `retryAfter`, `queued`; every membership-shaped problem also carries `tier` and `upgradeUrl` or `contact`.

A stable error name for programs. New codes may be added. If you do not
know a code, handle it like any other error with the same HTTP status.

| Code | Status | Meaning |
|---|---|---|
| `UNAUTHORIZED` | 401 | No key, or an unknown/revoked one |
| `FORBIDDEN_SCOPE` | 403 | Valid key, missing scope |
| `GRID_SIZE_LOCKED` | 403 | Grid larger than the tier's `maxGridSize` |
| `MEMBERS_ONLY` | 403 | Feature needs a paid membership |
| `AI_QUOTA_REACHED` | 429 | Monthly AI clue allowance spent |
| `FILL_QUOTA_REACHED` | 429 | Monthly fill allowance spent |
| `PUZZLE_QUOTA_REACHED` | 429 | Monthly new-puzzle allowance spent |
| `SHOWCASE_QUEUE_FULL` | 409 | Three puzzles already waiting for showcase review |
| `RATE_LIMITED` | 429 | Per-minute limit exceeded |
| `SOLVER_BUSY` | 429 | Too many solves running; retry shortly |
| `LANGUAGE_UNAVAILABLE` | 400 / 503 | Unknown code, or its index could not be loaded |
| `VALIDATION_ERROR` | 400 | Request body or query string is invalid |
| `NOT_FOUND` | 404 | No such resource, or not yours to see |
| `UPSTREAM_UNAVAILABLE` | 502 / 503 | Solver or storage unreachable |

## Retrying

- `RATE_LIMITED`, `SOLVER_BUSY`: wait `Retry-After` seconds and retry the same request.
- `FILL_QUOTA_REACHED`, `AI_QUOTA_REACHED`, `PUZZLE_QUOTA_REACHED`: the monthly allowance is spent; retrying before the next calendar month cannot succeed. `tier` names the plan, `upgradeUrl` (or `contact` on the top plan) is the way out, and `detail` lists what the plans above allow — show them to the person.
- `SHOWCASE_QUEUE_FULL`: three puzzles are already waiting for review; publish unlisted now and resubmit once one is reviewed.
- `UPSTREAM_UNAVAILABLE`, `LANGUAGE_UNAVAILABLE` with status 503: transient; retry with backoff.
- Everything else (`UNAUTHORIZED`, `FORBIDDEN_SCOPE`, `GRID_SIZE_LOCKED`, `MEMBERS_ONLY`, `VALIDATION_ERROR`, `NOT_FOUND`, `LANGUAGE_UNAVAILABLE` with status 400): the same request will fail the same way; change the request, the key, or the account.

Full explanations and fixes per code, for humans: https://crossword.texs.org/developers/errors
