---
title: "Best available seats"
description: "Find and hold the best adjacent seats by quantity, category, zone, and premium preference."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.seatlayer.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Best available seats

`bestAvailable()` asks SeatLayer to find and hold a suitable adjacent group
without requiring the buyer to click individual seats.

## Public methods

```ts title="best-available-types.ts"
// SeatingChart
bestAvailable(
  quantity: number,
  categoryKey?: string,
  options?: {
    zoneId?: string;
    preferPremium?: boolean;
    ttlMs?: number;
  },
): Promise<BestAvailableResult | null>

// SeatPicker
bestAvailable(
  quantity: number,
  categoryKey?: string,
  options?: {
    zoneId?: string;
    preferPremium?: boolean;
  },
): Promise<HoldResult | null>
```

> **Same operation, different presentation**
>
> `SeatingChart` returns the selected labels for a custom UI. `SeatPicker`
> reflects the hold in its built-in tray. Both create a real server hold and
> continue through the same checkout flow.

## Find a group

```js title="browser/find-group.js"
const chart = new seatlayer.SeatingChart({
  container: "#chart",
  event: "ev_9f3a",
  onHold: ({ holdId, expiresAt }) => {
    saveCheckoutHandoff({ holdId, expiresAt });
  },
  onError: (error) => {
    console.error("Best-available request failed", error);
  },
});

await chart.render();

const result = await chart.bestAvailable(4);
if (!result) {
  showAlternatives("No block of four seats is currently available.");
} else {
  console.log(result.labels, result.holdId, result.expiresAt);
}
```

A successful call updates selection, fires `onSelectionChange`, creates the
hold, and fires `onHold`.

## Narrow the search

```js title="browser/best-available-filters.js"
// Two adjacent VIP seats.
await chart.bestAvailable(2, "vip");

// Four seats in an authored venue zone.
await chart.bestAvailable(4, undefined, {
  zoneId: "zone-east-stand",
});

// Prefer a premium block and use a ten-minute checkout window.
await chart.bestAvailable(2, undefined, {
  preferPremium: true,
  ttlMs: 10 * 60 * 1000,
});
```

Use stable category keys and zone ids from the published chart, not translated
labels or screen coordinates. Hidden or unrevealed inventory is not eligible.

## Result contract

```ts
interface BestAvailableResult {
  holdId: string;
  expiresAt: number;
  labels: string[];
  seats?: SelectedSeat[];
  items?: HoldLineItem[];
  zoneId?: string;
}
```

`items` contains authoritative hold line information when present. Your browser
still sends only `holdId` to your server; the server re-inspects the hold before
payment.

## Failure behavior

The public method resolves to `null` for conflicts and routes the underlying
error through `onError`.

| Reason/code | Meaning | Buyer experience |
|---|---|---|
| `not_enough_together` | Enough seats may exist, but no adjacent block fits | Offer fewer seats, another zone/category, or manual selection |
| `sold_out` | Eligible inventory is exhausted | Offer another ticket type or waitlist |
| `invalid_zone` | Zone id is malformed | Treat as an integration error |
| `unknown_zone` | Zone is not in the published chart | Refresh configuration; do not retry blindly |
| `event_closed` | Sales are closed | Disable purchase controls |

Do not translate every `null` into “sold out.” Preserve enough error context in
`onError` to choose the correct message.

## Premium fallback

`preferPremium: true` expresses preference, not an absolute filter. If a full
premium block does not exist, the buyer picker may hold the best overall group
and show a fallback note. Use `categoryKey` when the result must be restricted
to a specific inventory category.

## Verification checklist

- [ ] Quantity is a positive integer within the buyer limit.
- [ ] Category and zone values are stable ids.
- [ ] Failure messages distinguish adjacency from sold out.
- [ ] The buyer controls any fallback to fewer or separated seats.
- [ ] A successful group appears in selection and `onHold`.
- [ ] The server inspects and atomically books the returned hold.
- [ ] Expiry clears the whole group from the cart.

Continue with [groups and GA](/integrations/groups-and-ga) or
[holds and checkout](/buyer-sdk/holds-and-checkout).

Source: https://docs.seatlayer.io/buyer-sdk/best-available/index.mdx
