A reservation is booked against a reservation definition: a bookable thing such as "Dinner table", "Consultation" or "Chair 3", with its services, hours and capacity. Definitions are created in Studio Manager. The app books against them, lists the bookings, and hands arrivals to the check-in queue.
Setting one up, in order
Definitions live in Studio Manager; the app consumes them. Work in this order and the wizard behaves on the first try:
1. Create the definition and set it active. Inactive definitions are not offered, and an organization with none makes the wizard say No bookable services configured.
2. Add services with real durations and prices. Skip this only if one length fits everything — a definition with no services books against itself at 30 minutes.
3. Set work days and office hours, with the right timezone. This is what generates slots; get it wrong and the wizard says No open slots for the selected date. on a day you are open.
4. Add blocked time for closures and maintenance.
5. Set spots if more than one booking may share a slot, and checkInBy for how much lateness you tolerate.
6. Set the reminder schedule and templates — see notifications.
7. Book one yourself from the app and check the confirmation arrives. That single test exercises hours, slots, templates and the customer record at once.
The definition
reservation_definition fields that shape what staff see:
| Field | What it does |
|---|---|
name, title, description | Identity. name is the slug used in records; title is what the wizard shows. |
type | service, interval, event, service_point or pipeline. |
status | active or inactive. Only active definitions are offered. |
services[] | The bookable options: { name, duration, price, breakAfter }. Duration and break are minutes; break is the gap enforced after each slot. |
workDays[] | Days the definition is open. A date outside them is refused with "We are closed on this day". |
officeHours[] | Opening windows, with a timezone (defaults to the server's Intl timezone if unset). |
blockedTime[] | Ranges that never produce slots. |
spots | How many bookings may share one slot. Default 1. |
checkInBy | Minutes of grace before a booking is considered late. |
bookingType | unassigned or round-robin across hosts[]. |
servicePointKind, servicePointParent | For service_point definitions: which points it books. |
notifications[] | Reminder schedule: { offset, unit: minutes|hours|days, channel: email|sms|whatsapp }. |
notificationTemplate, cancellationTemplate | Template overrides for the confirmation and cancellation emails. |
form | A CRM form to collect extra details at booking. |
paymentRequired | Whether the booking needs payment. The mobile wizard does not take payment. |
Slots
The wizard asks the server for slots rather than computing them:
/crm/reservations/definitionsNo auth/crm/reservations/slotsNo authThe request carries reservationDefinitionId, serviceName and serviceDate. The server checks the date is in the future and on a work day, resolves the service, then generates slots from office hours minus blocked time, stepping by the service duration plus its break.
If services[] is empty the server books against the definition itself, using { name: <definition name>, duration: 30 }. The app mirrors that: the wizard offers one implicit service named after the definition, with a note that the default duration applies. Add real services when you need different lengths or prices.
Service names are matched by name, so renaming a service in the definition orphans slots for bookings made under the old name.
Booking from the app
Reservations → calendar icon opens a four-step wizard: definition, service and date, slot, customer. The app posts the flat booking body to POST /crm/reservations/create with status: confirmed, the selected location, source: agent, the customer's name and phone, party size, and the slot's start and end time.
Slot times come back as UTC instants and are stored that way; the list converts them to local time for display. Older records made elsewhere may carry a zone-less wall-clock string, which the app shows as written.
Reservation statuses
reservation.status is read-only from the client's point of view; the server moves it.
| Status | Set when |
|---|---|
new / pending | Created. pending is also what a walk-in from the check-in screen gets. |
confirmed | The booking is accepted. The app books straight into this state. |
used | Check-in assigned the party to a service point. |
rescheduled | Time changed. |
cancelled | Cancelled by staff (the app's Cancel button) or the customer. |
no_show | The check-in queue recorded a no-show. |
Sources record where a booking came from: walk-in, phone, online, partner, kiosk, agent (the app), email.
What the app can and cannot edit
| Action | Available on mobile |
|---|---|
| Book a new reservation | Yes, via the wizard |
| Cancel | Yes |
| Hand an arrival to the check-in queue | Yes — POST /checkin/from-reservation/:id |
| Change the time or party size | No — Studio Manager |
| Edit definitions, services, hours | No — Studio Manager |
| Send a reminder by hand | Endpoint exists (POST /crm/reservations/send-reminder/:id); no button in the app today |
The list shows every reservation the location can see, grouped into Today, Upcoming and Past (folded). Most bookings do not carry a location, and the app keeps those visible at every location rather than hiding them; a booking that does carry one is shown only there.
When something goes wrong
| Symptom | Cause | Fix |
|---|---|---|
| No bookable services configured in the wizard | No active definition, or none the account can see | Create one and set it active. |
| No open slots for the selected date. | Not a work day, outside office hours, all blocked, or already full | Check workDays, officeHours and blockedTime for that date, then spots. |
| Slots appear an hour out | The office-hours timezone is unset or wrong | Set the timezone on the definition; the server falls back to its own otherwise. |
| A note about the default duration | The definition has no services | Expected. Add services when you need real lengths or prices. |
| Bookings made before a rename look orphaned | Services are matched by name | Avoid renaming a live service; create a new one and retire the old. |
| A booking is invisible at one location | It carries a different location | Bookings with no location show everywhere; one with a location shows only there. |
| Check in is missing on a booking | It is cancelled, a no-show, or already used | Expected. Look for the party in the queue instead. |
| A double tap of Check in does nothing | The server refuses a second queue entry | Expected — they are already in the queue. |
| Staff want to change a time | The app cannot reschedule | Cancel and rebook, or edit in Studio Manager. |
| No confirmation email arrives | Template or channel not configured | Check the definition's templates and the org's email setup. |