Every error is JSON in one shape: a stable code to branch on, a message that states the fact and the next step, and details when a field or an object is involved. The HTTP status tells you the class; the code tells you what to do.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "two fields need a change — see details",
"details": {
"items.0.material": "pick a material from GET /v1/materials",
"delivery.phone": "the courier needs a phone number"
}
}
}422 — two fields to fix
Statuses
| Status | Class | What to do |
|---|---|---|
401 | The key. | Fix the key — missing, malformed, unknown or revoked — then send again. |
403 | The account or the environment. | Read the code: the account is inactive, the key's prefix is wrong, or the route is test-only. |
404 | No such object in this environment. | Check the id and the environment of the key. |
409 | The request conflicts with the current state. | Read the code; most carry details naming the object in the way. |
413 | The body is over 256 KiB. | File bytes go to the signed upload URL, never into JSON. |
422 | A field is wrong. | Fix the fields named in details and send again. |
429 | Pace or a monthly cap. | Wait Retry-After seconds; see Rate limits. |
5xx | Our side. | Retry with backoff and jitter; quote X-Request-ID if it repeats. |
Codes
The key
Answered before the request is read. Fix the key, then send again.
| Code | Status | What it means and what to do |
|---|---|---|
INVALID_API_KEY | 401 | The API key is missing, malformed or unknown — send a live or test key as Authorization: Bearer lc_live_… or lc_test_…. |
API_KEY_REVOKED | 401 | This API key was revoked or has expired — create a new one in your dashboard under Integrations → Keys. |
SCOPE_MISMATCH | 403 | The key's prefix names a different environment than the key was issued for — use the key exactly as it was shown. |
PARTNER_INACTIVE | 403 | This partner account is not open for this key yet — live keys need an active account with a countersigned agreement; your dashboard shows the next step. |
TEST_ONLY | 403 | This route is for test keys — call it with your lc_test_ key; a live order moves through its states as production happens. |
The request
The request shape or pace. error.details names the field when there is one.
| Code | Status | What it means and what to do |
|---|---|---|
RATE_LIMITED | 429 | Too many requests for this key — wait the seconds in Retry-After and send again. |
QUOTA_EXCEEDED | 429 | This month's cap for your plan is reached — it resets on the first of next month (UTC); write to hello@layercrew.com for a higher cap. |
VALIDATION_ERROR | 422 | A field is wrong — error.details maps each field (items.0.material) to what to change. |
PAYLOAD_TOO_LARGE | 413 | The request body is over 256 KiB — file bytes go to the signed upload URL, never into a JSON body. |
IDEMPOTENCY_KEY_REQUIRED | 422 | Send an Idempotency-Key header (1 to 255 characters of letters, digits and . _ : ~ -) with every order so a retry never creates a second one. |
IDEMPOTENCY_KEY_REUSED | 409 | This Idempotency-Key was already used for a different request — use a new key for a new request, or send the same request to get the same answer. |
IDEMPOTENCY_IN_PROGRESS | 409 | A request with this Idempotency-Key is still being processed — wait the seconds in Retry-After and send the same request again. |
NOT_FOUND | 404 | No such object in this environment — ids are per environment; a test key sees test objects only. |
Files
Uploads and the files an order points at.
| Code | Status | What it means and what to do |
|---|---|---|
FILE_REJECTED | 422 | The uploaded bytes failed verification — error.details.rejection_code says why; upload a corrected file. |
FILE_NOT_READY | 409 | The file is still uploading or was rejected — call complete and wait for status: ready, or upload a corrected file. |
FILE_IN_USE | 409 | An open order, a pending quote or a running price job still needs this file — error.details names it; delete the file once that has finished. |
Quotes and orders
Creating, pricing and cancelling.
| Code | Status | What it means and what to do |
|---|---|---|
MATERIAL_UNAVAILABLE | 422 | This material, nozzle or colour is outside your plan or out of stock for this run — pick one from GET /v1/materials. |
REFERENCE_TAKEN | 409 | An order with this reference already exists in this environment — error.details.order_id names it; use a new reference for a new order. |
CANNOT_CANCEL | 409 | Production has started on this order — write to us from the order page in your dashboard and we tell you what is still possible. |
ACCEPT_IN_PROGRESS | 409 | This order is being accepted right now — read it again in a moment. |
Webhooks
Endpoints and deliveries.
| Code | Status | What it means and what to do |
|---|---|---|
ENDPOINT_LIMIT | 409 | This environment already has the maximum number of webhook endpoints your plan allows — delete one, or ask us to raise the limit. |
ENDPOINT_URL_INVALID | 422 | The webhook URL must be HTTPS on port 443 or 8443, without credentials, on a public host that resolves. |
EVENT_TYPE_INVALID | 422 | One or more event types are outside the published list — use the names from the lifecycle page, or omit event_types to receive every type. |
ENDPOINT_DISABLED | 409 | This webhook endpoint is disabled — enable it with PATCH /v1/webhook-endpoints/{id} and {"enabled": true}, then try again. |
DELIVERY_IN_FLIGHT | 409 | This delivery is being attempted right now — wait for its outcome, then redeliver if needed. |
Account and agreement
Met in the dashboard or when a key is issued, rarely on /v1/*.
| Code | Status | What it means and what to do |
|---|---|---|
TERMS_REACCEPTANCE_REQUIRED | 409 | A new version of the terms is in force — accept it in your dashboard under Integrations → Agreement to keep ordering. |
AGREEMENT_REQUIRED | 409 | Accept the integration agreement and the data processing agreement in your dashboard first. |
AGREEMENT_NOT_COUNTERSIGNED | 409 | Live keys are issued once LayerCrew has countersigned your integration and data processing agreements — test keys work meanwhile. |
TERMS_UNAVAILABLE | 422 | Payment terms are set by your plan — orders are paid before production by default; ship-before-payment can be agreed instead. |
ORGANIZATION_ALREADY_REGISTERED | 409 | This company already has a partner account — ask its account owner for an invitation. |
EMAIL_TAKEN | 409 | This email already has a LayerCrew login — sign in and open Integrations to register your company. |
Validation details
422 VALIDATION_ERROR maps field paths to messages: items.0.material, delivery.phone, white_label.card_text. Array positions are zero-based. Fix the named fields and send again; the message says what to change. A file-level problem names the file: FILE_REJECTED carries details.rejection_code, FILE_IN_USE the id of the order or quote that needs it.
A 403 without JSON
Debugging a call
Every response carries X-Request-ID. Your request log — GET /v1/requests with from, to, status and route filters, GET /v1/requests/{request_id}, and the Requests page of your dashboard — lists every call made with your keys in the last 90 days: route, status, duration, error code and the id. Bodies are never stored. Quote the id when you write to us at hello@layercrew.com.