Success
{ "success": true, "data": { "id": "cm3o7rd0e0001h2j3k4l5m6n" } }
List endpoints add meta (see Pagination):
{ "success": true, "data": [{ "id": "cm3o7rd0e0001h2j3k4l5m6n" }], "meta": { "total": 120, "page": 1, "limit": 50, "pageCount": 3 } }
A call that creates something returns 201 with the new resource. Other successful calls return 200. Writes return the resource as it is after the change, exactly as the matching GET returns it where there is one (for example POST /v1/sku-mappings returns a mapping summary).
Errors
{ "success": false, "error": "This shipment was updated. Please review it again.", "code": "shipment_changed" }
Validation errors add details, one entry per problem:
{ "success": false, "error": "Quantities must be at least 1.", "code": "validation_failed", "details": [{ "path": "lines.0.qty", "message": "Quantities must be at least 1." }] }
See Errors.
Headers on every response
| Header | Meaning |
|---|---|
X-Request-Id |
A unique id for this request. Quote it when you contact support. |
Cache-Control: no-store |
Responses are never cached. |
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset |
Your current rate-limit window, except 403 api_not_enabled, 403 account_action_required and unknown paths. See Rate limits. |
Retry-After |
On 429 only: seconds to wait. |
Idempotency-Replayed: true |
On a replayed response only. See Idempotency. |
The public OpenAPI document is the one exception: it may be cached and has no X-Request-Id.
Sending requests
- Send request bodies as JSON with
Content-Type: application/json. Another content type returns415 unsupported_media_type; JSON that doesn't parse returns400 invalid_json. - A body can be at most 1 MB (
413 payload_too_large) and nested at most 64 levels deep. - Text can't contain NUL characters (
\u0000). - On endpoints that take a body, an empty body returns
422 validation_failed, except onPOST /v1/orders/previewandPOST /v1/orders/{id}/cancel, where an empty body counts as{}. Endpoints that take no body, such asPOST /v1/shipments/{id}/cancel, ignore it. - Fields the endpoint doesn't know are ignored. Text values are trimmed, and control characters are removed from most of them.
- Send each query parameter at most once: a repeated parameter returns
422 validation_failedon every endpoint. Unknown query parameters are ignored. - In a query string, encode
+as%2B(for example in a time zone offset); otherwise it arrives as a space.
Data formats
| Kind | Format |
|---|---|
| Money | Whole numbers of the smallest unit, in fields ending in Cents, with the currency in currency. Amounts are US dollars (cents), except the supplier reference price of a product, which is Chinese yuan (fen). |
| Times | ISO 8601 in UTC, for example 2026-11-09T02:00:00.000Z. |
| Dates | Fields that are only a date (payment days, neededBy) are YYYY-MM-DD in China time (UTC+8). |
| Codes | status, kind and similar fields are stable uppercase codes such as SHIPPED. |
| Labels | Fields ending in Label are English text for display. They may change; don't use them in program logic. |
| Ids | Strings of letters, digits, _ and -. Treat them as opaque. An id in a path that isn't in this format returns 404. |
| Images and files | Not included in responses. |
| Empty values | Text without a value is "". Values that don't exist yet are null, as each field says. |
HTTP status codes
| Status | Meaning |
|---|---|
| 200 / 201 | Success / created |
| 400 | Invalid JSON or a bad Idempotency-Key |
| 401 | Missing or invalid API key |
| 403 | API access off, an account step needed, a missing permission, or the account on hold |
| 404 | The resource doesn't exist or isn't yours (we don't tell the two apart), or the path doesn't exist |
| 405 | The path exists but not with this method; see Allow |
| 409 | The current state doesn't allow it, or the data changed; read it again and decide |
| 413 / 415 | Body over 1 MB / not JSON |
| 422 | The input or a business rule was rejected |
| 429 | Rate limited; wait for Retry-After |
| 500 | Unexpected error; quote X-Request-Id |