Skip to content

Errors

Every error the API returns, when, and what to do about it.

Updated 2026-09-28

Every error is an RFC 9457 problem document with content type application/problem+json. Branch on status and the last part of type — never on detail, which is written for people and may change.

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json

{
  "type": "https://stickytier.com/docs/api/errors#balance-insufficient",
  "title": "Insufficient balance",
  "status": 422,
  "detail": "Insufficient available balance."
}

What is safe to retry

429, 500, 409 in_progress and any network failure: retry with the same Idempotency-Key, backing off. Everything else is a fact about your request — retrying unchanged returns the same answer. The idempotency guide has the full table.

Every error

401 unauthorized

Unauthorized. The Authorization header is missing or malformed, the key does not exist, it was revoked, its rotation grace has ended, or the programme is suspended.

What to do: Send `Authorization: Bearer sticky_live_…` (or `sticky_test_…`). We never say which of these it was — check the key under Advanced → Developers (the API keys & webhooks tab) in the admin sidebar.

402 payment-required

Payment required. The programme has no active plan or running trial, so it is switched off — every call with its keys answers this until a plan is active again. Your key is fine.

What to do: The programme owner chooses a plan (in the StickyTier app in Shopify, or by contacting support for invoice billing). Nothing is lost meanwhile; retry once the plan is active.

403 forbidden

Forbidden. The key is valid but lacks the scope this endpoint needs, the programme's plan does not include the public API (`reason: plan_restricted`), the member's account is paused, suspended or deleted, or an adjustment is over the programme's approval limit and nobody else on the team could approve it (`reason: approval_required`).

What to do: The detail names the missing scope. Create a key with that scope — scopes cannot be added to an existing key.

404 not-found

Not found. No such resource in THIS programme. Another programme's ids always look like this too.

What to do: Check you are using the member's public id (M-…), not your own customer id, and the right mode (a test key cannot see live data).

409 conflict

Conflict. An Idempotency-Key was reused with a different body or for a different member (`reason: idempotency_key_reused` when the key already names another ledger entry); a request with the same key is still running (`reason: in_progress`); a phone number or external_ref belongs to another member; the member has been erased; a reservation was confirmed with a different order_ref; the plan refuses the action (`reason: plan_restricted`); or an export is not ready to download yet (`reason: not_ready`).

What to do: For `in_progress`, retry after the Retry-After seconds. For a body mismatch, you have a key collision or a retry bug — never reuse a key for a different request.

410 gone

Gone. The thing existed but is no longer available: an export job's download link has expired, the export failed, or its file was cleaned up.

What to do: Queue a new export with POST /v1/admin/export-jobs and download it before its expires_at.

422 validation

Validation failed. The body or a query parameter is not valid (e.g. a non-numeric `limit` or a `cursor` that did not come from this list) or a field is missing, mistyped or out of range — including an order event whose `currency` is not the programme's.

What to do: `errors` lists every problem as `{ path, message }`. In a batch, validation is reported per event and never blocks the others.

422 balance-insufficient

Insufficient balance. The member does not have enough spendable points for this redemption, reservation or debit adjustment (an adjustment never takes a member below zero). Points on hold (return window) and points already reserved are not spendable.

What to do: Read `balances.spendable_cents` on the member, or ask /v1/redemption-quotes first. Until 2026-09 the voucher endpoint answered `402 insufficient-balance` for this; it now matches reservations.

422 rule-ineligible

Programme rules reject this action. The programme's own redemption rules say no: below the minimum, above the maximum share of the order, blocked payment method, or too many open reservations. `reason` says which.

What to do: Call /v1/redemption-quotes with the cart total and payment method — it returns the allowed range before you try.

429 rate-limited

Too many requests. This key exceeded its rate limit (default 10 requests per second, bursts of 50) — or, with `reason: daily_credit_cap`, its daily limit for adjustment credits; or, on `POST /v1/events` with `reason: backlog`, your earlier events are still being processed and nothing in this request was accepted.

What to do: Wait `Retry-After` seconds (also in the body as `retry_after`). Send events in batches of up to 100 rather than one call each. A `backlog` answer means resend the same request after `retry_after`. The daily credit cap resets at midnight UTC (`resets_at`); debits are not capped.

500 internal

Internal error. Something failed on our side. The request may or may not have been applied.

What to do: Retry with the same Idempotency-Key — a write that did land will replay instead of applying twice.

Errors — StickyTier API