# Your first booking

# Your first booking

How a customer books a spot on one of your events, from the widget to confirmation.

## 1. Open the booking widget

Customers reach the widget in two ways:

- **Embedded** on the company's site via the generated snippet, or
- **Directly** at `/widget/calendar` (the URL the snippet's iframe loads).

The widget lists the company's upcoming published events that are inside their booking window. (Inside the staff app, the **Bookings** nav link opens the bookings manager — not the widget.)

## 2. Pick an event

Each event shows its date and availability. The exact remaining-places count appears only once availability drops to the event's `show_bookable_threshold` or below. Sold-out events offer the **waitlist** when the event has `waitlist_enabled`.

## 3. Choose seats / time

Depends on the event's `booking_mode`:

- **Fixed slots** — pick a seat in an area, then a time slot (`seat_time` capacity).
- **Flexible window** — pick a people count and a time window. If the event has seats, the customer also picks a seat (no fixed time slot); without seats the window is booked on the event itself.

When the bookable exposes several price rows (e.g. `adult`, `child`), the customer sets a quantity per price; the people total must equal the sum of the per-price quantities.

## 4. Confirm and pay

- **Free bookings** (total `0`) skip payment and confirm immediately — state `Free`.
- **Promo codes** — the "I have a promo code" field parks the booking in `PromoPending` for staff review instead of charging the card. Approved codes confirm the booking (fully covered) or email the booker a link to pay the remainder; rejected ones fall back to cancellation or full payment, per the staff's choice.
- **Paid bookings** redirect to Stripe Checkout on the company's connected account. A capacity hold (`booking.hold_minutes`, default 30 min) reserves the spot while paying; `booking.max_hold_lifetime_minutes` (default 90 min) is the hard cap on the whole flow.
- The `bookings:expire-holds` sweeper (every 5 min) expires lapsed holds — and settles Checkout sessions Stripe already captured, so a slow payment still confirms instead of being lost.

## 5. Done

The finish page (`/booking/{booking}/{outcome}/finish`) shows the booking code and an `.ics` calendar download. Reminder emails go out 24 h and 1 h before the event start (`bookings:send-reminders`, hourly).

> Event full? With `waitlist_enabled` on, customers join the queue and receive an offer link when a spot frees up.


---
> Source: https://placeful-app.com/en/docs/getting-started/first-booking
