Booking & Appointments

Add appointment scheduling and multi-day reservation functionality to your Larapen site. Manage services, providers, weekly schedules, and an interactive booking calendar: with optional payment integration.

Dual Booking Modes

Switch between time-slot appointments (e.g., consultations) and multi-day reservations (e.g., hotel stays) from a single setting.

Service & Provider Management

Create bookable services with pricing, duration, and capacity. Assign providers with individual weekly schedules and blocked dates.

Interactive Calendar

Admin calendar view with provider filtering. Front-end calendar with real-time slot availability powered by AJAX.

Payment Integration

Optional payment requirement before confirmation. Supports Stripe, PayPal, Paddle, and MoMo via the Payable interface.

Email Notifications

Configurable notifications for clients, admins, and providers on booking creation, status changes, and cancellations.

Multi-language Support

Service names, slugs, and descriptions are translatable. All UI strings use the translation system.

Use Cases

Appointment Mode

  • Salon or Spa: Clients pick a service (haircut, massage), a date, and a time slot from available openings.
  • Consulting Firm: Visitors book a 30-minute or 60-minute consultation with a specific advisor.
  • Medical Practice: Patients schedule visits with practitioners. Break times and blocked dates keep the calendar accurate.

Reservation Mode

  • Hotel / B&B: Guests select check-in and check-out dates with per-night pricing and capacity limits.
  • Venue Rental: Event organizers reserve a venue for multiple days with minimum/maximum stay constraints.
  • Equipment Rental: Customers reserve gear for a date range with overlapping reservation detection.

Requirements

  • Larapen CMS v1.0.0 or later
  • PHP 8.3+
  • MySQL 8.0+
Optional: To enable payment collection before booking confirmation, install and activate at least one payment gateway add-on (Stripe, PayPal, Paddle, or MoMo).

Installation

Step 1: Place the Add-on

Copy or symlink the booking folder into your Larapen "extensions/addons" directory:

Step 2: Activate the Add-on

Go to Admin → Add-ons → Installed Add-ons and activate Booking & Appointments.

Step 3: Run Migrations

This creates 6 tables: booking_services, booking_providers, booking_provider_schedules, booking_provider_service (pivot), booking_blocked_dates, and booking_appointments.

Step 4: Set Permissions

The add-on registers 13 permissions (see Permissions). Assign them to admin roles via Admin → Users → Roles & Permissions.

Step 5: Configure

Navigate to Admin → Booking → Settings and configure the booking type, scheduling options, and notification preferences. See Configuration.

Step 6: Create Services & Providers

  1. Go to Admin → Booking → Services and create at least one active service.
  2. Go to Admin → Booking → Providers and add providers (staff members). The system initializes a default Mon–Fri 9:00–17:00 schedule for each new provider.
  3. Assign services to providers and customize their weekly schedules.
Quick start: Even without creating providers, the booking system works using a built-in default schedule (Mon–Fri, 09:00–17:00 with a 12:00–13:00 break). Providers can be added later.

Configuration

All settings are managed in Admin → Booking → Settings (stored in the settings table, group booking). Defaults are defined in config/booking.php.

Setting Description Default
booking_type Booking mode: appointment (time-slot) or reservation (date-range). appointment
booking_enabled Show or hide the booking page on the front-end. true
booking_multi_provider Allow clients to choose a specific provider when booking. When disabled, the system auto-assigns a provider. false
booking_pending_blocks_slot When enabled, pending appointments also block the time slot. When disabled, only confirmed/completed appointments block slots. true
booking_advance_days How many days in advance clients can book. 60
booking_min_advance_hours Minimum hours before an appointment can be booked (prevents last-minute bookings). 2
booking_slot_interval Override the time slot interval in minutes. Leave empty to use the service’s duration. (null: uses service duration)
booking_notification_email Email address to receive admin booking notifications. (empty)
booking_require_payment Require payment before booking confirmation. Only applies to services with a price > 0. false
booking_cancellation_policy Free-text cancellation policy displayed on the booking page. (empty)
booking_captcha_enabled Enable CAPTCHA challenge on the booking form. false

