Error envelope

Every error response uses the same JSON shape, regardless of which endpoint or HTTP status code it came from.

{
  "error": "insufficient_scope",
  "message": "This key is missing required scope(s): orders:write.",
  "required_scopes": ["orders:write"]
}
HTTPerrorWhen
400invalid_requestBody or query failed Zod validation.
400invalid_idPath param wasn't a UUID.
400invalid_jsonBody wasn't parseable JSON.
401missing_tokenNo Authorization header.
401invalid_tokenBearer doesn't resolve to a key.
401revokedKey was revoked.
401expiredKey passed its expiry date.
403wrong_modeLive key on test store (or vice versa).
403insufficient_scopeKey's scopes don't cover the route.
403ip_not_allowedRequest IP not in the key's allowlist.
402pro_requiredAPI access needs Zillo Pro on the store. (Stores already using the API before Pro launched are unaffected.)
404not_foundResource id doesn't exist on this merchant.
409already_redeemed_or_voidedRedeem on something already done.
429rate_limitedQuota exceeded — see Retry-After.
500internalBug on our end. Include X-Request-Id in support tickets.