Booking
Online and front-desk bookings for appointments and scheduled departures, with availability, deposits, payments and reminders.
Booking lets customers reserve time with a business. It covers two kinds of service: appointments, where a customer picks a time and the business assigns a free provider and room (a massage, a court), and departures, where a customer takes seats on a scheduled run (a tour, a ferry, a class). It works out which times are free, takes deposits or full payment, sends confirmations and reminders, and gives the front desk a day view to run bookings from. A Location's opening hours come from Branches, and messages go out through Outbox. Booking doesn't own the customer directory, staff pay or the public website: Customers, Staff and Website add those when they're on.
Discounts on bookings
Discounts from Discounts that run in Bookings apply to services, such as "20% off all massages this month" or a first-visit code.
- The price the customer sees is the price they're charged. The service picker shows a service's sale price with the regular price struck through, or an offer badge. The booking page has a Discount code field, shows the discounted price with the original struck through, and says why a code was refused (used up, not for bookings, below its minimum spend).
- Deposits come from the discounted total. A 50% deposit on a ฿2,000 service at 20% off is ฿800.
- Which time counts. A discount's dates are checked against when the customer books, and a time window against the appointment time, so an off-peak discount applies to the off-peak appointment, whenever it was booked.
- Staff see the discount on the booking, by name and amount.
- Changing the party. When staff add or remove people, the booking is priced again with the discounts it was booked with, and the balance or refund due is worked out on the discounted totals. A discount the new party no longer qualifies for drops off; a new one isn't added.
- A code's use follows the booking. It's held while the booking is pending, counted once the booking is confirmed, and given back if the hold expires or the booking is cancelled before that.
- Commission. With Staff on, commission is paid on the discounted amount.
What it handles
- Two customers wanting the last opening. Four guests can book a 19:00 massage when four therapists and four mats are free. The fifth is refused, and a cancellation reopens the time for the next guest. A blocked period can't be placed over an existing booking, and nobody can book into one. On the booking page, a guest who loses the time to someone else is sent back to pick another, with the taken time shown as unavailable. Tested: "Booking: asset-backed services take one booking per free therapist" Tested: "Booking: wizard reserve conflicts"
- Payments that race or arrive twice. Two pay requests at once create one charge with the provider. A cancellation that lands while the charge is being created keeps the booking cancelled. A repeated payment webhook confirms the booking once. The background sweep never expires a booking whose online charge it can't check with the provider. Tested: "Booking: payment confirmation"
- Bank transfers. The customer sees the business's account details, uploads a slip, and the seats stay held while the slip waits for review. Staff accept or reject it with a reason, and a rejection gives the customer at least 12 more hours. Two staff accepting at once confirm the booking once, with one confirmation email. Staff without payment verification, or at another location, can't reject a slip. Tested: "Booking: bank transfer"
- Moving a booking. Staff move a booking to a free time and the customer is emailed. A move onto a taken time is refused and the booking stays where it was. Two moves of the same booking at once leave one consistent result, with seats counted once. A move to a departure with different prices is refused until the booking is repriced. Tested: "Booking: admin booking reschedule slot" Tested: "Booking: reschedule concurrency"
- Opening hours and time zones. A service is sold only inside its Location's opening hours, including split shifts, and a booking outside them is refused. The website's "open now" agrees with what booking offers. Times are shown in the Location's own time zone. Tested: "Booking: a Location's opening hours" Tested: "Booking: a slot is labelled in its Location's zone"
- A customer's private booking link. A customer manages a booking through a link with a secret token. A missing or wrong token gets "not found" and cancels nothing, and one booking's token doesn't work on another. Already booked? Find your booking shows a booking from its reference and the email or phone used to book. Changing or cancelling it needs the private link, which the guest asks for and gets at the email or LINE account on the booking. Tested: "Booking: guest manage token" Tested: "Booking: guest manage link recovery"
- Reminders. A confirmed booking gets one reminder, even when the reminder job runs again. Pending and cancelled bookings get none. Tested: "Booking: booking reminders"
- Locations in a multi-location business. A room must belong to a Location, while a provider may work at any. A booking for a service shared across Locations is refused until a Location is named, and a Location's manager can't write to another Location. Tested: "Booking: location-required writes"
- Discounted prices and deposits. A ฿2,000 service at 20% off with a 50% deposit rule reserves at ฿1,600 and charges an ฿800 deposit. The booking page's quote is the amount reserve charges, a refused code is explained, and a guest who enters a code sees the discounted price with the original struck through and books at it. The service picker shows a sale price and an offer badge, and nothing for a discount that holds only at certain times. Tested: "Booking: a discount comes off before the deposit" Tested: "Booking: the booking page's price is the one reserve charges" Tested: "Booking: a guest enters a discount code" Tested: "Booking: the service picker advertises discounts"
- Off-peak discounts and dates. A time window is checked against the appointment start and a discount's dates against when the customer books. Tested: "Booking: when a discount applies"
- A one-use code on an abandoned booking. When the hold on a booking with a one-use code expires, the code is free for the next customer, and paying that booking spends it. Tested: "Booking: a discount code's use follows the hold"
- Changing a discounted party. Adding or removing people works out the balance and the refund on the discounted totals. Tested: "Booking: amending a discounted party"
What you build on top
- Modules that add to booking. Customers puts its
search-and-scan finder in the New booking composer through the
booking.customer-finderslot. Staff shows the commission and tips a booking earned inbooking.record-section. Website adds a Website page tab to a resource throughbooking.resource-section. POS lets register staff work bookings under their PIN throughbooking.register-auth. Membership adds packages, points and member discounts. See Extend a Module. - Payments. Online payments go through the payment provider connected to the app. With no provider connected, bookings are reserved without online payment. Bank transfer can be switched on either way.
- Slip uploads. Transfer slips need the optional
mediafile storage connected to the app. Without it, transfers still work: the upload is hidden and staff check their bank instead. - Your words. A business type renames pages for the business: a car hire's bookings are Rentals, a tour operator's services are Tours. Rename other words with an override.
- In code. Your coding agent imports Booking only through its public API:
index.tsandserver/index.tsinapps/web/src/modules/booking/. See Build on a Module.
Limits
- Refunds are records. Staff return the money through the payment provider, in cash or by transfer, then record it; Booking doesn't send a refund to the provider.
- A booking's prices and discounts are fixed when it's made. Moving it to a departure with different prices is refused until staff reprice it.
- A booking paid with a package gets no discount.
Facts
- Kind: feature Module, can be switched on and off
- Needs: Audit log, Branches, Discounts, Formatting, i18n, Identity, Infra, Outbox, Standard UI
- Needed by: Nothing
- Adds to these when they're on: Account, Customers, Membership, Tour, Website
- Added to by: Finance, POS, Queue, Staff, Website
- Off by default for these business types: Clothing, Snack store
Pages
| Where | Path |
|---|---|
| Customer site | /booking |
| Admin | /admin/booking/bookings |
| Admin | /admin/booking/operations |
| Admin | /admin/booking/resources |
| Admin | /admin/booking/schedules |
| Admin | /admin/booking/blocked-periods |
| Admin | /admin/booking/schedule-resources |
| Admin | /admin/booking/rooms |
| Register | /register/bookings |
Permissions
Admin holds every key. The other roles listed hold it when the app first gets the Module; after that, roles are yours to change under Settings → Roles & Permissions.
| Permission | What it allows | Organization roles that start with it |
|---|---|---|
operations:write | Manage daily bookings, queues, customer arrivals, and routine front-desk operations. | Admin, Manager, Staff |
payments:verify | Verify manual payments and collect outstanding booking balances. | Admin, Manager, Staff |
customers:read | View customer lists, profiles, exports, and CRM insights. | Admin, Manager, Staff, Viewer |
manager:write | Perform manager-level overrides and consequential operational actions. | Admin, Manager |
refunds:write | Record manual refunds and void previously recorded refunds. | Admin, Manager |
operations:close | Open, update, export, and close operational shifts. | Admin, Manager |
rewards:write | Manage reward packages, customer points, and reward adjustments. | Admin, Manager |
settings:write | Configure resources, schedules, availability, fares, blocked periods, and queue setup. | Admin |
Data
- Tables:
customer,resource,schedule,blocked_period,booking,slot_claim,booking_event,availability_rule,payment,payment_refund,booking_payment_evidence,booking_redemption_intent,fare_category,resource_fare,operations_shift,operations_shift_event,appointment_asset,asset_capability,service_requirement,asset_availability_rule,asset_availability_exception,booking_allocation,asset_claim - File storage
media: optional, shared across the organization
Slots
Places other Modules and your app code can add to. See Extend a Module.
booking.register-authbooking.customer-finderbooking.record-sectionbooking.resource-section
Tested workflows
- Booking: the janitor runs only when timed work is due
- Booking follows Beam's live readiness
- Booking: admin booking reschedule
- Booking: admin booking reschedule cross branch
- Booking: admin booking reschedule slot
- Booking: admin operations
- Booking: admin payment routes
- Booking: admin recurrence
- Booking: advance notice per location
- Booking: adaptive scheduling server
- Booking: availability
- Booking: availability days
- Booking: appointment options
- Booking: asset-backed services take one booking per free therapist
- Booking: bank transfer
- Booking: Beam card and PromptPay on the booking page
- Booking: booking
- Booking: booking notifications
- Booking: booking public api
- Booking: booking reminders
- Booking: team alerts
- Booking: concurrency real pg
- Booking: deposit rule payments
- Booking: front desk manager operations
- Booking: guest manage link recovery
- Booking: guest manage token
- Booking: a Location's opening hours
- Booking: a slot is labelled in its Location's zone
- Booking ledger: rules keep the zone they were written in
- Booking ledger: branch-wide rules move onto their services
- Booking: location-required writes
- Booking: money safety janitor and webhooks
- Booking: outbound messages
- Booking: outbox drain
- Booking: passenger fares
- Booking: reservation signing secret
- Booking: payment confirmation
- Booking: slot claim overlap trigger
- Booking: provider scheduling
- Booking: public appointment assets
- Booking: public boundary
- Booking: recurrence generator
- Booking: reschedule concurrency
- Booking: reschedule slot booking engine
- Booking: reservation core
- Booking: spa sample data
- Booking: ticketing
- Booking: wizard flow
- Booking: wizard reserve conflicts
- Module contract: endpoint congruence (booking)
- Booking: deposit policy per location
- Booking: per-location setting overlay
- Booking: reminder timing per location
- Convention: booking branch scope SQL (static scan, not runtime coverage)
- Booking: admin writes are audited
- Booking: time before the therapist
- Booking: the company a booking is sold as
- Booking: admin home and search
- Booking: bookings list at the shell's location
- Booking: customer message settings
- Booking: car hire sample data
- Booking: gym sample data
- Booking: online classes sample data
- Booking: tour operator sample data
- Booking: a discount comes off before the deposit
- Booking: a discount code's use follows the hold
- Booking: amending a discounted party
- Booking: a party edit keeps the discount as it was booked
- Booking: a party edit can drop the discount and bring it back
- Booking: a party edit moves the deposit and the balance
- Booking: a retried reserve claims the discount it froze
- Booking: a retried seat reserve claims the discount it froze
- Booking: when a discount applies
- Booking: the booking page's price is the one reserve charges
- Booking: a booking keeps the discount name it was sold under
- Booking: the service picker advertises discounts
- Booking: a guest enters a discount code
- Booking + customers: activity projection (with Customers on)
- Booking + customers: source panel (with Customers on)
- Booking + customers: guest bookings resolve at reservation (with Customers on)
- Booking + Customers: one set of contact details (with Customers on)
- Booking + customers: the admin's New booking composer (with Customers on)
- Booking + customers: a booking for a picked person (with Customers on)
- Booking: admin settings: customer account ID (with Membership on)
- Booking: admin settings: existing codes never mutate (with Membership on)
- Booking: crm packages (with Membership on)
- Booking: crm points (with Membership on)
- Booking: crm portal (with Membership on)
- Booking: crm redemption (with Membership on)
- Booking: customer card (with Membership on)
- Booking: member booking (with Membership on)
- Booking: rewards accrual (with Membership on)
- Booking: historical package review form (with Membership on)
- Booking + membership: endpoint congruence (with Membership on)
- Booking: payments e2e (with Membership on)
- Booking + membership: reschedule redemption (with Membership on)
- Booking + membership: points settings (with Membership on)
- Booking + membership: the janitor wakes for a stuck redemption (with Membership on)
Operator Guide pages
Pages this Module adds to the app's built-in Guide for the people who run the business.
- Dining reservations