Add time-slot appointment scheduling to your Larapen site. Manage services, providers, weekly schedules, and an interactive booking calendar, with optional payment integration.

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.

Time Slot Generation

Automatic slot generation from provider schedules. Respects breaks, blocked dates, capacity limits, and minimum advance time.

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 appointment creation, status changes, and cancellations.

Multi-language Support

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

Use Cases

  • 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.
  • Fitness Classes: Members reserve spots in group sessions with capacity-limited time slots.
  • Tutoring & Coaching: Students book individual or group sessions with tutors, each with their own availability schedule.

Requirements

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

Installation

Step 1: Upload the Add-on

In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.

Step 2: Activate the Add-on

Find Appointment Scheduling in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.

Step 3: Configure

Navigate to Admin → Appointments → Settings to configure services, availability rules, booking windows, and notifications. See Configuration.

Purchase Code (License Key)

Appointments is sold as a separate product, so it has its own purchase code (license key), distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate Appointments in Admin panel → Add-ons.

Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.

Platform / Marketplace How you get the purchase code Where to find it again
bedigit.com Store
In-site purchase (Shop)
Generated automatically when the order is paid, then sent by email, either in its own license email, or inside the order confirmation email. My Account → My Licenses on bedigit.com
Gumroad Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com
Envato Market
CodeCanyon
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. Envato account → Downloads → License certificate & purchase code
Check your spam folder. For both bedigit.com Store and Gumroad purchases, the purchase code is delivered by email. Automated license emails are very often filtered, so if the message is not in your inbox, look in your spam / junk folder before contacting support, and add our sender address to your contacts or allow list.

1. bedigit.com Store (in-site purchase)

  • As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit: buying 3 units gives 3 distinct keys).
  • It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
  • The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
  • The matching invoice is under My Account → My Orders.

2. Gumroad

  • A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
  • The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
  • When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
  • Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.

3. Envato Market (CodeCanyon)

  • Envato purchase codes are issued and delivered by Envato Market, never emailed by us, so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
  • Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
  • An Envato purchase code looks like 12345678-90ab-cdef-1234-567890abcdef (8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one.
  • Official Envato article: Where Is My Purchase Code?
Lost your purchase code? Search your mailbox (spam folder included) for “license” or “purchase code”, then check My Account → My Licenses on bedigit.com for Store and Gumroad purchases, or Downloads → License certificate on Envato. If it is still missing, open a ticket on our Help Center with your order number (Store), Gumroad sale ID or buyer email (Gumroad), or Envato username and item name (Envato).

Configuration

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

Setting Description Default
appointment_enabled Show or hide the appointment page on the front-end. true
appointment_multi_provider Allow clients to choose a specific provider when booking. When disabled, the system auto-assigns a provider. false
appointment_provider_selection Show the provider selection step in the booking wizard (requires multi-provider mode). true
appointment_pending_blocks_slot When enabled, pending appointments also block the time slot. When disabled, only confirmed/completed appointments block slots. true
appointment_advance_days How many days in advance clients can book. 60
appointment_min_advance_hours Minimum hours before an appointment can be booked (prevents last-minute bookings). 2
appointment_slot_interval Override the time slot interval in minutes. Leave empty to use the service’s duration. (null: uses service duration)
appointment_services_per_row Number of service cards per row on the front-end booking page. 3
appointment_providers_per_row Number of provider cards per row on the front-end booking page. 4
appointment_notification_email Email address to receive admin appointment notifications. (empty)
appointment_require_payment Require payment before appointment confirmation. Only applies to services with a price > 0. false
appointment_cancellation_policy Free-text cancellation policy displayed on the booking page (translatable). (empty)
appointment_captcha_enabled Enable CAPTCHA challenge on the booking form. false

Provider Label Settings

Setting Description Default
appointment_provider_step_label Custom heading for the provider selection step (translatable). Leave empty to use the default translation. (empty: uses default)
appointment_provider_any_label Label for the “Any Available Provider” option (translatable). Leave empty to use the default. (empty: uses default)

Notification Settings

Setting Description Default
appointment_notify_admin_on_new_appointment Send email to the notification address on new appointments. true
appointment_notify_client_on_appointment Send confirmation email to the client on appointment submission. true
appointment_notify_client_on_status_change Notify client when appointment status changes (confirmed, cancelled, completed). true
appointment_notify_provider_on_new_appointment Notify the assigned provider when they receive a new appointment. true
appointment_notify_provider_on_cancellation Notify the assigned provider when an appointment is cancelled. true

Admin: Services

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

Services List

A sortable, paginated table showing:

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

Per-row actions: Edit, Delete.

Creating & Editing Services

  • Name (translatable, required for default locale)
  • Slug (translatable, auto-generated if empty)
  • Description (translatable)
  • Duration (minutes): required, 5–480 minutes. Determines slot length.
  • Price (numeric, optional)
  • Currency (required, from active currencies)
  • Max Capacity (integer, 1–100)
  • Active toggle
  • Position (display order)

Admin: Providers

Providers represent the staff members or resources that deliver your services. Managed at Appointments → 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 appointment/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 (Appointments → Appointments) shows all appointments in a paginated table.

Appointments List

Filterable by status and provider. Columns include:

  • Client name & email
  • Service name
  • Provider name
  • Date & time
  • Status badge (pending/confirmed/cancelled/completed)
  • Payment status (if payment is enabled)

Stats cards at the top show: total appointments, pending count, confirmed count, today’s appointments, and this week’s appointments.

Appointment Detail & Status Management

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

  • Client information: name, email, phone, IP address, booked-at timestamp
  • Appointment information: service, provider, date, start time, end time, 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 appointment_notify_client_on_status_change is enabled). Cancellations also notify the assigned provider.

