Errors and retries
Recognize failures and recover without duplicating resources or charges.
Read the response
API errors use an HTTP status and a JSON body with code, message and optional details. Branch on code; message is explanatory and can change. A missing path ID returns 404 with a resource_not_found code, such as model_not_found. A missing body reference returns 400 with that resource code and details[].field naming the reference.
Example error
json
{
"code": "invalid_argument",
"message": "Supply a five-digit ZIP code.",
"details": [
{
"field": "shipping_address.postal_code",
"message": "Supply a five-digit ZIP code."
}
]
}Before parsing JSON, check Content-Type. A network failure has no HTTP response; CDN or proxy rejections can return HTML, text or an empty body. Direct storage errors use S3 XML. Preserve the HTTP status and a sanitized response for support, without API keys, upload grants or payment URLs.
Choose when to retry
| Outcome | Action |
|---|---|
| 400 / 401 / 403 / 404 / 412 / 413 / 415 | Resolve the indicated problem before retrying. See the code index below. |
| 409 idempotency_request_in_progress | Wait Retry-After, then retry the same key and body. |
| 409 model_not_ready / model_repair_estimate_pending | Wait until the model status is ready (poll or model.ready), then retry the same request. |
| Other 409 | Resolve the indicated conflict before retrying. |
| 429 | Wait at least Retry-After seconds (currently 60); check account quotas. |
| Network failure / 500 / 503 | Honor Retry-After on dependency 503s, then use bounded exponential backoff. Reuse the saved key and body for POST retries. |
| HTTP 200 with a failed workflow | Read the resource’s error; repeating GET or pricing does not restart processing. |
Error code index
| HTTP | Code | What to do |
|---|---|---|
| 400 Bad Request | file_not_found | No file with this ID exists in the account, or it expired before a model used it. Register and upload the file again. |
| 400 Bad Request | file_not_ready | The file bytes have not finished uploading, or their size differs from the registration. Finish the upload, then retry. |
| 400 Bad Request | file_too_large | The file is over the upload limit. Reduce it before you register it. |
| 400 Bad Request | filename_required | The file registration has no filename. Send the original filename with its extension. |
| 400 Bad Request | invalid_argument | A field, query parameter or header is invalid. Fix the field named in details, then send the request again. |
| 400 Bad Request | invalid_file_size | size_bytes is not a positive whole number. Send the file's exact byte count. |
| 400 Bad Request, 404 Not Found | model_not_found | No model with this ID exists in the account, or it was deleted. Check the ID. |
| 400 Bad Request | payment_method_not_found | No saved card with this ID is approved for the business. Choose a card from List payment methods. |
| 400 Bad Request | pricing_unavailable | The model cannot be priced, usually because processing failed. Read the model's status_reasons; repeating the request does not rerun inspection. |
| 400 Bad Request, 404 Not Found | quote_not_found | No quote with this ID exists in the account, or it is past retention. Check the ID. |
| 400 Bad Request | shipping_unavailable | No shipping service accepts this destination or basket. Check the address, or split an oversized basket. |
| 400 Bad Request | size_bytes_required | The file registration has no size_bytes. Send the file's exact byte count. |
| 400 Bad Request | unsupported_file_extension | The file type is not supported. Use a GLB, OBJ or ZIP file. |
| 401 Unauthorized | unauthenticated | The API key is missing, invalid or revoked. Send a valid business API key in Authorization: Bearer. |
| 403 Forbidden | permission_denied | The key lacks the endpoint's scope, or payments lack spending consent. Check the scope listed on the endpoint. |
| 404 Not Found | not_found | Any route (HTTP 404): no API route matches the path. Check the method, path and version prefix. |
| 404 Not Found | order_not_found | No order with this ID exists in the account. Check the ID. |
| 405 Method Not Allowed | method_not_allowed | Any route (HTTP 405): the route does not accept this HTTP method. Use a method listed in the reference. |
| 406 Not Acceptable | not_acceptable | Any route (HTTP 406): the Accept header excludes application/json. Accept application/json. |
| 409 Conflict | cancellation_unavailable | The order can no longer be cancelled, or other orders rely on its paid repair. Retrieve it to see its status. |
| 409 Conflict | idempotency_key_reused | This Idempotency-Key was already used with a different body. Retry the original body, or use a new key for a new operation. |
| 409 Conflict | idempotency_request_in_progress | A request with this Idempotency-Key is still running. Wait Retry-After seconds, then retry the same key and body. |
| 409 Conflict | invoice_unavailable | The order has no paid invoice yet. Pay the order, then download the invoice. |
| 409 Conflict | model_in_use | An order uses this model, so it cannot be deleted. |
| 409 Conflict | model_not_ready | The model is still processing. Wait until its status is ready, then retry. |
| 409 Conflict | model_repair_estimate_pending | The repair fee is still being estimated. Wait until the model status is ready, then retry. |
| 409 Conflict | payment_in_progress | A payment with a different method is still in progress. Wait for its result before you try another method. |
| 409 Conflict | payment_method_unavailable | The saved card cannot be charged, for example because its billing address is invalid. Update it, then retry. |
| 409 Conflict | payment_reconciliation_required | The payment outcome is unknown and needs review. Contact support with the order ID; do not pay again. |
| 409 Conflict | payment_unavailable | The order cannot take a payment now. Retrieve it and check its status and expires_at. |
| 409 Conflict | quote_accepted | An order already uses this quote. Find it with List orders and quote_id; do not create another. |
| 409 Conflict | quote_expired | The quote is older than 30 minutes. Create a new quote, then order it with a new Idempotency-Key. |
| 409 Conflict | quote_unavailable | A model, its price or its repair changed after quoting. Create and review a new quote. |
| 409 Conflict | repair_payment_pending | Another order has an unpaid repair fee for this file revision. Pay or cancel that order, then quote again. |
| 412 Precondition Failed | precondition_failed | The model changed since you read its ETag. Read it again, review the change, then retry with the new ETag in If-Match. |
| 413 Content Too Large | request_too_large | The JSON body is over this endpoint's size limit. Send a smaller body. |
| 415 Unsupported Media Type | unsupported_media_type | The body is not JSON. Send Content-Type: application/json. |
| 429 Too Many Requests | resource_exhausted | A rate or account limit was reached. Wait at least Retry-After seconds, then retry. |
| 500 Internal Server Error | internal | The server failed unexpectedly. Retry with backoff; contact support with X-Request-ID if it persists. |
| 503 Service Unavailable | shipping_rates_unavailable | Shipping rates could not be fetched. Retry with backoff and the same Idempotency-Key. |
| 503 Service Unavailable | unavailable | A required service is briefly unavailable. Retry with backoff, reusing the same Idempotency-Key. |
Retry a storage upload
Retry transfer with the same signed instructions while valid. If they expire, register a new file with a new key. Replaying the old key does not renew permission. Storage success is HTTP 204 with no body.
Contact support
Send your own X-Request-ID using 8–64 ASCII letters, digits or hyphens, or let the API generate one. Do not include secrets or account IDs in that value.
API v1 preview