Skip to content
Docs

01API

API v1For developers

Errors

Every error has a status and a body. The code never changes within version 1; the message is for people and may be reworded.

JSON
{
  "error": {
    "code": "missing_permission",
    "message": "This key cannot do that. It needs the orders:write permission.",
    "request_id": "req_a1B2c3D4e5F6",
    "required": "orders:write"
  }
}
FieldMeaning
codeA stable word. Branch on this.
messageA plain sentence. Show it to a person; do not parse it.
request_idAlso in the X-Request-Id header of every response. Quote it to support and the call can be found.
fieldsFor bad_request about a body: [{ "field": "lines[0].quantity", "message": "must be a whole number" }]
requiredOnly with missing_permission: the permission the call needed.
lockOnly with line_locked: why (shelf, ready, failed, placed).

The three catalog routes

GET /products, GET /products/{key} and GET /staff/products/{key} were the first routes of the API and keep their original bodies, so existing clients keep working: error is a bare word (unauthorized, forbidden, not_found, rate_limited, bad_request, setting_up, unavailable), and they add error_detail: { code, message } with the same codes as below. Their request id is in the X-Request-Id header only. A client that handles both reads error.code ?? error_detail.code ?? error.

Codes

StatuscodeMeaning
400bad_requestA parameter or body is wrong; fields says which
400bad_cursorThe cursor is malformed or belongs to another request. Start again without it.
400card_data_rejectedA body field is named like card data. Payment stays with the store; remove it.
400idempotency_requiredThis call needs an Idempotency-Key
401missing_keyNo Authorization: Bearer header
401bad_keyUnknown or revoked key, or a suspended store
403missing_permissionThe key lacks a permission; required names it
403wrong_scopeA key of the wrong kind for the route
403server_side_onlyA browser's request on a server-to-server route
403plan_not_allowedThe store's plan does not include this
403billing_read_onlyA write while the store's account is read-only
404not_foundNo such thing in this store
409idempotency_conflictThe Idempotency-Key was used for a different request
409intake_conflictAn order with this intake_ref was sent with different contents
409po_conflictThe dealer_po is used by another order
409already_matchedThe order is already matched to a different store order
409store_order_number_in_useAnother order has this store order number
409already_shippedShipped already, with different tracking
409order_cancelled, order_closedThe order is cancelled or closed, so this cannot be done
409line_lockedThe line is on a distributor order that was sent, is ready or failed, or is filled from the shelf; lock and the message say why
409not_a_transferReady, ship and deliver apply to an order that ships to an FFL
409not_a_draftOnly a distributor-order draft can change
409fastbound_managedThe item comes from FastBound; change it in FastBound
409invalid_stateThe thing is in a state that does not allow this; the message says how
413too_largeThe body or batch is over the limit
422ffl_not_allowedThe chosen FFL cannot be used (one answer for unknown, hidden, expired and blocked)
429rate_limitedOver the limit; wait Retry-After seconds
503setting_upThe store's database update is not finished. Try again later.
503unavailableA fault on Rollmark's side. Retry with the same Idempotency-Key.

What to do

  • 4xx: do not send the same request again; fix it. (409s that say a state, 429 and 503 are the exceptions: read the code.)
  • 429 and 5xx: wait (Retry-After if given, else back off), then send it again with the same Idempotency-Key. It is safe.
  • Log request_id with every failure.
Rollmark is made by Illumina Studios LLC. It was built at Ironcrest Arms LLC. Sample dealers, license numbers and costs in these docs are made up. Questions: [email protected].