Appointments Reference Public

Online Booking Portal

End-user documentation for the ERPat Appointments module (spa / salon / clinic booking).

Guide version: r1 Module version: 1.0.0 Updated: 2026-07-22 Estimated time: 22 min 3 views
Daily Operations

Online Booking Portal

The public, customer-facing "book online" side of Appointments. A member of the public — someone who is not logged into ERPat — finds your business, picks a service, chooses a provider and a free time, and confirms an appointment from any phone or browser. When no times are open, the same page lets them join the waitlist; after a completed visit, a separate link lets them leave a review.

Customer Manager Front desk Admin
ℹ️
Who does what here Nobody on staff "operates" these pages — customers do. Front desk and managers turn the portal on and shape it from the admin side: Appointment Settings, the service catalog, staff assignments, and each provider's HR working schedule. The public address is built from your company slug: /appointments/book/{company-slug}.

What the public portal is

The portal is a set of login-free web pages served under /appointments/book. It only appears and works when two conditions are met: the Appointments module is enabled for the business, and the business has ticked "Enable public booking page" in Settings. Miss either and every public page returns a 404 — a deliberate way to hide a portal that isn't turned on.

The public pages at a glance

????
Booking directory (landing)

/appointments/book — a multi-tenant landing page that lists every business accepting online bookings as clickable cards ("Book now"). Only populated when multi-tenancy is enabled; in a single-tenant install it looks empty, but the direct company URL still works.

????
Company booking page

/appointments/book/{company-slug} — the main flow for one business: three stacked steps that reveal progressively (pick service → provider + date + time → your details → confirm), plus the waitlist call-to-action.

Success / thank-you page

