Journey Docs
Guides

Errors, idempotency and pagination

The conventions to build against before you scale up a Partner API integration.

These three conventions are consistent across the whole Partner API. Getting them right once, in a shared client, is far less work than handling them per endpoint.

Errors

Every error uses the same envelope:

{
  "type": "validation_error",
  "timestamp": "2026-10-09T18:22:41.218Z",
  "code": "invalid_parameter",
  "message": "Human-readable summary.",
  "details": {},
  "errors": []
}

type, timestamp, code and message are always present. details and errors[] are optional.

Branch on code, never on message. Messages are written for humans and can change. In production, 5xx messages are deliberately masked, so there is nothing useful to parse there either.

What the statuses mean

StatusMeaning
400Validation failed, or an Idempotency-Key longer than 255 characters
401Missing, invalid, expired or revoked credential
403Authenticated, but missing a required scope — or the wrong key level
404Not found, or outside your organization or venue reach
409Idempotency conflict (see below)
413Upload above 10 MB
415Unsupported upload type
429Rate limited — back off and retry

404 is doing two jobs

Out-of-scope resources return 404, not 403. This is deliberate: a caller cannot use the error code to discover whether a reservation exists at a property they cannot reach.

The practical consequence is that a 404 does not prove something was deleted. If you are reconciling, treat 404 as "not visible to me" rather than "gone".

The one exception: passing propertyIds outside your scope on the reservations list returns 403 rather than filtering silently.

Idempotency

Idempotency-Keyheaderstring

Optional. Supported on POST, PUT, PATCH and DELETE under /partner. Maximum 255 characters.

Send one on every write. On a replay you get the stored response back, with:

X-Idempotent-Replay: true

What counts as "the same request"

Method, path, sorted query string and canonical body. Two details matter:

  • JSON key order is ignored — reserialising your body will not break a replay.
  • Array order matters — [a, b] and [b, a] are different requests. If you build arrays from a set or a map, sort them before sending, or your retry will be rejected as a conflict.

Conflicts

You get a 409 when:

  • the same key is reused with a different request, or
  • the same key is sent while the first request is still in flight.

An in-flight request holds its lease for a few minutes. If a request times out on your side, retrying with the same key shortly afterwards may legitimately return 409 — wait and retry rather than generating a new key, which would risk performing the operation twice.

Keys are scoped to your tenant, so they cannot collide with another partner's.

The Idempotency-Key header is not currently declared in the OpenAPI document, so you will not see it in the generated reference. It is supported regardless, as described here.

Already-idempotent operations

Some endpoints are naturally safe to repeat: acknowledging an arrival, and adding codes to a pool (duplicates are reported rather than failing). Send a key anyway for the replay semantics.

Pagination

Two styles, depending on the endpoint.

Offset

The default: limit (1–100) with offset. Fine for small, bounded lists like venues or programs.

Keyset cursor

GET /v1/partner/reservations supports a cursor, and you should use it for anything large:

  • Send cursor, read nextCursor, repeat until nextCursor is null.
  • Ordered by check-in date, then external reservation id.
  • A cursor overrides offset; the response echoes offset: 0.

A malformed cursor is ignored, not rejected. The request succeeds and returns the first page. A paging loop that mangles its cursor will therefore run forever over page one rather than erroring. Assert that each page advances, and cap the number of iterations.

Rate limits and backoff

Limits exist at both the per-key and edge layers, and a few individual routes carry their own — custom-domain recheck and retry, and the public guest-invite send.

Rather than coding to specific numbers, which can change:

  • treat 429 as a normal condition under load, not an error to alert on;
  • retry with exponential backoff and jitter;
  • keep a concurrency ceiling in your client, so a burst of work does not turn into a burst of requests;
  • remember that most data changes on a multi-hour cycle, so polling faster rarely gets you anything. See how the data flows.

On this page