Error codes
A failed call uses the same envelope as a successful one: read the HTTP status code, then read response for a message describing what went wrong. Messages are stable English sentences you can log and show to an operator, but branch on the status code.
{
"code": 403,
"title": "Forbidden",
"response": "The API key is missing the required scope: order:write"
} | Field | Type | Description |
|---|---|---|
code | integer | The HTTP status code, repeated in the body. |
title | string | The short status label. |
response | string | What went wrong. |
Note — The
404for an unknown path and the429described below are answered before your request reaches an endpoint; in those two answerscodeis a string ("404","429"). Rely on the HTTP status code rather than on the type of that field.
Status codes
| Code | Status | Description |
|---|---|---|
| 200 | OK | A read succeeded, or an import accepted at least one item. Read the report line by line: some items may still be refused, and check the dry_run field it returns. |
| 301 | Moved Permanently | You called http://. Repeat the call on https://. |
| 400 | Bad Request | A read named no record (the read parameter is missing), or the request body is not valid JSON. |
| 401 | Unauthorized | No key was sent, the Authorization header does not start with Bearer , or the key has expired. |
| 403 | Forbidden | The key is unknown or disabled, it does not hold the scope the call needs, or it was used for another shop. |
| 404 | Not Found | The record does not exist in your shop — including a record that belongs to another shop — or the path does not exist. |
| 409 | Conflict | The same record is already being imported by another request, or a voucher code is already taken. |
| 413 | Payload Too Large | The request body is larger than 200,000 bytes. Send smaller batches. |
| 422 | Unprocessable Entity | The whole batch was refused: every item was refused, items is missing or empty, or the batch is over the resource's limit. |
| 429 | Too Many Requests | Too many requests in a short time. Wait for the number of seconds given in the Retry-After header, then retry. |
| 503 | Service Unavailable | The service is temporarily unable to handle this resource for your shop. Retry later. |
Authentication failures
These are checked before anything else, on every path.
| Code | Message | Cause |
|---|---|---|
| 401 | No valid API key provided. | The Authorization header is missing, does not start with Bearer , or does not carry a shop key. |
| 401 | The API key has expired. | The key had an expiry date and it has passed. A key with no expiry date never raises this. |
| 403 | The API key doesn't have permissions to perform the request. | The key is unknown or disabled, or its shop is no longer active. |
Note — An unknown key and a disabled key give the same
403with the same message, on purpose: the API never confirms whether a key exists.
Scope and shop failures
| Code | Message | Cause |
|---|---|---|
| 403 | The API key is missing the required scope: <scope> | The key holds neither *, nor <resource>:*, nor the scope named. Add the scope to the key, or stop calling that endpoint. |
| 403 | This API key can only read and write its own project. | The request named a project other than the key's own shop. Remove the project field: the key already designates your shop. |
| 403 | This API key is not attached to a project. | The key is not linked to a shop. Use a key created for your shop. |
Request failures
| Code | Message | Cause |
|---|---|---|
| 400 | Invalid JSON. | The body is not parseable JSON, or is a JSON value that is not an object. |
| 400 | Missing required parameter: <name>. | A read gave neither the record's key nor its id. The topic of each resource lists its read parameters. |
| 400 | Name the customer to read: … / Name the payment to read: … | The same case on the customer and payment reads. |
| 413 | Request body too large. | The body exceeded 200,000 bytes. |
| 422 | Missing required field: items (…). | The body has no items list, or items is not a list. The wording varies slightly from one resource to another. |
| 422 | items is empty. | The items list holds no item. |
| 422 | A batch carries at most <limit> <records>. | The batch is over the resource's limit, given in each endpoint table. Split it. |
| 422 | The parameters were valid but the request failed. | The method is not supported on that path. Only GET and POST are served. |
Not found
| Code | Message | Cause |
|---|---|---|
| 404 | <Record> not found. | No record of your shop matches the key or id you read, for example Order not found. A record of another shop answers the same way. Check the spelling of the reference. |
| 404 | The requested resource was not found. | The path itself does not exist. Check it against the endpoint tables. |
Refusals inside a batch
An import checks each item on its own. An item that fails a check is reported in the response's data list with "action": "refused", the status code and label of the refusal in code and title, and what to correct in reason. The other items of the batch carry on.
{
"index": 3,
"external_id": "SHP-20931",
"action": "refused",
"id": null,
"code": 409,
"title": "Conflict",
"reason": "Another import is already writing this shipment.",
"notice": []
} code in a refused item | Meaning | What to do |
|---|---|---|
| 422 | A value is invalid or a required field is missing; reason names the field. | Correct the item and send it again. |
| 404 | The item refers to a record that is not in your shop, such as an order whose customer was not imported. | Import the record it refers to first. |
| 409 | Another request is importing the same record right now, or a voucher code is already held by another code. | Retry the item later, or choose another code. |
| 500 | The item could not be saved. | Send the item again; the import is safe to replay. |
So a batch answers:
200when at least one item was created, updated or left unchanged — even if others were refused;422when every item was refused, with the same report so you can see why.
Retrying safely
A 429, a 503, a dropped connection or a refused item with code 409 or 500 can all be retried. Every import is recognised record by record, so sending the same batch again never creates a duplicate: records already saved come back as unchanged. Wait a few seconds between retries, and honour Retry-After when it is present.