Getting started

Errors

Conventional HTTP status codes, and one envelope for every failure — so you can write a single error handler and be done.

JSON — error envelope
{
  "error": {
    "code": 400,
    "message": "Validation failed.",
    "details": {
      "items": {
        "0": {
          "quantity": ["Must be greater than zero."]
        }
      }
    }
  }
}

Status codes

400

Bad request

Validation failed. `details` names the offending fields, nested to match your payload.

Fix the payload. Retrying unchanged will fail again.

401

Unauthenticated

The access token is missing, malformed, or expired.

Refresh the token and retry once.

403

Forbidden

You are authenticated but not allowed: your role lacks the permission, or X-Shop-Id names a shop this credential cannot reach.

Do not retry. Fix the permission or the shop id.

404

Not found

No such record *in this shop*. A valid id from another shop is a 404 here, not a 403 — we do not confirm that other shops' records exist.

Do not retry.

409

Conflict

The operation is valid but the world disagrees — most often insufficient stock.

Re-read the current state before retrying.

429

Rate limited

1,000 requests per hour per shop. A Retry-After header tells you how many seconds to wait.

Back off for Retry-After seconds, then retry.

500 / 503

Server error

Something broke on our side, or a dependency is unavailable.

Retry with exponential backoff. If the write was idempotent, retrying is safe.

Insufficient stock

The one you will hit in the wild. A sale is rejected in full — we never sell you part of a basket — and nothing is written: no stock moved, no payment taken, no ledger entry.

JSON — 409
{
  "error": {
    "code": 409,
    "message": "Need 5 but only 2 available for NES-200 at Main Store.",
    "details": {
      "variant": "NES-200",
      "requested": "5.000",
      "available": "2.000"
    }
  }
}