Notification Settings

Setting Description Default
booking_notify_admin_on_new_booking Send email to the notification address on new bookings. true
booking_notify_client_on_booking Send confirmation email to the client on booking submission. true
booking_notify_client_on_status_change Notify client when booking status changes (confirmed, cancelled, completed). true
booking_notify_provider_on_new_booking Notify the assigned provider when they receive a new booking. true
booking_notify_provider_on_cancellation Notify the assigned provider when a booking is cancelled. true

Booking Types

The add-on supports two fundamentally different booking paradigms. The active mode is controlled by the booking_type setting and affects the front-end form, admin views, slot generation logic, and availability calculations.

Appointment Mode

Single-date, time-slot based bookings. Examples: haircut at 3pm, consultation at 10am, medical visit at 14:30.

  • Services define a duration in minutes (e.g., 30, 60, 90).
  • The system generates available time slots from the provider’s weekly schedule, excluding breaks and existing bookings.
  • Clients pick a date from the calendar, then select a specific time slot.
  • Capacity-aware: max_capacity allows multiple simultaneous bookings per slot (e.g., a gym class with 10 spots).
  • The start_time and end_time fields are used; check_in_date / check_out_date are null.

Reservation Mode

Multi-day, date-range based bookings. Examples: hotel room for 3 nights, venue rental for a weekend.

  • Services define price per night, min/max nights, and max guests.
  • Clients select check-in and check-out dates from a calendar that shows day-level availability.
  • Total price is calculated as: price_per_night × number of nights.
  • Overlap detection prevents double-booking: the system counts reservations occupying each date and compares against max_capacity.
  • The check_in_date, check_out_date, and num_guests fields are used; start_time / end_time are null.
Important: Switching the booking type after data has been collected does not alter existing appointments. The admin list and calendar views handle both types regardless of the current setting.

Admin: Services

The Services page (Booking → Services) manages your catalog of bookable services.

Services List

A sortable, paginated table showing:

  • Name (translatable)
  • Duration (formatted, e.g., “1h 30min”): appointment mode
  • Price (formatted with currency): or Price per Night in reservation mode
  • Max Capacity
  • Appointments count
  • Status (active/inactive badge)
  • Position (display order)

Per-row actions: Edit, Delete.

Creating & Editing Services

Common Fields (Both Modes)

  • Name (translatable, required for default locale)
  • Slug (translatable, auto-generated if empty)
  • Description (translatable)
  • Price (numeric, optional)
  • Currency (required, from active currencies)
  • Max Capacity (integer, 1–100)
  • Active toggle
  • Position (display order)

Appointment Mode Fields

  • Duration (minutes): required, 5–480 minutes. Determines slot length.

Reservation Mode Fields

  • Duration (minutes): optional (not used for slot generation in reservation mode).
  • Price per Night: used to calculate total price.
  • Min Nights / Max Nights: stay length constraints.
  • Max Guests: per-reservation guest limit.

Admin: Providers

Providers represent the staff members, rooms, or resources that deliver your services. Managed at Booking → Providers.

Providers List

A paginated table showing:

  • Avatar (or initials fallback)
  • Name, Email, Phone
  • Assigned services count
  • Appointments count
  • Status (active/inactive)

Per-row actions: Edit, Delete.

Creating a Provider

  • Name, Email, Phone
  • Bio: text description
  • Avatar: image upload (stored in booking/providers/ on the public disk)
  • Linked User Account: optional FK to the users table
  • Assigned Services: multi-select from active services
  • Active toggle, Position

When a provider is created, a default weekly schedule is automatically initialized: Monday–Friday 09:00–17:00 with a 12:00–13:00 break. Saturday and Sunday are off.

Weekly Schedule

The schedule editor (Providers → {provider} → Edit → Schedule tab) allows configuring each day of the week:

  • Available toggle (on/off)
  • Start Time and End Time
  • Break Start and Break End (optional lunch/rest period)

