← Documentation

API Error Codes

Every v1 API error carries a stable machine-readable code. Branch on the code — never on the message.

The error shape

Errors return a non-2xx HTTP status and a JSON body with a human-readable error message and a stable code:

{
  "error": "No barcodes remaining in this pass's pool.",
  "code": "pool_exhausted"
}

The code values below are a contract: they never change meaning and are only ever added to. The error strings are for humans and may be reworded — don't match on them. Some errors carry extra context fields (e.g. matchCount on ambiguous_barcode, retryable: true on retry-safe 500s).

Codes

CodeStatusMeaning
missing_authorization401No Bearer token in the Authorization header.
invalid_api_key401The API key is unknown or has been revoked.
forbidden403The resource exists but belongs to another account.
invalid_request400Malformed body or parameters — the error message says exactly what to fix.
pass_not_found404 / 400No pass with that ID on your account (400 from Process Order when the passId is inactive).
instance_not_found404No pass instance matches that instanceId or barcode.
holder_not_found404No loyalty holder matches that identifier.
pass_archived400Archived passes can't issue new instances.
fields_not_editable400This pass type's fields aren't a flat key→value map — edit it in the studio.
template_owned_field400The key is template-owned (title, details, terms, expiry) — update it for ALL holders instead.
unknown_field_key400The field key doesn't exist on the pass; the message lists the valid keys.
no_loyalty_program400Points operations on a pass with no loyalty program.
program_inactive400The loyalty program exists but is not active.
program_not_launched400The loyalty program has not been launched yet.
pool_exhausted409No barcodes remain in the pass's pool — upload more codes.
ambiguous_barcode409A shared Simple-mode code matches several instances; the response carries matchCount and how to disambiguate.
insufficient_credits402Not enough credits — top up in Billing and re-run.
rate_limited429Reserved: request rate exceeded. See Rate limits.
internal_error500Something failed on our side. When retrying is safe the response carries retryable: true.

Retry guidance

  • 4xx — don't retry unchanged; fix the request. The exceptions: insufficient_credits (retry after topping up) and rate_limited (retry with backoff).
  • 500 with retryable: true — safe to retry: the operation released its claim, and idempotent endpoints (issue, points with externalRef, Process Order) return the original result instead of double-applying.
  • 500 without retryable — contact support with the request details.

See also Rate limits and the API & integrations guide.