
# Booking Pages

A booking page lets someone book a meeting with one person on your team without a back-and-forth. It offers only times inside that person's hours and free on their calendar. The meeting is written to their Google or Outlook calendar, the visitor gets the invitation and a confirmation email with their own link to move or cancel, and the meeting appears on the **Calendar** page with the booking page as where it came from.

## What you'll need

- The **Calendar** module, which a Karmaflow.ai administrator includes for your workspace.
- **Manage Calendar Settings** (`calendar:settings:manage`) to create, change and publish a page. **View Calendar** is enough to see the pages.
- A connected Google or Microsoft calendar for the person the page books.
- **Your privacy link.** A page cannot be published without one: set your privacy policy link, or publish a short notice, under **Helpdesk Settings → Customer portal → Privacy**. See [Customer Portal](/help/helpdesk/customer-portal).

## Create a page

1. Open **CRM → Daily work → Calendar**, then **Booking pages**.
2. Press **New booking page**.
3. Under **Basics**, give it a **Title**. The **Address** fills in from the title; change it if you like.
4. Choose **Whose calendar it books** (you, until you pick someone else). Times are offered only inside that person's own hours (**Calendar → Your hours**) and the workspace's bookable hours.
5. Optionally pick an **Event type**: it fills in the length, the kind of meeting and the place.
6. Under **Availability**, set the **Length**, the **Kind of meeting** (video, phone or in person, with **Where** for in person), the **Notice needed** in hours and the **Gap between meetings**.
7. Set **Days shown to a new visitor** and **Days shown with a personal link**. A short window for new visitors shows less of when the person is away.
8. Under **Suggested times**, choose **How many** to show above the full view, and the **Undo window** in seconds.
9. Under **Consent**, choose whether to ask for more than the booking (below).
10. Under **Questions**, add anything you want to ask. Questions are asked after booking, never before.
11. Press **Create page**.

<!-- SCREENSHOT: crm/booking-pages-editor.png — Demo tenant, Calendar → Booking pages → New booking page, Basics and Availability filled in for "Solar consultation" -->

## Asking for consent

A booking is permission for the invitation and reminders about that meeting, and nothing more. To ask for more, turn on a box under **Consent**. A box is never ticked for the visitor.

**Ask if they want news from you** adds an unticked box under the booking, in your own words (or *Send me news and offers from <your name>. Unsubscribe any time.*). Ticking it records an opt-in to marketing email on their contact, with the words they saw and the page: see [Communication Consent and Opt-Outs](/help/crm/communication-consent).