Slots that overlap the break window are automatically excluded from availability.

Blocked Dates

Individual dates when a provider is unavailable (holidays, sick days, vacations). Managed from the provider edit page.

  • Date (required)
  • Reason (optional: e.g., “National Holiday”, “Vacation”)

Blocked dates can also be global (no provider assigned) to block all providers on that date.

Admin: Appointments

The Appointments page (Booking → Appointments) shows all bookings in a paginated table.

Appointments List

Filterable by status. Columns include:

  • Client name & email
  • Service name
  • Provider name
  • Date & time (or check-in/check-out for reservations)
  • Status badge (pending/confirmed/cancelled/completed)
  • Payment status (if payment is enabled)

Stats cards at the top show totals, pending count, today’s appointments, this week, and upcoming. In reservation mode, additional stats show check-ins today, check-outs today, and active stays.

Appointment Detail & Status Management

The detail page (Appointments → {appointment}) shows:

  • Client information: name, email, phone, IP address, booked-at timestamp
  • Booking information: service, provider, date/time (or date range), total price
  • Payment details (if applicable): status, method, reference, paid-at timestamp
  • Status management: buttons to change status with transitions:
    • Pending → Confirmed, Cancelled
    • Confirmed → Completed, Cancelled, Revert to Pending
    • Completed → Revert to Confirmed
    • Cancelled → Reopen (back to Pending)
  • Cancellation reason: shown when cancelling; cleared when reopening
  • Admin notes: internal notes not visible to the client
  • Client notes: notes submitted by the client during booking
Status change notifications: When a status changes to Confirmed, Cancelled, or Completed, the client is automatically emailed (if booking_notify_client_on_status_change is enabled). Cancellations also notify the assigned provider.

Calendar View

The Calendar page (Booking → Appointments → Calendar) provides a visual month view:

  • Events are loaded via AJAX (GET admin/booking/appointments/calendar-events).
  • Filter by provider using the dropdown.
  • Appointments show as time-based events; reservations show as multi-day spans.
  • Color-coded by status (warning=pending, success=confirmed, danger=cancelled, info=completed).
  • Click an event to navigate to the appointment detail page.

Admin: Settings

The settings page (Booking → Settings) is organized into sections:

General Settings

  • Booking Type: radio selector for Appointment or Reservation mode with descriptions.
  • Enable Booking: toggle to show/hide the front-end booking page.
  • Multi-Provider Mode: let clients choose their provider.

Scheduling

  • Pending Appointments Block Slots: toggle.
  • Slot Interval: override the default (service duration).
  • Advance Booking (days): how far ahead clients can book.
  • Minimum Advance (hours): prevents last-minute bookings.
  • Cancellation Policy: free-text displayed on the booking page.

Payment

  • Require Payment: toggle. Only applies to services with price > 0.
  • A warning is shown if no payment gateway add-on is active.

Notifications

  • Notification Email: admin email address for booking alerts.
  • Five toggle switches controlling which emails are sent (see Notifications).

CAPTCHA

  • Enable CAPTCHA on Booking Form: toggle. Requires a CAPTCHA provider to be configured in core settings.

Front-end: Booking Page

The booking page is available at /{locale}/booking and provides a step-by-step wizard.

Routes

MethodURLRoute NameDescription
GET /{locale}/booking booking.index.localized Booking wizard page
POST /{locale}/booking booking.store.localized Submit a booking
GET /{locale}/booking/confirmation/{appointment} booking.confirmation.localized Confirmation page
GET /{locale}/booking/my-bookings booking.my-bookings.localized User’s booking history (auth required)

Non-localized variants (without {locale}) are also registered.

Appointment Wizard Steps

  1. Select Service: card grid of active services showing name, description, duration, and price.
  2. Choose Provider: shown only if multi-provider mode is enabled. Includes an “Any Available Provider” option.
  3. Pick Date & Time: interactive calendar showing available/unavailable days. Selecting a date loads time slots via AJAX.
  4. Your Details: name, email, phone (optional), notes (optional). Pre-filled for authenticated users.
  5. Confirm: summary card with all selections. Submit button triggers the booking.

