General-admission areas and reserved-seat groups use different selection UX, but they produce the same server boundary: an authoritative hold that your backend inspects and books atomically.
General-admission inventory
A gaArea is a chart object with capacity instead of individually presented
seats. A chart can mix reserved rows, tables, booths, and GA areas in one event.
With SeatingChart, respond to onGAClick and hold the buyer’s requested
quantity:
const chart = new seatlayer.SeatingChart({
container: "#chart",
event: "ev_9f3a",
onGAClick: async (area) => {
const quantity = await askForQuantity({
label: area.label,
remaining: area.available,
});
if (quantity > 0) {
await chart.holdGA(area.id, quantity);
}
},
onHold: ({ holdId, expiresAt, items }) => {
saveCheckoutHandoff({ holdId, expiresAt, items });
},
});
await chart.render();SeatLayer materializes internal GA units for inventory correctness. Treat their
labels as opaque. For buyer-facing totals, aggregate hold items by objectId and
sum quantity ?? 1.
function summarizeHold(items) {
return Object.values(
items.reduce((groups, item) => {
const key = `${item.objectId}:${item.tierId ?? "base"}`;
groups[key] ??= {
objectId: item.objectId,
categoryKey: item.categoryKey,
tierId: item.tierId,
unitPrice: item.unitPrice,
currency: item.currency,
quantity: 0,
};
groups[key].quantity += item.quantity ?? 1;
return groups;
}, {}),
);
}Do not generate GA unit labels in your application or accept them from the buyer as trusted booking input.
Adjacent reserved seats
bestAvailable(quantity, categoryKey?, options?) asks SeatLayer to find and
hold a suitable adjacent group in one operation.
const result = await chart.bestAvailable(4);
if (!result) {
showNoGroupMessage("We could not find four seats together.");
} else {
console.log(result.holdId, result.labels);
}Restrict the search to a category:
const result = await chart.bestAvailable(2, "vip");A successful result updates the chart selection and triggers onHold like a
manual hold. Continue through the same server inspection, payment, and booking
flow.
Use intentional fallback rules
Ask for the desired group
Start with the buyer’s quantity and optional category or zone preference.
Explain an exact failure
If no adjacent block exists, say that clearly; do not report the whole event as sold out when scattered seats may remain.
Offer a buyer-controlled alternative
Let the buyer reduce quantity, choose a different category, or switch to manual selection. Do not silently split the group.
Book the hold atomically
Send only its holdId to your server. A conflict fails the whole booking, so
a four-person order cannot accidentally confirm three seats.
Server booking is unchanged
const response = await fetch(
`https://api.seatlayer.io/v1/events/${eventKey}/book`,
{
method: "POST",
headers: {
authorization: `Bearer ${process.env.SEATLAYER_SECRET_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({
holdId,
bookingRef: order.id,
}),
},
);
if (response.status === 409) {
return sendBuyerBackToGroupSelection();
}Whether the hold contains clicked seats, an adjacent group, a GA quantity, or a mixture, booking is all-or-nothing.
Accessibility and product details
- Label GA controls with the area name, remaining quantity, and chosen count.
- Provide increment/decrement buttons with keyboard and screen-reader labels.
- Announce the best-available result and hold expiry without moving focus unexpectedly.
- Preserve accessible-seat metadata when offering group alternatives.
- Show the group as one order line when that matches buyer expectations, while retaining item-level data in the order record.
- Never use colour alone to distinguish available, held, and booked inventory.
Verification checklist
- GA capacity is configured on the chart object.
- Quantity validation prevents zero, negative, and over-capacity requests.
- Buyer totals come from inspected
unitPrice, currency, and quantity. - Best-available failure does not silently split the group.
- Manual fallback preserves the requested category/accessibility needs.
- A mixed reserved + GA hold completes in test mode.
- Expiry and
409return the entire order to a useful state. - Keyboard and screen-reader behavior is tested for quantity controls.
Continue with best available, ticket tiers, or integrate your backend.