Calendar View

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

  • Events are loaded via AJAX (GET admin/appointment/appointments/calendar-events).
  • Filter by provider using the dropdown.
  • Appointments show as time-based events on the calendar.
  • 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 (Appointments → Settings) is organized into sections:

General Settings

  • Enable Appointments: toggle to show/hide the front-end appointment page.
  • Multi-Provider Mode: let clients choose their provider.
  • Provider Selection: show the provider selection step in the wizard (requires multi-provider mode).

Provider Labels

  • Provider Step Label: custom heading for the provider selection step (translatable).
  • Any Provider Label: label for the “Any Available Provider” option (translatable).

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.
  • Services Per Row: number of service cards per row on the front-end.
  • Providers Per Row: number of provider cards per row on the front-end.

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 appointment alerts.
  • Five toggle switches controlling which emails are sent (see Notifications).

Cancellation Policy

  • Cancellation Policy: free-text displayed on the booking page (translatable).

CAPTCHA

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

Front-end: Booking Page

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

Routes

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

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

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 appointment.

Slot & Availability API

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

GET /{locale}/appointment/slots
Description

Returns available time slots for a specific service, provider, and date.

Query Parameters
service_id Required Service ID
provider_id Optional Provider ID (null = any available)
date Required Date (YYYY-MM-DD)
Response
GET /{locale}/appointment/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.

Slot Generation Logic

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 appointment booking (or successful payment), the user is redirected to /{locale}/appointment/confirmation/{appointment}.

  • Shows a success message with appointment details.
  • Displays service name, provider, date, time slot, and total price.
  • Status note explaining the appointment is pending confirmation.
  • Links to “Back to Home” and “Book Another”.

Payment Checkout

When appointment_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}/appointment/checkout/{appointment} appointment.checkout.localized Payment checkout page
POST /{locale}/appointment/checkout/{appointment} appointment.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 appointment_require_payment is enabled, a warning is shown on the admin settings page. The checkout page will show no payment options.

My Appointments

Authenticated users can view their appointment history at /{locale}/appointment/my-appointments.

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

This page is also accessible from the user account menu via the “My Appointments” 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 AppointmentManager service and silently catch any sending errors.

Notification Class Recipient Trigger Setting
AppointmentConfirmationNotification Client Appointment created (after payment, if required) notify_client_on_appointment
NewAppointmentAdminNotification Admin (notification_email) Appointment created notify_admin_on_new_appointment
NewAppointmentProviderNotification Assigned provider Appointment created notify_provider_on_new_appointment
AppointmentStatusChangeNotification Client Status changed to confirmed/cancelled/completed notify_client_on_status_change
AppointmentCancellationProviderNotification Assigned provider Appointment cancelled notify_provider_on_cancellation
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

There are two ways to update this add-on: via the admin panel (recommended) or manually replacing files.

Method 1: Admin Panel Upload (Recommended)

  1. Download the latest .zip file of this add-on.
  2. Go to Admin panel → Add-ons and click the Upload button.
  3. Select or drag the .zip file into the upload area.
  4. A confirmation prompt will show the current and new version numbers. Click Replace to proceed.
  5. Go to Admin panel → System Update (/admin/update) to apply any pending database migrations.

Method 2: Manual File Replacement

Step 1: Replace Files

Replace the add-on directory with the new version.

Step 2: Run Migrations

php artisan migrate

Pending migrations run once, so the command is safe to repeat.

Step 3: Rebuild Assets

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

Step 4: Clear Caches

php artisan config:clear
php artisan route:clear
php artisan view:clear
Backup first: Always back up your database before running migrations on a production system.

Uninstallation

Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find Appointments and click Deactivate.

  • Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
  • Its database tables and all the data they hold are kept, and its files stay under extensions/addons/appointment/. Nothing is deleted.
  • The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
  • Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.

Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.

Removing

Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:

  1. Deactivate Appointments (see Uninstallation).
  2. Click Remove on its card and confirm the prompt.

The admin panel then, in one pass:

  • runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
  • revokes the permissions declared in its addon.json;
  • rolls back its migrations (this drops its database tables and every row they hold) and purges its entries from the migrations table, so a later reinstall migrates from scratch;
  • deletes its published assets: public/addons/appointment/, public/vendor/appointment/ and storage/app/public/addons/appointment/;
  • deletes the add-on directory extensions/addons/appointment/;
  • deletes its row in the addons table (the recorded purchase code goes with it) and clears the application cache.
This cannot be undone. Back up your database before removing an add-on whose data you may still need: installing it again later creates empty tables, not your old content.

Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/appointment/. In that last case, give that user write permission on the directory and on its parent, then try again.

Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.

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 appointment_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 appointment_min_advance_hours cutoff (e.g., today before the minimum advance window).
  • All slots may be booked. Check if appointment_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).

Appointment page returns 404

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

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.

Client not receiving confirmation emails

  • Check that appointment_notify_client_on_appointment 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.

Multi-provider mode not showing provider selector

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

CAPTCHA not displaying on booking form

  • Ensure appointment_captcha_enabled is set to true in settings.
  • Verify a CAPTCHA provider (reCAPTCHA, hCaptcha, etc.) is configured in Admin → Settings → Security.
  • Check that the CAPTCHA driver is set and API keys are valid.

Status change notifications not sending

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

Appointments v1.0.0: Part of the Larapen CMS platform.

© BeDigit. All rights reserved.

Was this article helpful?

Thank you for your feedback!

Still need help? Create a support ticket

Create a Ticket
Sep 18, 2026