Skip to content

Handle errors ​

Every error, from /oauth/token and from /v1, has the same shape:

json
{
  "error": "invalid_request",
  "error_description": "shipping_type: \"pigeon\" is not a supported courier; use one of: ecopost, ems, flash, jt, kex, spx_dropoff, spx_pickup"
}

Branch on error, never on the text of error_description. The wording may improve over time, but the codes will not change. error_description is for people reading logs, and names the field at fault where there is one, e.g. products[1].qty.

Error codes ​

StatuserrorMeaningWhat to do
400invalid_requestSomething in the request is wrong. Sending an id as a number instead of a string lands here too.Fix the request. Do not retry it unchanged.
400unsupported_grant_typegrant_type was not client_credentials.Fix the request.
401invalid_clientToken request: credentials rejected.Check the Client ID and Secret. Do not retry in a loop: ten failures in five minutes block the client for 15 minutes.
401invalid_token/v1 call: the access token is missing, malformed or expired.Get a new token and retry once.
403access_deniedYour app may not do that for its store.Contact the store owner.
403quota_exceededThe store's subscription order quota is used up.Only the store owner can resolve it.
404not_foundNo such order or product, for you.Check the id and its scope.
413invalid_requestThe request body is over 1 MB.Send less.
429slow_downToken request rate limited.Wait for as long as Retry-After says, and cache your token.
500server_errorOur problem.Retry. With an external_order_id, retrying an order create is safe.

When to retry ​

  • 500 and network errors on order/create: retry with the same external_order_id. You get the order back whether or not the first attempt went through. See Retrying safely.
  • 401 invalid_token: get a new token, then retry the call once.
  • 429: wait for Retry-After, then retry.
  • Every other 4xx: do not retry. The same request will fail the same way.

Things we deliberately do not tell you ​

Some misses look the same on purpose, so the API cannot be used to probe for data that is not yours:

  • An address id that is not your store's returns 400 "no such address for this store", whether it does not exist at all or belongs to someone else. A sku behaves the same way.
  • Every miss on POST /v1/order/detail is the same 404: another store's order, another app's external id, a deleted order or an id that never existed.
  • Every miss on POST /v1/product/detail is the same 404 too.
  • Every failed token request is the same 401 invalid_client: an unknown client, a wrong secret or an expired app.

Asking us for help ​

Include the request id of the failing call: the X-Request-Id response header, which every response carries, errors included. Successful responses also repeat it in the body as request_id. With it we can find that exact request in our logs.

XSelly Open Platform API v1 · Webhooks v2