SeatBuilderSeatBuilder Docs

Hold and book lifecycle

The end-to-end hold → book → release flow with contract-verified request and response JSON for every write and read endpoint.

Hold and book lifecycle

This guide walks the full server-side lifecycle of a seat: hold it, book it, release it, and read its status or the parent event at any point. Every JSON block below is copied verbatim from the API contract (openapi.json) so what you read here is exactly what the API sends and accepts.

This guide deepens the e-commerce recipe in Hold seats and confirm at checkout — the recipe shows the browser-to-cart-to-checkout choreography; this guide is the endpoint-by-endpoint contract reference. For the concepts behind the statuses, see Core concepts.

All write calls authenticate with a secret key (X-Api-Key: sk_live_xxx); the read calls accept a public or secret key.

Two flows: which one are you building?

Who takes the initial hold depends on your integration flow. Get this right or you will double-hold a seat (re-holding a seat the SDK already holds returns a 409).

  • SDK checkout — the browser SDK auto-holds each seat on select and captures the holdToken client-side. Your server calls only extend / book / release, and never POST /seats/hold. Every endpoint below still applies — just skip step 1 (hold), because the SDK already holds the seat.
  • Headless / server-authoritative — no JS SDK; your server owns the whole lifecycle. It calls hold (step 1) first, then book. The rest of this guide walks this flow end to end.

1. Hold a seat

This step runs only in the headless flow. In SDK checkout the SDK has already taken the hold — skip to step 2.

Take a hold on a single seat with POST /events/{eventKey}/seats/hold. The holdToken you pass ties the hold to a buyer session; extraData is an opaque bag you can round-trip (e.g. your order id). A successful hold returns 201 with the seat's new state and its holdExpiresAt.

The initial hold's ttlSeconds defaults to 900s (15 min) when omitted; the SDK forwards its holdDurationSeconds into this field — see the holdDurationSeconds field in the SDK reference for the full reconciliation.

POST /api/v1/events/evt_q3-2026-jazz-night/seats/hold HTTP/1.1
Host: seatbuilder.org
X-Api-Key: sk_live_xxx
Content-Type: application/json

{"objectLabels":["A-12","A-13"],"holdToken":"7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2","extraData":{"orderId":"ord_98a2"}}
{"chartKey":"chart_8a2b1c","eventKey":"evt_q3-2026-jazz-night","holdToken":"7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2","holdExpiresAt":"2026-10-02T18:55:00.000Z","objects":[{"objectLabel":"A-12","status":"held","extraData":{"orderId":"ord_98a2"}},{"objectLabel":"A-13","status":"held","extraData":{"orderId":"ord_98a2"}}]}

2. Book the held seats

At checkout, promote the holds to permanent bookings with a single all-or-nothing call to POST /events/{eventKey}/seats/book. Pass every seat label in objectLabels[] and the shared holdToken; all the labels must currently be held by that token. Success returns 200 with a booked[] array — one object per confirmed seat.

POST /api/v1/events/evt_q3-2026-jazz-night/seats/book HTTP/1.1
Host: seatbuilder.org
X-Api-Key: sk_live_xxx
Content-Type: application/json

{"objectLabels":["A-12","A-13"],"holdToken":"7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2","extraData":{"orderId":"ord_98a2"}}
{"booked":[{"chartKey":"chart_8a2b1c","eventKey":"evt_q3-2026-jazz-night","objectLabel":"A-12","status":"booked","bookedAt":"2026-10-02T18:46:00.000Z","extraData":{"orderId":"ord_98a2"}},{"chartKey":"chart_8a2b1c","eventKey":"evt_q3-2026-jazz-night","objectLabel":"A-13","status":"booked","bookedAt":"2026-10-02T18:46:00.000Z","extraData":{"orderId":"ord_98a2"}}]}

3. Release seats

Give seats back to inventory with POST /events/{eventKey}/seats/release, passing the labels in objectLabels[]. Released seats return to free. The 200 response reports the releasedAt timestamp and each freed label.

POST /api/v1/events/evt_q3-2026-jazz-night/seats/release HTTP/1.1
Host: seatbuilder.org
X-Api-Key: sk_live_xxx
Content-Type: application/json

{"objectLabels":["A-12","A-13"]}
{"chartKey":"chart_8a2b1c","eventKey":"evt_q3-2026-jazz-night","status":"free","releasedAt":"2026-10-02T19:15:30.000Z","released":[{"objectLabel":"A-12"},{"objectLabel":"A-13"}]}

4. Read seat status

Poll the current state of every seat in an event with GET /events/{eventKey}/status. This is a read-only call (no request body) — a public key is enough. Each object reports its status, its categoryKey, and, for held seats, the holdToken and holdExpiresAt (both null once the seat is booked).

GET /api/v1/events/evt_q3-2026-jazz-night/status HTTP/1.1
Host: seatbuilder.org
X-Api-Key: pk_live_xxx
{"eventKey":"evt_q3-2026-jazz-night","objects":[{"objectLabel":"A-12","status":"held","holdToken":"7f6c3a91-b1ef-4d0a-9c84-3f12a8e0b5d2","holdExpiresAt":"2026-10-02T18:55:00.000Z","categoryKey":"premium","extraData":{"orderId":"ord_98a2"}},{"objectLabel":"A-13","status":"booked","holdToken":null,"holdExpiresAt":null,"categoryKey":"premium","extraData":{"orderId":"ord_98a3"}}]}

5. Read the event

Fetch an event's metadata — including the chart it renders and the published chart version it is pinned to — with GET /events/{eventKey}. Also a read-only call.

GET /api/v1/events/evt_q3-2026-jazz-night HTTP/1.1
Host: seatbuilder.org
X-Api-Key: pk_live_xxx
{"eventKey":"evt_q3-2026-jazz-night","chartKey":"chart_8a2b1c","chartPublishedVersion":3,"name":"Friday jazz night, October 2026","createdAt":"2026-09-18T11:30:00.000Z","updatedAt":"2026-09-18T11:30:00.000Z"}

Putting it together

The authoritative server-side lifecycle is: hold each seat the buyer selects (step 1), book the whole selection in one atomic call at checkout (step 2), and release anything the buyer abandons (step 3). Read status (step 4) to reconcile your own state against the platform, and read the event (step 5) to confirm which chart version is live.

Remember which flow you are in: in SDK checkout the server must never call /seats/hold (the SDK already holds — start at book), while in the headless flow the server calls hold then book.

For the full checkout choreography — capturing holds from the SDK, extending to a payment window, and recovering from a 409 at book time — see Hold seats and confirm at checkout. For the webhook that tells your backend a seat was booked or a hold expired, see Webhooks.

Hold and book lifecycle — SeatBuilder Docs