# Waitlist

# Waitlist

When a bookable is sold out and the event has `waitlist_enabled`, customers can join the waitlist straight from the widget. Promotion is FIFO per bookable (by `waitlist_entries.created_at`).

## How it works

1. The customer joins → a `WaitlistEntry` is created in `waiting`.
2. Capacity frees up (booking cancelled, hold expired, booking edited) → `OfferSpotOnCapacity` promotes the next waiting entry: state `offered`, a 64-char `offer_token`, and `expires_at` = now + **24 h** (`OfferSpotOnCapacity::DEFAULT_OFFER_TTL_HOURS`). The customer gets a `WaitlistSpotOfferedNotification` with the `/waitlist/claim/{token}` link.
3. The customer opens the link — they must be logged in **as the entry's user** — and clicks **Claim**: state `claimed`, then a redirect to the booking review page pre-seeded with the bookable and people count.
4. Completing that booking marks the entry `fulfilled` (the `waitlist_entry_id` is carried through; a `BookingCreated` listener is the safety net).
5. **Decline** → `cancelled` and the next waiting entry is promoted immediately.
6. `waitlist:expire-claims` (every 5 min) expires stale offered/claimed entries and promotes the next in line.

## States

```
waiting → offered → claimed → fulfilled
            ↘ expired   ↘ cancelled (declined)
```

## Two kinds of entry

`waitlist_entries.kind` splits the table in two lifecycles that never mix:

- **`capacity`** (default) — the sold-out flow above: account users queueing for freed capacity, FIFO promotion, claim link gated by token **and** the matching authenticated user.
- **`walkin`** — the [door queue](/docs/venue/door-ops): staff take same-day walk-in parties on an Area, the guest is a name/phone pair (no account), the offer goes out over SMS/mail, and the claim page is token-only. Walk-in rows never auto-promote and are seated by hand — see door ops.

## Permissions

Owner, admin and manager see waitlist state on the widget and in the booking flow. Joining and claiming are customer actions — the claim link is gated by the 64-char token **and** the matching authenticated user, no staff role needed. Walk-in queue writes need `bookings.seat`.


---
> Source: https://placeful-app.com/en/docs/bookings/waitlist