Reservation Wizard Steps

  1. Select Service: card grid showing name, description, price per night, and stay range constraints.
  2. Select Dates: interactive calendar for picking check-in and check-out dates. Real-time availability check via AJAX.
  3. Guests: number of guests input (if max_guests is configured).
  4. Your Details: client information form.
  5. Confirm: summary with date range, nights, total price. Submit button triggers the reservation.

Slot & Availability API

Three JSON endpoints power the front-end calendar and slot selection:

GET /{locale}/booking/slots
Description

Returns available time slots for a specific service, provider, and date. Used in appointment mode.

Query Parameters
service_id Required Service ID
provider_id Optional Provider ID (null = any available)
date Required Date (YYYY-MM-DD)
Response
GET /{locale}/booking/availability
Description

Returns day-level availability for an entire month. Used to render the calendar with available/unavailable indicators.

Query Parameters
year Required Year (2024–2030)
month Required Month (1–12)
service_id Optional Service ID
provider_id Optional Provider ID
Response

Values: past, available, unavailable.

GET /{locale}/booking/check-availability
Description

Checks if a specific date range is available for reservation. Used in reservation mode.

Query Parameters
service_id Required Service ID
provider_id Optional Provider ID
check_in_date Required Check-in date (YYYY-MM-DD)
check_out_date Required Check-out date (YYYY-MM-DD, must be after check_in_date)
Response

Slot Generation Logic

For appointment mode, time slots are generated as follows:

  1. Load the provider’s schedule for the requested day of week.
  2. Check for blocked dates (provider-specific and global).
  3. Generate slots from start_time to end_time at intervals of slot_interval (or service duration).
  4. Exclude slots that overlap the break window.
  5. Exclude slots before the minimum advance cutoff time.
  6. For each candidate slot, count existing blocking appointments (confirmed + completed, and pending if pending_blocks_slot is enabled).
  7. Include the slot only if the overlap count is below max_capacity.

When no provider is specified, the system aggregates slots across all active providers for the service. If no providers exist at all, a built-in default schedule (Mon–Fri 09:00–17:00, break 12:00–13:00) is used as a fallback.

Confirmation Page

After a successful booking (or successful payment), the user is redirected to /{locale}/booking/confirmation/{appointment}.

  • Shows a success message with appointment/reservation details.
  • Displays service name, provider, date/time (or date range for reservations), and total price.
  • Status note explaining the booking is pending confirmation.
  • Links to “Back to Home” and “Book Another”.

Payment Checkout

When booking_require_payment is enabled and the appointment has a total price > 0, the booking flow redirects to a checkout page instead of the confirmation page.

Routes

MethodURLRoute NameDescription
GET /{locale}/booking/checkout/{appointment} booking.checkout.localized Payment checkout page
POST /{locale}/booking/checkout/{appointment} booking.checkout.process.localized Process payment

Payable Interface

The Appointment model implements the App\Contracts\Payable interface, providing:

  • getPayableAmount(): returns total price
  • getPayableCurrency(): from the service’s currency or site default
  • getPayableDescription(): e.g., “Appointment: Haircut on Mar 15, 2026”
  • getPayableCustomerEmail(), getPayableCustomerName()
  • markAsPaid(): sets status to Confirmed, payment_status to “paid”
  • markPaymentFailed(): sets payment_status to “failed”
  • getPaymentSuccessUrl(): redirects to confirmation page
  • getPaymentCancelUrl(): redirects back to checkout page

Supported Payment Gateways

The checkout page works with any active payment gateway add-on:

  • Stripe: client-side Payment Intents with Stripe.js
  • PayPal: redirect-based checkout
  • Paddle: inline overlay or redirect
  • MoMo: mobile money with phone number input
Note: If no payment gateway add-on is active while booking_require_payment is enabled, a warning is shown on the admin settings page. The checkout page will show no payment options.

My Bookings

