Every SeatLayer Platform/SDK integration follows one invariant:
The browser holds. Your server books inventory.
This page assumes the chart and event model: one reusable venue document, and many independent realtime occurrences created from it.
The buyer can explore inventory and temporarily reserve a selection without receiving an account secret. Only your trusted backend can commit that hold. Your platform separately owns payment, its commercial Order, and ticket fulfilment. Direct organizers using SeatLayer-managed checkout follow the Managed Ticketing path.
The complete journey
Render live inventory
Your browser or mobile surface loads a published event through the buyer SDK. For ordinary Platform Public sale, the event key and publishable key start a direct, exact-origin bootstrap. Login, presale, partner, and channel inventory use a scoped token from your authenticated backend. Neither path grants server booking authority.
Select and hold
The buyer chooses seats, a table, booth, or GA quantity. The SDK creates a short-lived hold and returns an opaque holdId with an expiry time.
Inspect on your server
Your backend receives the holdId and resolves it with GET /v1/events/:eventKey/holds/:holdId. The returned items—not browser-posted prices—become the order source.
Run your order and payment logic
Create or reuse your own order. Authorize or capture payment according to your payment provider and recovery model.
Book inventory atomically
Your backend calls POST /v1/events/:eventKey/book using a secret key and your immutable order id as bookingRef.
Confirm, fulfil, and reconcile
The synchronous response drives the buyer journey. Your platform creates and delivers its tickets. Realtime updates repaint open pickers, and signed inventory webhooks reconcile downstream systems.
BuyerSelects seats
The buyer uses your browser or mobile surface to choose currently available inventory.
Buyer SDKCreates a temporary hold
The browser receives an opaque hold ID and sends that ID, not a booking request, to your backend.
Your serverInspects trusted items
Your backend uses its secret key to read authoritative prices, quantities, labels, and the expiry.
Your platformRuns checkout
Your product creates the order and applies its own payment, tax, and customer rules.
Your serverBooks inventory once
It books with the stable booking reference. The result is atomic: success or an inventory conflict.
Your platformFulfils and reconciles
Your application confirms the order, delivers tickets, and uses signed webhooks for reconciliation.
Why the split exists
Security
A browser can reserve inventory but cannot create a permanent inventory booking. Booking authority remains in your trusted environment.
Correctness
Each event serializes inventory transitions, so two buyers cannot successfully take the same seat.
Product control
Your application owns identity, pricing rules, payment, tax, commercial Orders, tickets, email, refunds, scanning, support, and the final confirmation experience.
What each system owns
| Responsibility | Browser / SDK | Your server | SeatLayer |
|---|---|---|---|
| Display chart and live availability | Yes | No | Supplies state |
| Let a buyer select | Yes | No | Enforces availability |
| Create and restore holds | Yes | May inspect | Stores authoritative hold |
| Calculate the trusted charge | No | Yes | Supplies trusted line items |
| Process payment and orders | No | Yes | No |
| Permanently book inventory | No | Initiates | Applies atomically |
| Create and deliver tickets | No | Yes | No |
| Refund and check in buyers | No | Yes | No |
| Realtime inventory synchronization | Receives | Optional listener | Publishes |
| Signed event notification | No | Receives | Sends |
Seat lifecycle
| State | Meaning | Typical transition |
|---|---|---|
free |
Available to buyers | Initial, released, or expired |
held |
Temporarily reserved | Buyer SDK creates a hold |
booked |
Permanently committed inventory | Your server books |
not_for_sale |
Removed from buyer inventory | Operator or inventory rule |
Holds expire automatically. Booking is all-or-nothing: if any required item cannot be booked, the request returns a conflict without partially completing the sale.
The browser handoff
const picker = new seatlayer.SeatPicker({
container: "#picker",
event: "ev_9f3a",
publicKey: "pk_test_…",
onCheckout: async (_, __, handoff) => {
await fetch("/api/checkout/seats", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ holdId: handoff.holdId }),
});
},
});
await picker.render();For Public sale, the first SeatLayer response carries both the chart and compact
inventory status. The SDK keeps the returned bearer in memory and renews it when
needed. Supplying buyerAccessTokenProvider or buyerAccessToken for a private
audience takes precedence over publicKey and prevents an anonymous fallback.
The browser sends your backend the hold id. Your backend obtains trusted labels, quantities, tiers, currency, and prices from the hold inspection endpoint.
Expected failure paths
- Hold expired: return the buyer to selection and clear stale cart state.
- Booking returned
409: treat it as a recoverable inventory conflict; do not partially confirm the order. - Payment succeeded but booking is uncertain: retry using the same
bookingRef. - Realtime connection dropped: reconnect and refresh authoritative inventory.
- Mode mismatch: use a test key with test events and a live key with live events.
Verify your understanding
Before implementation, you should be able to answer:
- Which value crosses from the browser to your server?
- Where is the secret key stored?
- Which response supplies authoritative inventory and configured-price input, and where does the final amount charged remain authoritative?
- Which identifier makes a retry safe?
- What buyer experience follows a
409?
Continue to Authentication, then install the Buyer SDK.