← API reference
Errors
Branch on the error code, never on the message. The table is generated from the OpenAPI document.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Schema error. details.path points at the offending field. |
| 401 | unauthorized | Missing or unknown API key. |
| 402 | quota_exceededRetry-After | Monthly quota reached. Retry-After gives the seconds until the month rolls over. |
| 403 | key_revoked | The key exists but may not be used: it has been revoked, or the account Engine API subscription is no longer active. The message says which. |
| 404 | not_found | No such route — also what you get for the right path with the wrong method. |
| 409 | idempotency_conflictRetry-After | Only with an Idempotency-Key header: the key was already used for a different request (idempotency_conflict — use a new key), or the first request with it is still running (idempotency_in_progress — retry after Retry-After to receive its answer). Never charged. |
| 409 | idempotency_in_progressRetry-After | Only with an Idempotency-Key header: the key was already used for a different request (idempotency_conflict — use a new key), or the first request with it is still running (idempotency_in_progress — retry after Retry-After to receive its answer). Never charged. |
| 413 | too_large | Input above a limit (see Limits). |
| 429 | busyRetry-After | Momentarily at capacity, or — on any key-authenticated path — your address sent too many unknown API keys within a minute. Retry-After in seconds; this never counts against your quota. |
| 500 | internal | Unexpected error, or the auth backend is unreachable (requests fail closed). |
| 503 | service_unavailable | An engine you asked for cannot be served right now — the nesting engine, or the async max engine. Two causes for max, and the message says which: the tier is not built into this deployment, or it is built in but the worker that solves the jobs is not responding. Fail-closed before a call is reserved, so it never costs you anything. |
| 504 | solve_timeout | The solve exceeded its hard time bound. On the rectangular paths the proxy enforces it; on /v1/optimize/nest the engine enforces its own, shorter budget and answers solve_timeout in the normal envelope. A call the proxy gave up on is not charged. |
Error body
Every error the engine itself produces uses the same envelope. Branch on error, which is a stable code; never on message, whose wording can change between releases. details is present on invalid_request, where path names the offending field, and on too_large, where max and got give the cap and what you sent.
The exception is a request body over the size cap: it carries maxBytes instead. An unknown engine adds available, the engine ids this deployment accepts.
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
{
"error": "invalid_request",
"message": "parts[0].h: must be greater than 0",
"details": { "path": "parts[0].h" }
}HTTP/1.1 402 Payment Required
Retry-After: 41400
Content-Type: application/json; charset=utf-8
{ "error": "quota_exceeded", "message": "monthly quota exhausted" }- 402 and 429 both carry a Retry-After header in seconds. On 402 it counts down to the quota reset at 00:00 UTC on the 1st of next month; on 429 it is a short back-off, and a 429 never consumes quota — the reserved call is handed back.
- The public demo key's refusals use the same envelope: outside its scope (nesting, the max engine, usage, jobs, import, a job above its size caps) a 403 key_revoked with details.reason "demo_scope"; at its rate limit a 429 busy with details.reason "demo_rate_limit" and details.limit. Both carry details.testKeyUrl, where a free test key is created, and every demo answer has the header X-CutOptim-Demo: true.
- A routing failure answers with not_found, a code deliberately outside the list above because the router produces it rather than the API contract. You get 404 and not 405 when the path is right but the method is wrong: all four optimize endpoints are POST-only.
- On the rectangular paths 504 comes from the reverse proxy, not from the engine, so its body belongs to the proxy and is not this JSON envelope; a single job within the input limits below solves well inside it, but several of the heaviest jobs arriving together can queue past it — and a call the proxy gave up on is not charged. /v1/optimize/nest is the exception: that solve is a subprocess with its own budget, deliberately kept below the proxy bound, so a timeout there does use this envelope, with the code solve_timeout.
Is an engine down? The status page shows the live state of the website, the Engine API, the nesting engine and the async max engine: Service status ↗