Handling failures and retries
Checkout is a write API, so knowing which failures are retryable matters more than usual. This page lists every error you can get, what causes it, and what to do.
All errors use RFC 9457 Problem Details with a
stable machine-readable code and a traceId. Branch on code and status, never on
detail — detail is human-readable prose and may be reworded.
At a glance
Section titled “At a glance”| Status | code |
Cause | Retry? |
|---|---|---|---|
400 |
ERR_VALIDATION_0001 |
The request body is wrong | No — fix the request |
400 |
ERR_VALIDATION_0001 on DeliveryOptionId |
The option id is not on this checkout’s menu | Yes — re-read the menu, resubmit |
401 |
— | Missing, malformed, or expired token | Yes — get a new token |
403 |
ERR_ACCESS |
Not entitled to place orders for this soldTo |
No — contact your Account Manager |
404 |
ERR_NOTFOUND |
No checkout with that id | No — check the id |
422 |
ERR_PROCESSING |
Draft expired | No — create a new checkout |
422 |
ERR_PROCESSING |
Submit already in progress | Yes — wait, then retry the same id |
422 |
ERR_PROCESSING |
Placement rejected downstream | No — inspect detail, contact support |
500 |
InternalServerError |
Unexpected server error | Yes — with backoff |
400 — the create body failed validation
Section titled “400 — the create body failed validation”All broken rules come back at once, so fix them in one pass rather than resubmitting repeatedly.
{ "errors": [ { "fieldName": "SoldTo.CustomerId", "message": "CustomerId must be a valid GUID." }, { "fieldName": "OrderLines[0].Quantity", "message": "Quantity must be greater than zero." }, { "fieldName": "OrderLines[0].MaterialId.Value", "message": "MaterialId value is required." }, { "fieldName": "OrderLines[0].MaterialId.Type", "message": "Only the 'MaterialNumber' or 'KomplettPcConfigurationId' material type is supported." }, { "fieldName": "Delivery.DeliveryAddress.AddressLine1", "message": "AddressLine1 cannot be null or empty." }, { "fieldName": "Delivery.DeliveryAddress.PostCode", "message": "PostCode cannot be null or empty." }, { "fieldName": "Delivery.DeliveryAddress.City", "message": "City cannot be null or empty." } ], "code": "ERR_VALIDATION_0001", "traceId": "0HNNJ344GRP52:00000005", "type": "https://<store-url>/swagger#Validation", "title": "Validation Failed", "status": 400, "detail": "Some fields have validation errors", "instance": "/checkout/v1/create", "extensions": {}}fieldName is the dotted path into your request, with array indexes — map it straight back to
the offending field. Not retryable until the body changes.
Watch out: only
addressLine1,postCodeandcityare enforced on the address. Omittingname,countryor
400 — the delivery option is not valid for this checkout
Section titled “400 — the delivery option is not valid for this checkout”{ "errors": [ { "fieldName": "DeliveryOptionId", "message": "The selected delivery option is not valid for this checkout." } ], "code": "ERR_VALIDATION_0001", "traceId": "0HNNJLGM0FAKD:00000003", "type": "https://<store-url>/swagger#Validation", "title": "Validation Failed", "status": 400, "detail": "Some fields have validation errors", "instance": "/checkout/v1/submit", "extensions": {}}Option ids belong to exactly one checkout and do not survive into another. Retryable: re-read
the menu with GET /checkout/v1/{checkoutId}, pick an id from that response, and submit again.
The draft is untouched and still submittable.
404 — no such checkout
Section titled “404 — no such checkout”{ "code": "ERR_NOTFOUND", "traceId": "0HNNJ344GRP52:00000004", "type": "https://<store-url>/swagger#NotFound", "title": "Not Found", "status": 404, "detail": "Checkout not found.", "instance": "/checkout/v1/doesnotexist000000000000000000", "extensions": {}}Returned by both GET and submit. Not retryable — the id is wrong, or was never created.
422 — the draft expired
Section titled “422 — the draft expired”{ "code": "ERR_PROCESSING", "traceId": "0HNNJLGM0FAKD:00000002", "type": "https://<store-url>/swagger#Processing", "title": "Unprocessable Request", "status": 422, "detail": "Checkout has expired.", "instance": "/checkout/v1/submit", "extensions": {}}Drafts are short-lived and this is permanent — resubmitting the same id will never succeed.
Recovery: create a new checkout from the same input and submit that one. Prevention: create the draft when the buyer is ready to commit, not while they are still filling in a form.
422 — submission already in progress
Section titled “422 — submission already in progress”{ "code": "ERR_PROCESSING", "traceId": "0HNNJLGM0FAKD:00000009", "type": "https://<store-url>/swagger#Processing", "title": "Unprocessable Request", "status": 422, "detail": "Checkout submission is already in progress.", "instance": "/checkout/v1/submit", "extensions": {}}Your earlier submit is still running. Do not create a second checkout — that is how duplicate
orders happen. Wait briefly, then either retry the same checkoutId or GET it and read
status.
Idempotency
Section titled “Idempotency”Submitting the same checkoutId more than once never places a second order.
- While the first submit is in flight →
422, “already in progress”. - Once the order is placed →
204again, an idempotent replay.
So a lost response is always safe to retry with the same id. Treat 204 as the single source of
truth that the order is placed, and never treat a timeout as failure without checking.
Reporting a problem
Section titled “Reporting a problem”Every response carries an X-Trace-Id header, echoed as traceId in error bodies. Quote it
when contacting support — it is what lets us find your exact request in our logs.