Preventing Double-Booking: How a Server-Held Booking Session Works
Stop two buyers from holding the same seat. A server-held booking session owns the seats in its cart and, after payment, sells all of them or none.
A double booking starts with a seat that looks free on one buyer’s screen while another buyer already holds it. A booking page shows what it read from the server a moment ago, and in that moment someone else may have taken the seat. That gap is why stale seat data leads to double bookings.
A cart kept in the browser cannot settle that, since each browser knows only its own cart. Only the server sees them all. It has to decide who owns a seat, at the moment the buyer clicks it.
Booking sessions in 1.73.0
Seatmap Pro 1.73.0 added booking sessions, server-held carts for one event that survive a page reload. Each seat is owned by exactly one session, so two buyers cannot be sold the same seat. While a session is live, no other session can take what it holds, and neither can a lock or sale from the existing booking calls.
Opening a session takes only the event id and the Public API key; every later public call needs no API key, because the session id it returns is the credential. A booking page can run the cart from the browser while the Secret API key stays on your server for the final confirm.
How a booking session holds seats
Opening a session requires an Idempotency-Key header, and the same key returns the same session, so a retried page load gets its cart back instead of a second one.
A session is active while the buyer picks seats and pending payment once checkout has frozen the cart. Only those two states hold seats: a confirmed session has sold them, and a cancelled or expired one holds nothing.
A booking session holds its seats for fifteen minutes by default, counted from the first seat placed in an empty cart. It also caps its cart at ten by default, counting seats and general admission capacity together. Both are operator settings. Each cart line keeps the price it was held at, and the session carries the total.
Session payloads carry expiresInSeconds and the server’s time, so a page runs the buyer’s countdown from expiresInSeconds rather than the browser clock.
On the map, the renderer’s onSeatSelect callback can return false, or a promise that resolves to false, to cancel a selection. That is where a booking page holds the seat on the server before the map accepts the click. The renderer ships BookingSessionClient for the public session calls. A failed call arrives as a BookingSessionError with the HTTP status, the error code and, for a refused hold, the seats and areas in conflict.
The 1.73.0 notes document the session calls and their errors and the renderer’s session client. The round trip from venue schema to confirmed booking shows where the session calls sit among the other calls.
Four situations a seat hold has to handle
Two buyers, one seat. Both pages ask their sessions to hold the same seat. The server gives it to one. The other hold is all-or-nothing, so it is rolled back whole: that session keeps exactly what it held before, and the answer lists the seats and areas in conflict for the page to show the buyer.
A reload mid-selection. The page stored the session id, for example in session storage, and reads the session back. A read on an ended session still answers with its stored state, so the page reuses the id only when the state is active and expiresInSeconds is above zero. Then it marks the cart’s seats on the map.
A slow payment. Checkout freezes the cart, and a frozen cart cannot change. The session gives it its own payment grace period, ten minutes by default, also an operator setting. After payment, your server confirms the session with the Secret API key, and the confirm sells every held seat and area in one transaction: the whole cart or none of it. A repeated confirm returns the stored result, and confirm can store your order reference.
An abandoned cart. Once the hold has run out, the session refuses any further change, checkout or confirm. It is then released in the background and marked expired, which puts its seats and general admission capacity back on sale. The map reads availability when the event loads, so a reload or a new read shows those seats.
Constraints and what stays the same
Booking sessions accept nothing until an organization turns them on. A self-hosted operator can also close the session endpoints with one Helm value, and sessions that already exist still expire normally.
An integration that does not use sessions sees no change. Seats are only held by a session when one is created, and without booking sessions your backend owns hold lifetime and releases what it no longer needs. Where sessions and the existing calls sell the same event, a lock or sale from the existing calls is refused for any seat a live session holds, and the answer names those seats.
Where to go next
A ticketing platform needs more from its seat map than safe holds. What else a seat-map layer has to expose sets out the rest. To talk through where holds belong in your own booking flow, book a demo.
Continue reading
All posts →From Venue Schema to Confirmed Booking, One API Call at a Time
Go from venue schema to confirmed booking with the Booking API, one call at a time: event, prices, map, hold and sale, with the error case at each step.
Open Ticketing APIs: What a Seat-Map Layer Has to Expose
Before choosing a ticketing API, check what its seat-map layer exposes. Five criteria from layout reads to hold conflicts, each answered with Booking API v2.
Accessible Seats in Venue Seating Charts: What Ships and What You Own
See how a seat map records accessible seats, styles them in the renderer, and where keyboard and screen-reader work belongs to your own page.