Errors
When a request fails, the body is an error envelope:
{ "error": { "code": "NOT_FOUND", "message": "Purchase order not found", "retryable": false, "requestId": "0f8c…" }}Retryable errors also include retryAfterMs and a Retry-After response header
(in seconds).
Status codes
Section titled “Status codes”code | HTTP | Meaning | Retry-After |
|---|---|---|---|
UNAUTHORIZED | 401 | Missing, invalid, or revoked token | — |
PLAN_REQUIRED | 403 | The shop isn’t on the Elevate plan (the REST API is Elevate-only) | — |
FORBIDDEN_SCOPE | 403 | The token’s scope can’t access this resource | — |
INVALID_INPUT | 400 | A bad query parameter (the message names the field) | — |
NOT_FOUND | 404 | Unknown path, or the id doesn’t exist | — |
RATE_LIMITED | 429 | Per-shop rate limit reached | ✓ |
DO_OVERLOADED | 503 | The shop’s data store is busy | ✓ |
DO_UNAVAILABLE | 503 | The data store is temporarily unavailable | ✓ |
UPSTREAM_SHOPIFY | 502 | A Shopify-facing dependency failed | if present |
TIMEOUT | 504 | The request timed out | if present |
OUTPUT_TOO_LARGE | 413 | The response exceeded the size cap | — |
INTERNAL | 500 | An unexpected error | — |
A non-GET method returns 405 (METHOD_NOT_ALLOWED).
Handling retries
Section titled “Handling retries”On 429 / 503, wait Retry-After seconds (or retryAfterMs) and retry the same
request. Don’t fan out parallel requests against one shop — the data store is
single-threaded per shop, so concurrency doesn’t go faster and can trip the rate limit.