Reservations
How holds, reservation tokens, and the X-Device-ID header work.
A reservation prices an attendee's cart and holds the stock for the checkout window, so tickets can't be sold out from under them while they pay.
const { data: reservation } = await client.createReservation('my-event', {
items: [{ sku: 'ticket-type-uuid', quantity: 2 }],
promoCode: 'EARLYBIRD', // optional
})The response contains everything your checkout page needs:
| Field | Purpose |
|---|---|
reservationToken | UUID identifying the attendee's cart. Echo as X-Device-ID on order/release calls. |
quoteReference | Opaque handle to the priced, server-held quote. Send back when creating the order. |
total / totalFees | Priced cart, in the smallest currency unit (Money). |
discount / promoCode | Applied promo discount, if any. |
items | Per-ticket price and fee breakdown. |
clientExpiresAt | Deadline to drive your checkout countdown. |
The X-Device-ID header
The reservationToken doubles as a device/cart identifier, sent as the
X-Device-ID header:
- Recommended: generate one stable UUID per attendee (persist it in the
browser, e.g.
localStorage) and send it on every call. Each attendee then maps to exactly one reservation, and repeatedPOSTcalls refresh and extend the same hold instead of holding fresh stock. - If omitted when reserving, the server mints a token and returns it, but it also falls back to reusing a single reservation per client IP + event, so distinct attendees behind the same IP (offices, campus networks) would share a cart. Supply your own per-attendee token in production.
- Required when creating an order: echo the
reservationTokenverbatim.
// Refresh/extend an existing hold for the same attendee
await client.createReservation(
'my-event',
{ items: [{ sku: 'ticket-type-uuid', quantity: 3 }] },
{ deviceId: reservation.reservationToken },
)Expiry and release
Holds expire on their own after the checkout window. Use clientExpiresAt to
show a countdown and prompt the attendee to re-reserve when it lapses.
To free the stock early (e.g. the attendee empties their cart):
await client.releaseReservation('my-event', {
deviceId: reservation.reservationToken,
})
// → { released: true }If no token is supplied, the server falls back to releasing the reservation
held for your client IP + event; 400 is returned when there is nothing to
release.
Availability reflects holds
quantityLeft on the tickets endpoint already subtracts stock held in other
attendees' reservations, so what you display is what can actually be bought
right now.