The box is shown to visitors who arrive by their [personal link](#personal-links). A new visitor could type someone else's email, and an opt-in recorded on a stranger's record would be false evidence, so they are not asked.

A phone number typed for the booking is not permission to text. Meeting reminders are sent by email; a box for text reminders comes with them.

If a visitor has opted out of email, the page they booked on tells them they will not get a confirmation email or reminders, and the meeting's **Reminders** list says why each was not sent.

## Taking payment

A page can ask visitors to pay before the meeting is booked: the whole price, or a deposit. They pay on your own Stripe account, on Stripe's page, so the money goes straight to you and Karmaflow never sees their card. This is part of **Paid bookings**, an add-on to the Calendar; it includes 30 paid bookings a month.

### Connect Stripe

You need the **calendar:settings:manage** permission and a Stripe account.

1. In Stripe, open **Developers → API keys** and choose **Create restricted key**. If Stripe asks how you will use it, choose the option for an integration you built and set the permissions yourself. Name it "Karmaflow" and give it exactly these permissions: **Checkout Sessions: Write**, **PaymentIntents: Read**, **Charges and Refunds: Write**, **Customers: Write** and **Webhook Endpoints, Event Destinations: Write**.
2. In Karmaflow, open **Settings → Integrations → Stripe (paid bookings)**.
3. Paste the key (it starts with `rk_test_` or `rk_live_`) and press **Connect**.

Saving checks the key with Stripe and sets up Karmaflow's webhook in your Stripe account, so there is nothing to copy back. The page then reads *Connected · payments to* your account, with **Test mode** or **Live**. A secret key (`sk_…`) is refused, because it could do anything in your account. **Disconnect** removes the webhook from your Stripe account, forgets the key, and unpublishes any published page that asks for payment (the message names them), since those pages could not take a booking.

Start with a test key: visitors pay with Stripe's test cards, no money moves, and test bookings do not count toward your 30 a month. Paste a live key when you are ready.

Visitors pay by card (including Apple Pay and Google Pay where Stripe offers them). Bank debits are not offered: they clear days later, long after the time could be kept.

### Set the price

1. Open the booking page and find **Payment**.
2. Tick **Ask for payment to book**.
3. Enter the **Price**, the **Currency**, and whether it is **The full price** or **A deposit**.
4. Under **If the visitor cancels**, choose **Full refund up to a time before** (and the **Hours before**; a day by default), **Full refund any time before it starts**, or **No refund**. Visitors read this before they book.
5. Leave **Refund automatically** off to press **Refund** yourself when a paid meeting is cancelled, or turn it on to have Karmaflow refund what the policy says at once.
6. Press **Save**. A page that asks for payment publishes only while Stripe is connected and Paid bookings is included for your workspace; a published page can start asking for payment only on the same terms.

### What happens when a visitor pays

- The page shows the price before they choose a time. Choosing a time shows **Continue to payment**; the time is kept for them for 30 minutes while they pay on Stripe's page. There is no undo countdown: paying is the deliberate step.
- When Stripe tells Karmaflow the payment went through, the meeting is booked, exactly as an unpaid booking is. The visitor sees *You're booked* and *Paid …*; Stripe sends their receipt.
- If they leave Stripe's page without paying, the time is let go and nothing is booked.
- If the time cannot be booked after they paid (someone took it, or the calendar refused), the payment is **refunded in full** and the page's host is told, with a link to the payment in Stripe.
- The meeting on the **Calendar** shows a **Payment** section (what was paid, and any refund) with a link to the payment in Stripe. The contact gets a paid invoice, and the **Meeting paid for** trigger fires, so a workflow can act on it.

### When a paid meeting is cancelled

The policy decides what is due back when the **visitor** cancels: from their link, by declining the invitation, or by asking one of your agents in a call, chat or text. When **your side** cancels (from the Calendar page, your own calendar, or a campaign), the whole payment is due back, whatever the policy says.

Each booking keeps the policy it was paid under: changing the page's policy later applies to new bookings only. **Refund automatically** is different: it is how you handle refunds now, so turning it on or off applies to every cancellation from then on.

- With **Refund automatically** off (the default), the meeting's **Payment** section says what is due and why ("They cancelled 3 hours before, inside the 1 day the booking's terms keep the payment for."), and the host is told. To refund, open the meeting on the **Calendar**, check the amount (it starts at what is due) and press **Refund**. You can refund a different amount, up to what is left, and you can refund a meeting that was not cancelled.
- With it on, Karmaflow refunds what is due at once and tells the host.
- The visitor is told on their cancel page what comes back to them.
- Each refund is listed in the meeting's history, with who made it. A refund you make in Stripe yourself also shows on the meeting once Stripe reports it.

**Refund** needs the **calendar:events:manage** permission and is on your own meetings.

## Publish it

1. Open the page. If you changed anything, press **Save** first: **Publish** waits for unsaved changes.
2. Press **Publish**.
3. If your workspace has no privacy link yet, the page says so and links to where you add one. If the host's calendar is not connected, it says that instead.
4. **Share** shows the page's address and code to put it on your website from the moment the page is saved; until it is published, the address shows *not available*. Once published, **Open the page** and the personal links appear.

**Unpublish** takes the page down at once. Any time a visitor was still deciding on is let go; nothing is written to the calendar from a page that is off.

## What the visitor sees

The page carries your logo, colour and font from your brand kit (the same as your help portal), the host's name, the length and the kind of meeting.

1. **Suggested times** sit above the full view: the soonest time on each of the first days with one. Times are shown in the visitor's own time zone, which they can change.
2. A new visitor gives their first name and email first, with the line *Only for the invitation and reminders. No account, no newsletter.*
3. One tap holds the time. A bar counts down with **Undo**, **More time** and **Book now**; the countdown is announced to screen readers and can be extended.
4. When the countdown ends, the meeting is written to the host's calendar and the invitation goes out from it. A confirmation email follows, from your business's name, with the time, the join link or place, what they paid and the refund terms (on a paid page), and their move and cancel link. Replies reach the host. If the visitor closes the page first, the meeting is still booked and the email still goes.
5. They see *You're booked*, then your questions.

The footer shows your **Privacy** link, **Terms** and **Questions about your data** when you have set them, and *Scheduling by Karmaflow*.

While someone holds a time, nobody else can take it: agents and other visitors see it as busy.

## Moving or cancelling, for the visitor

The person who booked can move or cancel the meeting themselves, without an account:

- The page they booked on shows **Move or cancel this meeting**; the confirmation email and the reminder email (when reminders are on) carry the same link. The calendar invitation itself does not: it comes from the host's calendar.
- When they move it, a new confirmation with the new time follows. The meeting's **Reminders** list on the Calendar shows each confirmation: sent, or not sent and why.
- The link opens their meeting with **Move it** (the page's open times, then **Move it there**) and **Cancel it** (**Yes, cancel it**). The host's calendar is updated and the invitation follows.
- It works while the meeting is still ahead and the page is published. After the meeting has started, or on an unpublished page, the visitor replies to their invitation instead.
- Only the person who booked gets the link in their reminder; another guest on the meeting does not.

The meeting's history on the **Calendar** page says *the visitor, on a booking page*.

## Personal links

A personal link recognises one contact on one page: they skip the form and see the longer window.

1. Open a published page.
2. Under **Share → A personal link for one contact**, find the contact.
3. Set **Works for (days)** and press **Make a link for them**.
4. Copy the link and send it.

After the days you set, the link opens as a new visitor's page. **Greet them by first name** (under **Recognised visitors**) can be turned off; for a clinic, a name on a web page can be health information.

Making a personal link needs **Book, Move & Cancel Meetings** (`calendar:events:manage`).

## Where the answers and the meeting go

- The meeting is on the host's calendar and on the **Calendar** page, with the booking page as its origin.
- A new visitor becomes a contact, matched by their email. A phone number they type is kept as a note on the contact, not saved as their number: anyone can type anyone's email on a public page.
- A visitor with a personal link is that contact. An email or a phone number they type is saved on their record only where the record has none; it never replaces one already there.
- Answers to your questions are a note on the contact. They are never put in the calendar invitation.

## Troubleshooting

**Publish says I need a privacy link.** Add your privacy policy link or publish a notice under **Helpdesk Settings → Customer portal → Privacy**, then publish again.

**The page shows no times.** Check the host's hours (**Calendar → Your hours**), the workspace's bookable hours, the **Notice needed** and the window. Times past the window are not shown.

**Publish says Stripe is not connected.** The page asks for payment. Connect Stripe under **Settings → Integrations → Stripe (paid bookings)**, or untick **Ask for payment to book**.

**Connecting Stripe says a permission is missing.** Edit the restricted key in Stripe, tick the permission the message names, and press **Connect** again.

**Refund says Stripe is not connected.** Connect it again under **Settings → Integrations → Stripe (paid bookings)**, or refund the payment in your Stripe dashboard.

**A visitor paid but has no invitation.** Look for the meeting on the **Calendar**. If it is not there, the host got a notice saying the time could not be booked and whether the payment was refunded; if the refund failed, refund it in Stripe.

**A visitor says the time was taken.** Someone else held or booked it a moment earlier. The page shows the remaining times again.

## Related

- [Customer Portal](/help/helpdesk/customer-portal): your privacy link and brand kit
- [Communication Consent and Opt-Outs](/help/crm/communication-consent)

[Sign in to Karmaflow.ai](https://omni.karmaflow.ai/auth/login)
