Skip to content

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.

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

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, postCode and city are enforced on the address. Omitting name, country or email passes validation but can still be rejected later. Always send a complete address.


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.


{
"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.


{
"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.


{
"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.


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 → 204 again, 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.

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.