Authenticated users can view their booking history at /{locale}/booking/my-bookings.

  • Matches bookings by user_id or client_email (covers bookings made before registration).
  • Paginated list (15 per page) sorted by date descending.
  • Each entry shows: service name, provider, date/time (or date range), status badge, and payment status.

This page is also accessible from the user account menu via the “My Bookings” link (registered in addon.json under provides.user_menu).

Notifications

The add-on uses Laravel’s Notification system with on-demand mail recipients. All notifications are sent via the BookingManager service and silently catch any sending errors.

Notification Class Recipient Trigger Setting
BookingConfirmationNotification Client Booking created (after payment, if required) notify_client_on_booking
NewBookingAdminNotification Admin (notification_email) Booking created notify_admin_on_new_booking
NewBookingProviderNotification Assigned provider Booking created notify_provider_on_new_booking
BookingStatusChangeNotification Client Status changed to confirmed/cancelled/completed notify_client_on_status_change
BookingCancellationProviderNotification Assigned provider Booking cancelled notify_provider_on_cancellation

Each notification adapts its subject line and content based on the booking_type (appointment vs. reservation), including appropriate date/time or date-range details.

Observer-driven: Status change and cancellation notifications are triggered by the AppointmentObserver, which watches the status field for changes. This ensures notifications fire regardless of how the status is updated (admin panel, API, etc.).

Updating

Step 1: Replace Files

Replace the add-on directory with the new version.

Step 2: Run Migrations

Step 3: Rebuild Assets

Required if the update includes new or modified theme SCSS/JS files.

Step 4: Clear Caches

Backup first: Always back up your database before running migrations on a production system.

Troubleshooting

Calendar shows no available days

  • Ensure at least one active service exists.
  • If providers are configured, verify at least one provider has an active schedule for the relevant day of the week.
  • Check that booking_advance_days is set to a value greater than 0.
  • Verify no global blocked dates cover the entire visible period.
  • If no providers exist, the system uses a default Mon–Fri schedule: weekends will show as unavailable.

No time slots appear for a selected date

  • The selected date may be within the booking_min_advance_hours cutoff (e.g., today before the minimum advance window).
  • All slots may be booked. Check if booking_pending_blocks_slot is enabled: pending appointments count toward capacity.
  • The provider’s schedule may be set to unavailable for that day of the week.
  • A blocked date may exist for the provider or globally.
  • The service duration may exceed the available time window (e.g., 3-hour service but only 2 hours available after the break).

Booking page returns 404

  • Ensure booking_enabled is set to true in settings. The controller throws a 404 when booking is disabled.
  • Verify the add-on is activated in Admin → Add-ons.

Reservation mode: “dates not available” despite empty calendar

  • Check blocked dates across the entire date range (any single blocked date invalidates the range).
  • Verify min/max nights constraints on the service. A 2-night stay on a service with min_nights = 3 will fail.
  • Ensure max_capacity is set correctly. A capacity of 1 means only one reservation can occupy any given date.

Client not receiving confirmation emails

  • Check that booking_notify_client_on_booking is enabled in settings.
  • Verify your mail configuration works (SMTP, Mailgun, etc.) in Admin → Settings → Mail.
  • Notification failures are silently caught: check storage/logs/laravel.log for any errors.

Payment checkout shows no payment methods

  • Ensure at least one payment gateway add-on (Stripe, PayPal, Paddle, or MoMo) is installed and activated.
  • Verify the gateway is properly configured with API keys in its own settings.
  • The PaymentService::getAvailableGateways() only returns gateways that are fully configured.

Multi-provider mode not showing provider selector

  • Ensure booking_multi_provider is enabled in settings.
  • Verify at least one active provider exists and is assigned to the selected service.

Status change notifications not sending

  • The AppointmentObserver handles status change notifications. Ensure it is registered in BookingServiceProvider::boot().
  • Only transitions to Confirmed, Cancelled, or Completed trigger client notifications.
  • Provider cancellation notifications require the provider to have an email address set.

Was this article helpful?

Thank you for your feedback!

Still need help? Create a support ticket

Create a Ticket