Using the API

Errors

One error envelope and a small published code set, on every endpoint. Branch on code, never on message.

The error envelope

Every failure, on every endpoint, is:

{
  "error": {
    "code": "not_found",
    "message": "no such product in this account",
    "request_id": "req_8f3a…"
  }
}

Published error codes

The code set only ever grows. Treat an unknown code as a generic failure of its HTTP status — the versioning promise guarantees no existing code changes meaning.

CodeStatusMeaning
unauthorized401No credential, or one that no longer resolves (e.g. a revoked key).
forbidden403The credential has no authority here — a browser/Shopify session on the public API, or an API key outside /api/v1.
forbidden_scope403The key is valid but lacks the route's required scope — a read-only key on a pim:write endpoint, or any key at all on the reserved pim:delete endpoint.
not_found404No such record in this account. Another account's record, an id of a different entity kind, and an entity with no version on the requested store all answer identically.
validation_failed400A parameter or body was understood but rejected — a malformed updated_since, a foreign cursor, an unknown status or scan dimension.
rate_limited429Over the per-key or per-account minute budget. Wait Retry-After seconds — budgets and headers on Rate limits.
pim_locked423Writes are held while an import or store refresh is being reconciled. Reachable since the data-health write endpoints shipped — retry after the merchant finishes the review.
conflict409A stale draft_revision on a write. Part of v1's write surface; the current data-health batches re-verify state server-side instead of taking a draft_revision, so today you are most likely to meet it on future entity writes.
internal_error5xxSomething failed on our side. Safe to retry with backoff; report persistent ones with the request_id.

When Shopify is the failure: 502

The sales-channel reads query Shopify live rather than Peak PIM's own rows. They are the only endpoints that can answer 502 — the store could not be reached — and they carry Shopify's latency rather than ours. A 502 uses the same envelope; treat it like a 5xx and retry with backoff.

Correlate with X-Request-Id

Every response — success or failure — carries an X-Request-Id header, and every error body repeats it as request_id. Log it alongside your own request logging, and quote it when reporting a problem: it lets support find the exact request on our side.

Rate-limit budgets moved.

The per-key and per-account budgets, the X-RateLimit-* headers, and the full retry guidance now live on Rate limits.