# PRD: Add-on Services for NeetoCal
**Feature:** Add-on Services
**Status:** In Development
**Last Updated:** 2026-03-09
---
## 1. Overview
Add-on Services allow meeting hosts to define optional, client-selectable services that can be attached to a booking. Clients choose one or more services (depending on host configuration) before picking a time slot. Each service has a name, duration, optional image, and optional price. The selected services increase the total meeting duration and payment amount.
**Primary use case:** A hair salon offering "Haircut" as the base meeting, with add-ons like "Beard trim", "Hair spa", etc. A physiotherapy clinic offering base consultation with optional "Red light therapy", "Sports taping", etc.
---
## 2. Scope and Constraints
- **Not available for group meetings.** Group meetings have a fixed duration shared by all attendees, so per-client service selection is not applicable.
- **Supported for recurring meetings.** Add-on services work independently with recurring meetings; there is no dependency or restriction.
- **Rescheduling does not support modifying services.** If a client wants to add or remove services after booking, they must cancel and re-book.
- **No partial refunds.** If a booking with add-on services is cancelled, the full amount (base + services) is refunded.
- **Templates:** If add-on services are configured in a meeting template, those services are inherited when a scheduling link is created from that template.
---
## 3. Host Configuration — Admin UI
### 3.1 Navigation Entry Point
A new settings section, **"Add-on services"**, is added to the meeting configure tab sidebar (same level as Payments, Availability, etc.).
| Property | Value |
|---|---|
| Sidebar label | Add-on services |
| Sidebar icon | Tag icon |
| Route (scheduling link) | `/admin/scheduling-links/:id/settings/addon-services` |
| Route (template) | `/admin/admin-panel/meetings/templates/:id/settings/addon-services` |
The page heading **"Add-on services"** has a help info icon (ⓘ) next to it. Hovering over the icon shows a popover with the following content:
| Property | Value |
|---|---|
| Popover title | Add-on services |
| Popover description | These are optional services that clients can choose when booking a meeting. The booking's total duration and amount will automatically update based on the services the client selects. |
| Link label | View help article |
| Link URL | *(to be added when the help article is published)* |
A short description line appears below the heading: **"Create services your clients can add on when booking."**
---
### 3.2 Add-on Services Page — Empty State
When no services have been added yet:
| Element | Text |
|---|---|
| Empty state message | No add-on services |
| Add button | Add new service |
---
### 3.3 Add-on Services Page — Services List State
When one or more services exist:
| Element | Text/Behavior |
|---|---|
| Section label | Services |
| Count badge | `{{count}} added` (e.g., "2 added") |
| Add more button | Add new service |
| Multi-select toggle label | Allow clients to select multiple services |
| Drag handle | Each service card has a drag handle for reordering |
The **"Allow clients to select multiple services"** checkbox controls whether clients can select one or several services during booking. When unchecked, only a single service can be chosen (radio buttons on client side). When checked, multiple can be selected (checkboxes on client side).
---
### 3.4 Service Card (in the services list)
Each service is shown as a card in the list with the following layout:
| Element | Details |
|---|---|
| Service image | If an image is uploaded, it appears as a square thumbnail with rounded corners (border radius applied). Not shown if no image is set. |
| Service name | Bold, primary text |
| Duration + Price | Subtext format: `{duration} · {price}` (e.g., "30 min · $10 USD") |
| Free indicator | If price is 0, shows "Free" instead of a price |
| Drag handle | Left side, for reordering |
| Three-dot menu actions | Edit / Delete |
---
### 3.5 Add / Edit Service Pane
A slide-out pane opens when creating or editing a service.
**Pane titles:**
- Add mode: **"Add service"**
- Edit mode: **"Edit service"**
**Form fields:**
#### Service Name (required)
| Property | Value |
|---|---|
| Label | Service name |
| Placeholder | Enter service name |
| Validation error | Service name is required |
#### Service Image (optional)
| Property | Value |
|---|---|
| Label | Service image |
| Button (no image) | Upload image |
| Button (image exists) | Change image |
| Remove button tooltip | Remove image |
| Accepted formats | JPEG, PNG |
#### Duration (required)
| Property | Value |
|---|---|
| Label | Duration |
| Options | 0 min, 15 min, 30 min, 45 min, 1 h, Custom |
| Custom option | Shows a custom time input when selected |
A duration of **0 min** is valid. This means the service adds no extra time to the meeting.
#### Price
| Property | Value |
|---|---|
| Label | Price |
| Placeholder | 0.00 |
| When value is 0 | Displays "Free" help text in green below the field |
#### Currency (always read-only/disabled)
| Property | Value |
|---|---|
| Label | Currency |
| Behavior | Always disabled; auto-populated from payment settings |
**Tooltip logic on Price field:**
| Condition | Tooltip text on Price field |
|---|---|
| Payment not enabled for services (Cases 1 and 4 below) | "Enable 'Accept payment for services' on this page to set a price." |
**Tooltip logic on Currency field:**
| Condition | Tooltip text on Currency field |
|---|---|
| Payment is configured (services payment on) | "The default currency is {{currency}}. To change this, close this pane and update the payment settings." |
| Payment not enabled for services | "Enable 'Accept payment for services' on this page to set a price." |
**Multi-currency info callout (Case 6 only — paid meeting, services payment enabled, multiple providers with different currencies):**
> "You have payment methods with different currencies and you have set your default(★) currency as {{defaultCurrency}}. We'll convert to other currencies for clients who choose a different provider at checkout. [Learn more about how we convert.]"
This callout appears below the Price and Currency fields inside the Add/Edit Service pane. It is informational — the price is still editable using the default currency, and auto-conversion is handled at checkout.
**Pane footer buttons:** Save changes / Cancel
---
### 3.6 Payment Configuration for Services
Above the services list, a section handles whether and how clients pay for services.
#### Toggle
| Property | Value |
|---|---|
| Toggle label | Accept payment for services |
#### Free Meeting — Payment Enabled
If the base meeting is free (no meeting fee), the host can still collect payment for services. When this toggle is enabled on a free meeting, a **"Services payment pane"** opens immediately to configure the currency and provider. There is no subtext shown here — configuration is done entirely within the pane.
Once the pane is saved, the section shows **pill chips** below the toggle row summarising the configured providers:
- Each pill shows: `{Provider name} · {CURRENCY}` (e.g., "Stripe · USD")
- The default provider's pill has a filled star (★) icon to its left
- A three-dot menu (⋯) appears next to the toggle label, with a single **"Edit"** option to re-open the Services Payment Pane
#### Paid Meeting — Payment Inherited
If the base meeting is already paid, the services payment currency and provider are inherited automatically from the meeting's existing payment settings. The host does not need to configure them separately. When the toggle is enabled on a paid meeting, the following subtext is shown below the toggle:
- Subtext: "Provider and currency will be taken from the [payment settings]." (with "payment settings" as a clickable link to the meeting's payment settings page)
No pill chips or edit menu are shown for the inherited case — the configuration lives entirely in the meeting's payment settings.
---
### 3.7 Services Payment Pane (Free Meeting Payment Setup)
A slide-out pane for configuring payment specifically for services on a free meeting.
| Property | Value |
|---|---|
| Pane title | Accept payment for services |
| Currency field label | Currency |
| Currency required error | Currency is required. |
| UPI currency tooltip | Currency is fixed as INR for UPI payments. |
| Default provider star button tooltip | Default payment provider |
| Footer buttons | Save / Cancel |
**Multi-currency info callout (Case 3 — shown inside this pane when the host configures multiple providers with different currencies for a free meeting):**
> "You have payment methods with different currencies and you have set your default(★) currency as {{defaultCurrency}}. We'll convert to other currencies for clients who choose a different provider at checkout. [Learn more about how we convert.]"
---
### 3.8 Service Preview (Live Preview in Config UI)
A live preview panel on the right side of the Add-on Services page shows how the services step will appear to clients.
| Element | Text/Behavior |
|---|---|
| Preview heading | Choose add-on services |
| Empty state (no services added) | Add services to see the preview |
| Continue button | Continue |
| Selection mode | Checkbox (multi-select on) or Radio button (single-select) |
| Service row format | Image thumbnail (if set) · Service name · "duration · price" |
---
## 4. Payment Configuration Edge Cases
There are six combinations of meeting payment status and services payment configuration. Each determines what the host sees in the Add/Edit Service pane.
---
### Case 1: Meeting Free + Services Free (payment not enabled for services)
- "Accept payment for services" toggle is off.
- Price field is **disabled**. Tooltip: "Enable 'Accept payment for services' on this page to set a price."
- Currency field is **disabled**, shows **"Not selected"** as placeholder. Tooltip: "Enable 'Accept payment for services' on this page to set a price."
- All services default to free.
- No callout.
---
### Case 2: Meeting Free + Services Paid (single currency)
- Host has enabled "Accept payment for services" and configured a single provider/currency in the Services Payment Pane.
- Price field is **editable**.
- Currency field is **disabled** (read-only), showing the configured currency. Tooltip: "The default currency is {{currency}}. To change this, close this pane and update the payment settings."
- No callout.
---
### Case 3: Meeting Free + Services Paid (multiple providers, different currencies)
- Host has enabled "Accept payment for services" and configured multiple providers with different currencies in the Services Payment Pane.
- Price field is **editable**, using the default service currency.
- Currency field is **disabled** (read-only), showing the default currency. Tooltip: "The default currency is {{currency}}. To change this, close this pane and update the payment settings."
- No callout inside the Add/Edit Service pane.
- The multi-currency callout appears inside the **Services Payment Pane** (the "Accept payment for services" configuration pane), not here. See section 3.7.
- At checkout, the system auto-converts to the client's chosen provider currency.
---
### Case 4: Meeting Paid + Services Free (payment not enabled for services)
- "Accept payment for services" toggle is off.
- Price field is **disabled**. Tooltip: "Enable 'Accept payment for services' on this page to set a price."
- Currency field is **disabled**, shows **"Not selected"** as placeholder. Tooltip: "Enable 'Accept payment for services' on this page to set a price."
- All services default to free.
- No callout.
---
### Case 5: Meeting Paid + Services Paid (single currency, or multiple providers with the same currency)
- "Accept payment for services" toggle is on; currency and provider are inherited from the meeting's payment settings.
- Price field is **editable**.
- Currency field is **disabled** (read-only), showing the meeting's currency. Tooltip: "The default currency is {{currency}}. To change this, close this pane and update the payment settings."
- No callout.
---
### Case 6: Meeting Paid + Services Paid (multiple providers, different currencies)
- "Accept payment for services" toggle is on; currency and providers are inherited from the meeting's payment settings.
- Price field is **editable**, using the meeting's default currency.
- Currency field is **disabled** (read-only), showing the default currency. Tooltip: "The default currency is {{currency}}. To change this, close this pane and update the payment settings."
- A **multi-currency info callout** is shown below the Price and Currency fields:
> "You have payment methods with different currencies and you have set your default(★) currency as {{defaultCurrency}}. We'll convert to other currencies for clients who choose a different provider at checkout. [Learn more about how we convert.]"
- At checkout, the system auto-converts to the client's chosen provider currency.
---
## 5. Client-Facing Booking Flow
### 5.1 Add-on Services Step
A new step is inserted into the booking flow **before** the time-slot calendar picker.
| Element | Text/Behavior |
|---|---|
| Step heading | Choose add-on services |
| Service row | Image thumbnail (if set) + Service name (bold) + subtext: "duration · price" |
| Free service subtext | "duration · Free" (e.g., "15 min · Free") |
| Paid service subtext | "duration · $30.00 USD" |
| Selection mode | Checkbox (multi-select allowed) or Radio button (single-select only) |
| Continue button | Continue |
When the client proceeds past this step, the selected services persist through the rest of the booking flow.
### 5.2 Back Navigation
After entering the calendar step, a **"Back"** button is available to return to the add-on services step.
---
### 5.3 Left Panel — Booking Summary (LeftViewDetails)
The left-side booking summary panel shows:
1. Meeting name and base duration
2. Total price (base + selected service prices)
3. **Add-on services section** (shown below the price row), with a Tag icon
- Label: **"Add-on services"**
- Each selected service listed as: `{Service name} · {duration} · {price}`
**Duration display:** Shows the base meeting duration plus the sum of all selected add-on service durations.
**Price display:** Shows the base meeting price plus the sum of all selected add-on service prices.
---
### 5.4 Payment Summary — Amount Overview Card
The payment summary section (shown during the payment step) reflects add-on services as follows:
| Element | Behavior |
|---|---|
| Header row label | Meeting name (e.g., "30 Minute Consultation"), replacing the generic "Amount" label |
| Add-on service rows | Each selected service listed below the base row, in gray |
| Add-on service price | Shown right-aligned in gray; shows "Free" if price is 0 |
| Total row | Base meeting fee + all add-on service prices |
---
### 5.5 Discount Codes
- Discount codes are applied on the **total amount** (base meeting fee + all add-on services prices combined).
- This applies to both percentage and fixed-amount discount codes.
---
### 5.6 Tips
- Tips are calculated on the **total amount** (base meeting fee + add-on services prices combined, after discounts).
- Preset tip options: 18% and 22%.
- Custom tip: 1–100% (validated).
- Tip label: "Do you want to add tip?"
---
### 5.7 Taxes
- Taxes are applied on the **base meeting fee only** (original meeting amount).
- Tax is **not** applied at the individual service level.
- Tax on services may be considered in future releases based on customer demand.
- If tip is enabled and taxable, tax on tip is calculated separately.
- Help text (amount): "Tax applied on amount is {{taxAmount}}"
- Help text (tip): "Tax applied on tip is {{taxAmount}}"
---
### 5.8 Packages
- Package duration is tracked against the **total duration** of the booking (base + selected service durations).
- When a package is active: "You have {{duration}} remaining in this package."
- When a client exceeds the remaining package duration: "You have exceeded the duration remaining in your package. Please remove additional slots to continue."
---
## 6. Booking Confirmation & Post-Booking Displays
### 6.1 Booking Confirmation Screen
The confirmation screen (shown after a successful booking) displays add-on services under the **"What"** section:
- Meeting name with duration badge
- Each selected add-on listed as: `+ {Service name} · {duration} · {price}`
### 6.2 Booking Details Page
The booking detail view's **"What"** field shows:
- Meeting name + duration
- Each add-on service listed below as: `+ {Service name} · {duration} · {price}`
### 6.3 Bookings List
The bookings list shows add-on service names as additional rows below the meeting name in the meeting name column (e.g., "+ Beard trim", "+ Haircut").
---
## 7. Email Notifications
In all booking-related email notifications, the **"What"** section shows:
- Meeting name
- Each selected add-on service listed as: `+ {Service name}` (e.g., "+ Haircut", "+ Beard trim")
This applies to all email types:
- Booking confirmation
- Cancellation (by customer)
- Cancellation (by host/member)
- Rescheduled (by client)
- Rescheduled (by host/member)
- Spot updated
- Reminder (to customer)
- Reminder (to host)
The **"When"** section continues to show the total duration (base + add-on services duration sum).
---
## 8. Calendar Events
The calendar event title is **not** modified to include service names, even when meeting name is selected as the calendar event title.
- **Calendar event title:** Meeting name only (e.g., "Haircut")
- **Calendar event duration:** Total duration (base + selected service durations)
Rationale: Including service names in the calendar title could be confusing and cluttered. This decision may be revisited based on customer feedback.
---
## 9. SMS Reminders
Same rule as calendar events. The meeting name used in SMS reminders does **not** include service names appended.
---
## 10. Automation Rules
The meeting name token in automation rules does **not** include service names. Same behavior as calendar events and SMS.
---
## 11. Rescheduling
- When a booking is rescheduled, the selected services remain **unchanged**.
- The full bundle (meeting + selected services) is rescheduled as-is to the new time slot.
- Clients cannot add or remove services during rescheduling.
- To change services, a client must cancel the booking and re-book with the desired services.
---
## 12. Refunds
- Refunds are always for the **full amount** (base meeting fee + all add-on service prices + taxes + tip).
- Partial refunds (e.g., refunding only one service's price) are not supported.
---
## 13. Exporting Bookings
When bookings are exported (CSV/spreadsheet):
- A new column is added to the export.
- This column lists the add-on services selected for that booking.
- If no add-on services were selected, the column is empty.
---
## 14. API
### 14.1 Create Booking API
The external booking creation API accepts a `selected_services` field:
```json
{
"selected_services": ["Haircut", "Beard trim"]
}
```
> Note: Service IDs (e.g., `ser_1234`) may be used instead of names in the final implementation. This will be confirmed during engineering.
### 14.2 Get Scheduling Links API
Form questions and add-on services are not returned in the scheduling links listing API response.
---
## 15. URL Parameters (Pre-filling Services) (not to be added in V1)
Services can be pre-selected via URL parameters using service IDs:
```
?service=ser_1234,ser_5436
```
or
```
?service=ser_1234&service=ser_5436
```
This will be implemented based on customer demand.
---
## 16. Webhooks
Webhook payloads will include the selected services for a booking. Engineering team will determine the exact payload structure.
---
## 17. Reports (not to be added in v1)
Service-level reporting (e.g., revenue per service, most popular services) will be added based on customer requests.
---
## 18. Meeting Reminders, Booking Limits, and Outcomes
- Meeting reminders: No change in behavior. Reminders still apply to the whole booking.
- Booking limits: Limits are still counted per booking (not per service).
- Booking outcome: A single outcome is recorded for the whole booking, not per service.
---
## 19. Future Considerations (Out of Scope for v1)
- **Tax at the service level:** Currently, tax is only applied on the base meeting amount. Service-level tax may be added per customer request.
- **Reporting:** Service revenue and popularity reports.
- **URL pre-fill:** Pre-selecting services via URL parameters.
- **Webhooks:** Including service details in webhook payloads.
- **Package limits based on price:** No dependency; packages work on duration.
- **Partial refunds:** Not supported in v1.
- **Service-level discounts:** Discount codes apply to total amount; per-service discounts are not planned.