API errors and rate limits

The error envelope, what each code means and whether retrying will help, plus the request rate limit and how to stay inside it.

Updated 7/26/2026

Every error uses the same envelope, so one handler covers the whole API.

{
  "error": {
    "code": "invalid_request",
    "message": "A human-readable explanation."
  }
}

Branch on code, not on the message - messages get reworded, codes don't.

The codes

StatusCodeMeansRetry?
401unauthorizedMissing, malformed, unknown or revoked keyNo - fix the key
403forbiddenValid key, not permitted to do thisNo
403account_suspendedThe account is suspendedNo - get in touch
404not_foundNo such pass, template or subscriptionNo
422invalid_requestThe request is malformed or missing something requiredNo - fix the request
429rate_limitedToo many requestsYes, after backing off
5xx-Something went wrong our endYes

The rule of thumb: 4xx means fix your request, 429 and 5xx mean try again. Retrying a 422 will produce the same 422.

The most common mistakes

401 on a first integration is nearly always the header format. It must be exactly Authorization: Bearer <key>.

422 on creating a pass is usually the missing passTemplate query parameter. It's required, and there's no default.

404 when the pass definitely exists is usually the wrong account - a key only ever sees its own account's data. See Working across multiple accounts.

A field that silently doesn't appear isn't an error at all: an unrecognised key in passContent is ignored rather than rejected. Check the field id against the template. See Creating passes over the API.

Rate limits

600 requests per 60 seconds per API key.

That's a generous ceiling for normal use - it only bites when you're bulk-issuing or backfilling.

Over the limit you get 429 with code rate_limited.

The limit is per key, so a batch job on its own key can't starve your live checkout of requests. That's a good reason to give each system its own key anyway. See API keys and authentication.

Staying inside it

For anything bulk:

    1. Add a small delay between requests rather than firing them as fast as possible.
    2. On a 429, wait and retry with exponential backoff - a second, then two, then four.
    3. Cap concurrency. Ten parallel workers hammering the API will hit the limit that ten sequential ones never would.
    4. Set your bulk job's own key so it can't affect anything customer-facing.

Don't retry a 429 immediately in a tight loop. You'll stay rate-limited and turn a brief slowdown into a sustained failure. Back off properly.

Retrying safely

Retries are only safe if repeating a request can't cause damage. For pass creation, that's what extId guarantees - the same request twice produces one pass, not two.

If you're going to retry anything, read External IDs and idempotency first.

Useful response headers

  • X-Total-Count on GET /api/v1/passes - the total number matching your filters, for pagination.
  • X-Notification-Status on pass updates that carry a message, and on the notification endpoint - whether the push was delivered.

Where to go next

More in Developers