API conventions
Behaviour shared by every endpoint, documented once rather than repeated on each page.
Base URL and versioning
https://developer.allthe.com/api/v1
The version is in the path. We will not make a breaking change inside v1 — new fields may appear on responses and new optional fields may be accepted on requests, so parse tolerantly: ignore fields you do not recognise rather than rejecting the payload. Anything that would break an existing integration ships as v2.
All requests and responses are JSON (Content-Type: application/json), except the OAuth token and revoke endpoints, which take form encoding as the spec requires.
Pagination
Collection endpoints are cursor-paginated and share one envelope:
{
"data": [ ... ],
"has_more": true,
"next_cursor": "cmuk0y584000004l8x3h63vs6"
}
| Parameter | Description |
| --- | --- |
| limit | 1–100. Defaults to 25. Outside that range returns 422. |
| cursor | Pass the previous response's next_cursor. |
Loop until has_more is false:
cursor=""
while :; do
page=$(curl -s "$ALLTHE_API/products?limit=100${cursor:+&cursor=$cursor}" \
-H "Authorization: Bearer $ALLTHE_TOKEN")
echo "$page" | jq -c '.data[]'
[ "$(echo "$page" | jq -r '.has_more')" = "true" ] || break
cursor=$(echo "$page" | jq -r '.next_cursor')
done
Cursors are opaque record ids — do not construct or parse them. Do not use next_cursor as a "what changed since" marker: it points at a position in the current ordering, not a moment in time. For change notification, use webhooks.
Identifiers
| Kind | Looks like | Notes |
| --- | --- | --- |
| Resource id | cmuk0y584000004l8x3h63vs6 | Opaque, globally unique, stable. Compare for equality only. |
| Order reference | SMP-ALGQS4ATP | Human-facing. Shown on paperwork and accepted wherever an order id is. |
| Variant SKU | YP023BKBK | Identifies a colour/size on a base product. |
| external_reference | yours | Your own order id, stored and echoed back. Not unique-checked by us. |
Order endpoints accept either the resource id or the reference in the path, so GET /orders/SMP-ALGQS4ATP and GET /orders/cmuk… both work.
Money
- Every amount is a number in major units —
15.98means £15.98. Never minor units, never a string. currencyisGBPthroughout. There is no multi-currency support today.- Amounts are rounded to 2 decimal places at source, so what you see is what is charged.
- Prices you are charged are net of VAT, with
vat_amountreported separately. Do not infer VAT by subtraction; read the field.
Dates
All timestamps are ISO 8601 with a Z suffix, in UTC: 2026-09-27T21:52:40.361Z. There are no local-time or offset-bearing fields anywhere in the API.
Retries and duplicate orders
external_reference is your idempotency key. Send one on every POST /orders and a repeated call with the same value short-circuits: it returns the order that already exists rather than creating a second one.
This matters because order creation does real work — pricing, charging, artwork intake — and can legitimately take several seconds. Without an external_reference, a request that times out leaves you unable to tell whether the order was placed, and retrying can place it twice and charge you twice. With one, the retry is safe.
{ "external_reference": "your-system-order-4821", "items": [ ... ] }
Use an id from your own system that is stable across retries of the same logical order — not a random value generated per attempt, which defeats the point entirely.
Make it unique to you, not just unique within your system.
external_referenceis currently unique across the whole platform, not per account. If another customer has already used the value you send, you get409 duplicate_external_referencerather than an idempotent hit — so a bare counter like1001can collide with somebody else's order.Prefix it with something of your own:
acme-1001, or a UUID. We deliberately return a generic error in that case and reveal nothing about the existing order, so a collision is indistinguishable from any other rejection — you cannot debug your way past it, only avoid it.
Also safe to repeat:
- Reads (
GET) andPOST /orders/estimatehave no side effects at all. - Cancelling twice returns
200withalready_cancelled: true, so a retry after a dropped response is not an error.
Errors
Every error shares one shape, and the HTTP status tells you whether retrying can help. See Errors & rate limits for the full table, the rate-limit headers, and back-off guidance.