Errors
The error envelope
Section titled “The error envelope”Every app route — everything you call with an app token — reports a failure in one shape:
{ "error": { "code": "missing_scope", "message": "This operation requires the write_products scope.", "scope": "write_products", "request_id": "0HN7…" }}| Field | Meaning |
|---|---|
code |
A stable, machine-readable identifier. Branch on this, never on message. |
message |
A human-readable explanation. Its wording can change; do not parse it. |
scope |
Only on missing_scope: the scope the operation needs. |
request_id |
Quote it when you contact support — it finds the request in our logs. |
The one exception is the token endpoint, which follows RFC 6749 instead:
{"error":"invalid_client","error_description":"…"}. See credentials & tokens.
Some routes also keep their own typed refusal body where the refusal carries detail an envelope cannot — for
example the metaobject bulk request-level refusals ({ "code", "error" }) and their
per-row results. Those are documented on the route’s page.
Error codes
Section titled “Error codes”| Status | code |
Meaning | What to do |
|---|---|---|---|
400 |
invalid_request |
The request is malformed or breaks a documented limit. | Fix the request. Do not retry unchanged. |
400 |
idempotency_key_required |
The route requires an Idempotency-Key and none (or a blank one) was sent. |
Send one. See idempotency. |
401 |
invalid_token |
Token missing, unknown, expired or revoked, or the installation was removed or the app suspended. Carries WWW-Authenticate: Bearer error="invalid_token". |
Get a new token once. If that fails too, stop and alert — the installation is gone or disabled. |
401 |
tenant_not_active |
The store itself is not active. | Do not retry. Tell the merchant. |
403 |
wrong_store |
The token was issued for a different store than the domain you called. | Call the store the token belongs to, or exchange credentials on this store’s domain. |
403 |
missing_scope |
Your installation lacks the scope this operation requires; scope names it. Carries WWW-Authenticate: Bearer error="insufficient_scope". |
Ask the merchant to grant it. |
404 |
not_found |
The record does not exist in this store. A record belonging to another store is always 404, never 403. |
— |
409 |
conflict |
The request conflicts with the current state of the record. | Re-read the record and decide. |
409 |
idempotency_in_progress |
An idempotent request with this key is still running. Carries Retry-After: 1. |
Wait, then retry with the same key. |
409 |
idempotency_unreplayable |
The original request succeeded, but its response was too large to store. | Do not retry; the work was done. |
413 |
payload_too_large |
The body exceeds the route’s size limit. | Split the request. |
415 |
unsupported_media_type |
The Content-Type is not one the route accepts. |
Send application/json. |
422 |
validation_failed |
The body is well-formed but a value is refused. | Fix the value; message says which. |
422 |
idempotency_key_reuse |
This Idempotency-Key was already used with a different request. |
Use a new key for a new request. |
429 |
rate_limited |
The installation’s request budget is spent. Carries Retry-After. |
Wait Retry-After seconds. See rate limits. |
503 |
provider_unavailable |
A service the operation depends on is unavailable. | Retry with backoff. |
5xx |
internal_error |
A platform fault. Internals are never included. | Retry with backoff; idempotent writes are safe to retry. |
Partial success is normal for batch routes
Section titled “Partial success is normal for batch routes”Batch routes — bulk product updates and media imports — answer
200 when the request was valid, and report each row separately. A 200 with failed: 3 means three rows
did not apply. Always read the per-row status.