---
title: "Groups and general admission"
description: "Hold GA quantities and find adjacent reserved seats without changing the server booking flow."
---

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.

GA is supported only as capacity authored inside a reserved-seat Chart. This
guide does not create or support a pure-GA event without a seating chart.

<Aside type="tip" title="SeatPicker includes both flows">
  `SeatPicker` renders GA quantity controls and best-available group selection
  in its buyer UI. Use the headless `SeatingChart` methods below when your
  application owns those controls.
</Aside>

## 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:

```js title="browser/ga-selection.js"
const chart = new seatlayer.SeatingChart({
  container: "#chart",
  event: "ev_9f3a",
  publicKey: "pk_test_…",
  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();
```

For a public Platform event, use a publishable key that matches the event mode
(`pk_test_…` for test or `pk_live_…` for live) and register the page's exact
Embed origin. The SDK obtains Public-only access directly and keeps the grant in
memory, so your server does not mint a buyer token when the chart loads. For a
login, presale, partner, or channel audience, replace `publicKey` with an async
`buyerAccessTokenProvider` backed by your authenticated server; an explicit
provider or token takes precedence.

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`.

```js title="server/group-ga-lines.js"
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.

```js title="browser/best-available.js"
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:

```js
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

<Steps>
  <Step title="Ask for the desired group">
    Start with the buyer's quantity and optional category or zone preference.
  </Step>
  <Step title="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.
  </Step>
  <Step title="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.
  </Step>
  <Step title="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.
  </Step>
</Steps>

## Server booking is unchanged

```js title="server/book-group.js"
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 `409` return the entire order to a useful state.
- [ ] Keyboard and screen-reader behavior is tested for quantity controls.

Continue with [best available](/buyer-sdk/best-available),
[ticket tiers](/buyer-sdk/ticket-tiers), or
[integrate your backend](/integrations/ticketing-backend).