/appointments/book/success/{uuid} — a standalone confirmation page (also the target of the confirmation email's "Manage" link). No login and no tenant lookup needed.

Leave a review page

/appointments/review/{company-slug}/{uuid} — linked from the review-request email. Shows the star form only when the visit is Completed and not yet reviewed.

How the right business is resolved

Every public request carries the company slug in the URL. Behind the scenes the portal performs tenant resolution: it looks up the slug in the main directory, verifies the business is active, and switches to that business's data so the services, availability, and booking all operate within the correct company. A slug that is unknown, inactive, or points to a business with public booking switched off simply 404s.

????
Share the direct link, not the directory Put /appointments/book/{company-slug} in your SMS, social bio, and Google profile — it drops customers straight into the flow and skips the directory. The Settings page shows this exact URL as a read-only, clickable link so you can preview or copy it.

The customer booking journey (SOP)

The company booking page reveals three steps one at a time — each step only appears once the previous choice is made. Here is the happy path exactly as a customer experiences it.

SOP · Book an appointment online (happy path)

Actor: Customer (public, not logged in)

  1. Open the business's booking link

    Go to /appointments/book/{company-slug}, or click the business card on the directory. A teal hero banner shows the company logo (if set), the company name, and a "Book an Appointment" subtitle.

  2. Step 1 — Select a service

    Under "Select a service", click the desired service card. Services are grouped by category; anything uncategorized falls under "Other Services". Each card shows the service name, its duration in minutes, and its price. Only Active and Public services appear. Selecting a card reveals Step 2 and loads the providers who can perform it.

  3. Step 2 — Choose a provider and date

    The Provider dropdown defaults to "Any available provider". Leave it there to maximise the times shown (the system pools every capable staff member), or pick a specific person. Then choose a Date in the native date picker.

  4. Pick a time slot

    Available times load as clickable buttons. While they load you may see "Loading available times…"; before choosing a date the hint reads "Select a date to see available times." Each button shows a friendly 12-hour label (e.g. 2:30 PM). Clicking one selects it (it turns solid teal) and reveals Step 3. Changing the provider or date re-queries the times.

  5. Step 3 — Enter your details

    Fill Customer Name, Phone, and Email (all required); Notes is optional. The email must be valid — it is where the confirmation goes and how your account is found or created.

  6. Click "Confirm Booking"

    The teal Confirm Booking button re-checks that the slot is still free, then creates the appointment. On success an inline panel shows a large green check with "Appointment Confirmed" and "A confirmation has been sent to your email.", and the customer is sent to the success page.

  7. Keep the confirmation email & reference

    A Confirmed booking triggers a confirmation email to the customer (and a "new appointment" notice to staff). The success page shows a Reference code (the appointment UUID) in monospace — worth keeping; it is also embedded in the email links.

ℹ️
Every online booking starts Confirmed Successful online bookings are created as Confirmed with source = online — not Pending. (Pending is only used for some staff-entered bookings; see the Calendar page.) Only Confirmed appointments are eligible for reminder emails.

What happens the moment a customer confirms

When Confirm Booking succeeds, the portal:

  • Re-resolves the business, re-verifies the service is active and public, and confirms the chosen staff really is assigned to that service.
  • Re-checks the exact slot is still free inside a locked transaction (see the race check) so two customers can't grab the same time.
  • Finds or creates the customer by email, then writes the appointment (status Confirmed, source online) and its service line.
  • Emails a confirmation to the customer and a "new appointment" notice to the assigned staff (falling back to the company email if the staff member has no email).
⚠️
Email finds or creates the customer The booking uses the email as the key. If that email already exists as a user, that account is reused — the name and phone typed on the form still save on the appointment, but the existing customer record is what gets linked. A brand-new email creates a fresh customer. The name is split on the first space into first/last (a single word becomes the first name).
ℹ️
Emails are best-effort Confirmation and staff emails are sent after the booking is saved. If an email fails to send, the booking still succeeds (the failure is logged, not shown to the customer). The relevant email templates must exist and be non-empty — customise them in the core Email Templates editor (see Settings).

Booking form fields

FieldRequiredMeaning & notes
Service (Step 1 card)YesThe treatment wanted. Only Active + Public services appear; cards show duration & price. Grouped by category; uncategorized under "Other Services". Selecting one loads capable providers.
ProviderNoDefaults to "Any available provider". Options are loaded for the chosen service and list only staff assigned to it. If a slot is picked, the actual staff for that slot is captured from the slot button, not the dropdown.
DateYesNative date input. Only today through the Maximum advance booking window is bookable; past or too-far dates return no slots. Changing it re-queries slots.
Time slotYesChosen by clicking a slot button. Labels are 12-hour (e.g. "2:30 PM"); the stored value is 24-hour. Picking one reveals Step 3 and captures the slot's actual provider.
Customer NameYesFull name. Split on the first space into first/last when a new customer is created.
PhoneYesRequired on the main booking form. (Optional on the waitlist mini-form.)
EmailYesMust be a valid email. The confirmation goes here and it is the key used to find/create the customer.
NotesNoFree-text message to the business (preferences, requests). Saved on the appointment; defaults to empty.
????
Helping a customer who "can't book" All three of Name, Phone, and Email are required and the email must be valid. If a customer is stuck, that is the first thing to check. (The waitlist mini-form, by contrast, needs only Name and Email.)

The success / thank-you page

After confirming, the customer lands on /appointments/book/success/{uuid}. It shows a large green check, an "Appointment Confirmed" heading, the reassurance line about the email, the Reference code in monospace (when present), and a "Back to home" button linking to the site root. This page needs no login and no tenant lookup, so the link in the confirmation email works from anywhere.

What customers see when things are empty

No services "No services are available for booking right now."The business has no Active + Public services. Fix it in the Services catalog.
No slots "No available times for this date."Shown when the availability engine returns nothing for that day; the waitlist call-to-action appears alongside it.
Empty directory "No businesses are accepting online bookings yet."Directory empty-state — only populated when multi-tenancy is enabled.

How available time slots are calculated

The Time buttons are not free-typed — every one is computed by the availability engine. Customers only ever see start times the engine returns. Understanding the six inputs below is the fastest way to answer "why aren't there more times?" without touching any code.

ℹ️
The one-sentence version For the chosen service (and provider, if picked) the engine takes each capable staff member's working hours, subtracts their existing bookings plus every service's before/after buffer, and offers only the start times that fit the service duration, respect the minimum lead time, and stay within the maximum advance window — spaced by the slot interval.

The six inputs to a slot

InputWhat it does to the slotsSet where
Slot intervalThe spacing between offered start times (e.g. every 15 min). Smaller interval = more start times. Minimum 5, in steps of 5.Settings
Minimum lead timeHides (and rejects) any slot starting sooner than this many minutes from now — blocks last-minute bookings.Settings
Maximum advance daysThe booking horizon. Dates beyond this window return no slots at all.Settings
Provider working availabilityEach capable provider's start/end working times for that weekday, read from the HR weekly Schedule. No schedule = no slots for that person.HR Schedule
Existing bookingsTimes a provider is already busy are removed. Cancelled and No Show appointments are excluded (they don't block time).Calendar / bookings
Service duration + buffersA start time only survives if the service (plus its before/after buffer) fits without overlapping the provider's other bookings or their prep/cleanup.Services

Working hours come from the HR schedule

The engine reads each provider's working window — start and end times for the relevant weekday — from the HR weekly Schedule, not from the Appointments module. This is the single most common reason a provider shows no times.

????
No HR schedule ⇒ no slots A provider with no weekly HR Schedule with in/out times will never generate a single slot. Off-days, and overnight shifts where the out time is at or before the in time, also yield no slots. If a provider "has no times", check their HR schedule for that weekday first.

Buffers & duration shrink availability

Buffers are turnaround padding attached to a service (setup before, cleanup after). When checking whether a new booking fits, the engine pads the busy intervals of both the existing appointment and the new one, so services never overlap into each other's prep or cleanup time. A service with large buffers legitimately shows fewer slots than the raw working hours suggest. The duration itself must also fit end-to-end within a free gap.

Lead time and the horizon can look like "fully booked"

Two settings quietly trim the ends of the day and the calendar:

  • Minimum lead time removes slots that are too soon. With a 60-minute lead, nothing starting within the next hour is offered.
  • Maximum advance days removes dates that are too far. Pick a date past the horizon (seeded default 60 days) and you get "No available times" — even though nothing is booked.
????
"The site says no times" ≠ "fully booked" When a customer reports no times, check the date is inside the max-advance window and that the chosen provider actually works (has a schedule) that day before assuming you're fully booked. A too-soon or too-far date returns "No available times" for entirely legitimate reasons.

"Any available provider" pools everyone

Leaving the provider on Any available provider pools every staff member assigned to the service and returns their combined open times (the earliest option at each time). Picking a specific slot then assigns whichever provider that slot belongs to. This is the setting that shows customers the most options.

The race check on submit

Two customers can see the same slot at once. To keep only one from winning, Confirm Booking re-checks availability inside a locked transaction with a per-provider, per-day lock. The second submitter gets the inline error "That time slot is no longer available. Please choose another." and the button re-enables so they can pick a different time.

⚠️
To open up more times Widen provider schedules, reduce service buffers, lower the minimum lead time, or shorten the slot interval (15 min gives more slots than 30). Also make sure each public service has at least one assigned provider — a service with no providers has no slots.

Joining the waitlist online

When a chosen date returns "No available times for this date.", a waitlist call-to-action appears right below the slots. It lets the customer ask to be emailed if a spot opens, without booking anything now.

SOP · Join the waitlist from the public page

Actor: Customer (public, not logged in)

  1. Reach a "no slots" result

    Follow Steps 1–2 of the booking journey and pick a date that shows "No available times for this date." The waitlist prompt appears.

  2. Click "Join the waitlist"

    This reveals a mini-form. The service and the preferred date you had selected are carried over automatically.

  3. Fill Name and Email (Phone optional)

    On this mini-form only Name and a valid Email are required; Phone is optional. The email is where the "a spot opened" notice is sent.

  4. Submit

    The form is replaced in place with the success line: "You're on the waitlist — we'll email you if a spot opens." A waitlist entry is created with status Waiting and source = online.

ℹ️
What happens after they join When a matching Confirmed appointment is later Cancelled, matching Waiting entries are auto-emailed the "a spot just opened" message (with a booking-page link) and moved to Notified so they aren't blasted again. Auto-notify is capped at 20 entries per cancellation. See the dedicated Waitlist page for the matching rules and staff actions.
????
Waitlist needs public booking ON too The public waitlist mini-form only appears when the public booking page is enabled and the service is Active + Public. If public booking is off, customers can't self-join from the portal (staff can still add waitlist entries from the admin side).

Waitlist statuses a customer's entry moves through

Waiting WaitingQueued and not yet contacted. Online joins start here. Only Waiting rows are eligible for auto-notify on a cancellation.
Notified NotifiedThe "slot opened" email has been sent; the entry won't be re-blasted on future openings.
Booked BookedThe customer converted and re-booked into a real appointment.
Cancelled CancelledThe waitlist entry was withdrawn/cancelled.

Leaving a review (public flow)

After a visit, a customer can leave a 1–5 star review with an optional comment. The link arrives by email and points at /appointments/review/{company-slug}/{uuid}. The page is state-driven — it only shows the star form when the visit is genuinely reviewable.

Where the review link comes from

Reviews are invited by the automated review-request email, sent by an hourly job a configured number of hours after the appointment is marked Completed — once per appointment. That email carries the {REVIEW_URL} link to this page. The whole flow depends on staff marking the visit Completed and on "Enable review requests" being on in Settings.

What the review page shows (three states)

StateWhat the customer sees
Reviewable (Completed, not yet reviewed)A teal hero with logo + name, a "Leave a Review" heading, a row of 5 clickable stars (hover highlights amber), an optional comment box ("Tell us about your experience (optional)"), and a full-width teal "Submit Review" button.
Already reviewedA green check with "You've already reviewed this visit. Thank you!" — one review per appointment is allowed.
Not yet CompletedA muted message that the review isn't available yet. Customers who follow the link too early see this.

SOP · Leave a review after a completed visit

Actor: Customer (public, not logged in)

  1. Open the review link from the email

    /appointments/review/{company-slug}/{uuid}. If the visit is Completed and not yet reviewed, the star form shows.

  2. Click the stars

    Choose 1–5 stars — filled stars light amber (#f0ad4e); hovering previews the level. A rating is required; submitting without one shows "Please select a star rating."

  3. Add a comment (optional)

    Type any feedback in the comment box, or leave it blank.

  4. Submit the review

    Click Submit Review. The card is replaced in place with a green check and "Thanks for your feedback!" The review is saved tied to the appointment, customer, staff, and service, and is published immediately.

????
Only Completed visits, only once Completed is the only status that unlocks the review page. No-shows and cancellations never qualify. Each appointment can be reviewed exactly once — a duplicate or concurrent submit is quietly turned into "You've already reviewed this visit." by a uniqueness rule.
????
To encourage reviews Mark visits Completed promptly — completion is what starts the review-request clock. Only published reviews feed average ratings and the recent-reviews list, and reviews here are published immediately by default. See Reports for how ratings roll up per staff/service.

Settings that shape the portal

Everything about the portal is controlled from the admin side. These are the per-tenant settings that most directly change what customers see and can do — all on the Appointment Settings page, which requires the Manage Appointment Settings permission.

SettingEffect on the portalSeeded default
Enable public booking pageThe master on/off. Off ⇒ the whole portal 404s; customers can't book or join the waitlist.Off
Slot interval (minutes)Spacing between offered start times. Smaller = more slots. Min 5, step 5.15
Minimum lead time (minutes)Hides slots starting too soon; blocks last-minute online bookings.60
Maximum advance booking (days)How far ahead customers may book. Dates beyond return no slots.60
Cancellation window (hours)How many hours before start a customer may still cancel/change.24
Public booking URLRead-only, clickable — derived from the company slug. Opens the live portal in a new tab so you can preview/share it.from slug
Enable review requestsMaster switch for the automated post-visit review email that links to the public review page.Off
Review request delay (hours)How long after completion the review email is sent.24
ℹ️
Beyond Settings — the catalog also shapes the portal What appears online is equally driven by the Services catalog: only Active + Public services with at least one assigned provider show up, and providers must have an HR schedule to produce slots. The portal is the front window; Settings, Services, staff assignments, and HR schedules are the levers behind it.

SOP · Turn on public booking & prepare the portal

Actor: Manager / Front desk (admin side)

  1. Enable the Appointments module

    In Settings → Manage Modules, make sure the Appointments module is enabled for the business. Without it, the portal 404s and the settings page won't appear.

  2. Tick "Enable public booking page"

    On Appointment Settings, turn on the master switch. Note the read-only Public booking URL shown just beneath it (built from your company slug).

  3. Build the public catalog

    In Services, create your categories and services and mark the ones you want online as Active and Public. Private or inactive services never reach the portal.

  4. Assign staff to each service

    Only staff explicitly assigned to a service are offered for it. A service with no assigned staff has no providers and therefore no slots.

  5. Give each provider an HR schedule

    Make sure every provider has an HR weekly Schedule with working in/out times — otherwise no slots will generate for them, no matter what else is set.

  6. Tune the booking window

    Set slot interval, minimum lead time, and maximum advance days so the engine offers the right times, then Save.

  7. Preview and share the URL

    Click the Public booking URL link (opens in a new tab) to see exactly what customers see, then share /appointments/book/{company-slug} in your SMS, social bio, and Google profile.

Permissions & access model

The public pages themselves are fully public — no permission gates apply to booking, slots, providers, submit, success, the waitlist, or reviews. Access is instead controlled by the two conditions above (module enabled and public booking on), plus a business rule for reviews (status must be Completed and no existing review). The admin-side permissions that configure the portal are:

PermissionGoverns
Manage Appointment SettingsTurning public booking on and setting slot / lead / advance / review windows.
Services (+ Create/Update/Delete)Building the public catalog that customers browse and the staff assignments that produce slots.
Appointments (+ Create/Update/Delete)The resulting bookings once they land in the calendar.
Waitlist (+ Create/Update/Delete)Managing the waitlist entries customers create from the portal.
ℹ️
Admin bypass Users flagged as administrators bypass all admin-side permission checks. The public pages need no permissions at all.

Troubleshooting & edge cases

The most common "why doesn't the portal work?" questions, with the fix.

The public booking page shows a 404. Why?

The portal silently 404s unless both the Appointments module is enabled and "Enable public booking page" is turned on in Settings. A slug that is unknown, inactive, or belongs to a business with booking off also 404s. Check both switches and the slug.

No time slots appear for a provider.

The engine reads working hours from the HR weekly Schedule (not the Appointments module). A provider with no schedule with in/out times for that weekday gets no slots. Off-days and overnight shifts (out time at or before in time) also yield nothing. Confirm the provider actually works that day.

A service I created isn't on the booking page.

Only services that are both Active and Public show online, and each needs at least one assigned provider to produce slots. A private or inactive service is invisible to customers even if staff are assigned. Fix it in Services.

The date says "No available times" but we're not fully booked.

Slots respect the minimum lead time and maximum advance days. A too-soon or too-far date legitimately returns "No available times" — easy to mistake for "fully booked". Check the date is inside the window and the provider is working that day.

A customer got "That time slot is no longer available."

Two customers raced for the same slot. The submit re-checks availability inside a locked transaction with a per-provider/day lock, so the second submitter is rejected even though they saw the slot moments earlier. They just pick another time — the button re-enables automatically.

Fewer slots appear than the working hours suggest.

Buffers count against availability: a service with large before/after buffers reserves prep/cleanup time around each booking, so the raw working hours produce fewer offer-able starts. Reduce the buffer, shorten the slot interval, or widen schedules to open up more.

A returning customer booked but their profile didn't update.

Booking finds the customer by email. If that email already exists, the existing account is reused — the name/phone typed on the form still save on the appointment, but the existing user record is what gets linked. This is expected behavior, not a bug.

The customer says they never got a confirmation email.

Emails are best-effort after the booking commits — a booking still succeeds even if the email fails (the failure is logged, not shown to the customer). Emails also require the matching email templates to exist and be non-empty. The customer can still use the success page and its Reference.

The confirmation/review links point at the wrong place.

Public confirmation and review links are built from the company slug — the only slug the portal resolves the business by. A custom booking slug that differs from the company slug can break these links. Keep them aligned.

The review page says the review isn't available.

The review page only works once staff mark the appointment Completed. Before completion, customers who follow the link see a "not available" message. Each appointment can be reviewed only once; a duplicate quietly becomes "You've already reviewed this visit."

The directory at /appointments/book looks empty.

The directory landing page is only populated when multi-tenancy is enabled. In single-tenant installs it looks empty, but the direct company URL /appointments/book/{company-slug} still works. Share the direct link.

Why is Phone required to book but optional for the waitlist?

The main booking form requires Name, Phone, and a valid Email. The waitlist mini-form only needs Name and a valid Email — Phone there is optional. If a customer can't submit a booking, the missing Phone or an invalid Email is the usual cause.


Appointment status legend

Statuses a portal booking can reach (set by staff after the online booking is created). Only Confirmed is produced by the portal itself; the rest are staff-driven and shown here for context.

Pending PendingBooking exists but not yet confirmed. Not produced online — online bookings start Confirmed — but shown in staff views. Amber #f0ad4e.
Confirmed ConfirmedEvery successful online booking starts here; a confirmation email is sent. Only Confirmed appointments get reminders. Teal #1d97a6.
Checked In Checked InCustomer has arrived / been checked in at the front desk (staff-set). Light-blue #5bc0de.
In Progress In ProgressService currently being performed (staff-set). Light-blue #5bc0de.
Completed CompletedVisit finished. The only status that unlocks the public review page. Green #5cb85c.
Cancelled CancelledCancelling a Confirmed slot can trigger waitlist slot-open notifications. Excluded from availability. Red #d9534f.
No Show No ShowCustomer did not arrive. Excluded from availability; sends no email. Grey #777777.

Related pages

Was this guide helpful?

Report a content problem