> ## Documentation Index
> Fetch the complete documentation index at: https://docs.famulor.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Calendar & booking

> Let assistants check availability and book appointments mid-call via Acuity Scheduling, Cal.com, Calendly, eTermin, HighLevel, or the built-in engine

Appointment scheduling is the classic voice-agent use case: the assistant checks open slots during the call, offers a few options, and books the one the caller picks. The platform supports this in two ways that can be combined freely:

1. **Calendar integrations** — connect an external scheduling provider (Acuity Scheduling, Cal.com, Calendly, eTermin, HighLevel) once, assign it to an assistant, and the assistant automatically gets booking tools for every call. Google Calendar and Outlook connect in the same place, but they feed the built-in engine's calendar sync rather than mid-call booking — see the note under the table.
2. **The built-in booking engine** — define your own event types with weekly availability and get a public, embeddable booking page at `/book/{workspace}/{slug}`, ICS invitation emails, and a `native` integration your assistants can book against. No external account required. See [Built-in calendar](/assistants/native-calendar) for the full picture.

## Providers at a glance

| Provider                     | Availability                                                       | Booking                                                                                    | Credentials                                                                                            |
| ---------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| **Cal.com**                  | ✓ open slots of an event type                                      | ✓ direct booking                                                                           | API key (`cal_…`) + API endpoint (US, EU, or self-hosted), event type picked from a synced list        |
| **Calendly**                 | ✓ available times of a selected event type                         | ✓ direct booking (paid Calendly plans), single-use scheduling link, confirmed cancellation | OAuth connect (one time)                                                                               |
| **Acuity Scheduling**        | ✓ live slots or class availability for a selected appointment type | ✓ direct booking, confirmed cancellation and rescheduling (series cannot be rescheduled)   | OAuth connect (one time)                                                                               |
| **eTermin**                  | ✓ live slots for a selected service + calendar/person              | ✓ direct booking                                                                           | Public Key + Secret Key (Account Settings → API), service and calendar/person picked from synced lists |
| **HighLevel**                | ✓ live free slots of a selected calendar                           | ✓ direct booking                                                                           | An existing HighLevel connection (from Automations → Connections) + calendar                           |
| **Google Calendar**          | ✓ free/busy of a connected calendar, for the built-in engine       | ✓ event creation with attendee invite, from the built-in engine                            | OAuth connect (one time)                                                                               |
| **Outlook / Microsoft 365**  | ✓ free/busy of a connected calendar, for the built-in engine       | ✓ event creation with attendee invite, from the built-in engine                            | OAuth connect (one time)                                                                               |
| **Native (built-in engine)** | ✓ computed from your event type's weekly availability              | ✓ direct booking + ICS email                                                               | none — see [Built-in calendar](/assistants/native-calendar)                                            |

<Note>
  **Google Calendar and Outlook are sync targets, not mid-call booking providers.** Connecting them makes their busy times and event creation available to the [built-in booking engine](/assistants/native-calendar#the-built-in-booking-engine); assistants cannot call them directly during a conversation yet. To book on those calendars mid-call, either put a Cal.com, Calendly, Acuity, or HighLevel event type in front of them, or use a built-in event type with calendar sync switched on.
</Note>

<Note>
  **Calendly link mode**: Calendly's Scheduling API requires a paid Calendly plan. If your plan cannot book directly, set the integration's `booking_mode` to `link` — the assistant then agrees on a rough time with the caller and sends a **single-use scheduling link** by SMS or email (`link_channel`) instead of hard-booking. Integrations that hit the paid-plan restriction at call time are flagged with status `link_mode`.
</Note>

## Connecting an integration

Go to **Booking → Integrations** and pick a provider card:

<Tabs>
  <Tab title="Cal.com">
    Paste your API key (Cal.com → Settings → Developer → API Keys) and pick the **API endpoint**: US (default), EU, or Custom for a self-hosted Cal.com instance. Select **Load event types** to fetch your events by name and duration — no need to copy a numeric ID from the URL. The integration also reads the event type's custom booking questions automatically; use **Refresh fields** if you change them later in Cal.com. Optional timezone override — make sure it matches the Cal.com event type.
  </Tab>

  <Tab title="Calendly">
    Click **Connect with Calendly**, approve access, then choose an active event type by **name and duration**. One account connection can be reused by multiple integrations. If the event type has more than one location configured in Calendly, pick the one the assistant should use under **Meeting location**. Choose the booking mode, link channel, and Book/Cancel permissions.
  </Tab>

  <Tab title="Acuity Scheduling">
    Click **Connect with Acuity**, approve access, then choose an appointment type. Optionally select a specific calendar or person, or let the service choose any available calendar. Enable or disable Book, Cancel, and Reschedule for each integration.
  </Tab>

  <Tab title="eTermin">
    Paste your **Public Key** and **Secret Key** (eTermin → Account Settings → API), then select **Load services** to fetch your services by name and duration. Picking a service loads only the calendars/persons eTermin offers for it — pick one and adjust the duration if it needs to differ from the service default. After the integration is saved, a **Web Push URL** appears: paste it into eTermin's **API → API & Web Push** settings (enable **Send Web Push**, prefer JSON format) so eTermin notifies the platform whenever an appointment is created, changed, or cancelled on its side. The editor then shows when the last event arrived — the quickest way to confirm the connection is live. An optional shared secret can be set on both sides and is checked as the `X-Webhook-Secret` header.
  </Tab>

  <Tab title="HighLevel">
    First connect a HighLevel account under **Automations → Connections** if you haven't already. Back in **Booking → Integrations**, choose **Connect HighLevel**, select that connection, then pick one of its active calendars. Book, Cancel, and Reschedule toggles are stored per integration, but assistants currently get availability and booking only for HighLevel — there is no HighLevel cancel or reschedule tool yet.
  </Tab>

  <Tab title="Google / Outlook">
    Click **Connect** and complete the OAuth consent. The connection can be reused by multiple event types in the workspace.
  </Tab>

  <Tab title="Native">
    Pick one of your [booking event types](/assistants/native-calendar#the-built-in-booking-engine).
  </Tab>
</Tabs>

Every integration is **verified before it is saved**. Invalid credentials or event settings are rejected with a clear error. Secret values are never displayed again after saving.

Deleting the final integration that uses an Acuity account revokes its OAuth token through Acuity's disconnect endpoint and removes the local connection. An unused account can also be removed with **Disconnect account** in the Acuity editor; shared accounts cannot be disconnected until their remaining integrations are removed.

Existing personal-access-token integrations remain operational but appear as
**Legacy connection — reconnect with Calendly**. Reconnecting upgrades them to
OAuth and removes the PAT from the integration.

## Assigning to an assistant

Open the assistant's settings and tick the integrations it should use (or `PUT /api/v1/assistants/{id}/integrations`). Each assigned integration adds its own booking tools to every call:

| Tool                                                           | Type                                                 | What it does                                                                                                                                                                               |
| -------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `check_availability(start_date, end_date?)`                    | read-only, interruptible                             | Fetches open slots for the date range and reads them out in the assistant's timezone (capped so the agent never recites 200 slots).                                                        |
| `book_appointment(name, email, start, notes?)`                 | write — runs with a filler phrase, not interruptible | Books the chosen slot. On success the booking start/ID are stored as call variables for flows, analysis, and webhooks. If the slot was just taken, the agent is told to offer another one. |
| `send_booking_link(email?, phone?)`                            | Calendly link mode only                              | Creates a single-use scheduling link and sends it via SMS or email.                                                                                                                        |
| `find_appointment(email, name)`                                | Calendly/Acuity management                           | Finds upcoming appointments for the selected event/appointment type. Both the exact booking email and full name are required.                                                              |
| `cancel_appointment(event_id / appointment_id, confirmed)`     | write — not interruptible                            | Cancels only an event or appointment returned by `find_appointment` during the same call, after the assistant reads it back and receives explicit confirmation.                            |
| `reschedule_appointment(appointment_id, new_start, confirmed)` | Acuity management                                    | Moves only an Acuity appointment returned in the same call, after availability was checked and the caller explicitly confirmed the new time.                                               |

Every integration gets `check_availability` and `book_appointment`. The management tools are added only where the provider supports them: **Calendly** (find and cancel), **Acuity** (find, cancel, and reschedule, following the toggles you set), and the **built-in engine**, which adds a workspace-wide set that identifies the caller by phone number first and falls back to email plus full name. **Cal.com**, **eTermin**, and **HighLevel** calendars currently offer availability and booking only — the assistant can read slots and book on them, but not look up, cancel, or move an existing appointment during a call.

If more than one integration is assigned, tool names get the integration name as a suffix (for example `check_availability_sales`). Slots are always spoken in the **assistant [timezone](/assistants/timezone)** — set it in the assistant's settings.

<Note>
  Calendly bookings can't be rescheduled through its API — a caller who wants a different time gets a fresh `cancel_appointment` and `book_appointment` instead, or reschedules through the link in their Calendly confirmation email.
</Note>

<Tip>
  Tell the assistant **when** to book in its prompt, e.g.: *"Before offering any time, call check\_availability. Once the caller confirms a slot, call book\_appointment with their name and email."*
</Tip>

## Plan gating

Your plan must include **Calendar integrations**. If it is not included, you cannot create integrations.

## Troubleshooting

<AccordionGroup>
  <Accordion title={`Cal.com: "Invalid API key" or event types won't load`}>
    Confirm the key is still active in Cal.com and that you pasted a live key (Cal.com's live keys begin with `cal_live_`), then select **Load event types** again. If you get an authentication error instead of an empty list, you likely picked the wrong API endpoint — an EU Cal.com account needs the EU endpoint (or Custom for a self-hosted instance), not the US default.
  </Accordion>

  <Accordion title="Cal.com: the assistant keeps asking for an email, or the booking never completes">
    `book_appointment` needs a valid email address, because Cal.com rejects a booking without one. Spoken addresses ("anna at example dot com") and German umlauts are converted automatically before the request goes out, so most dictated addresses work; if what the assistant heard still isn't usable, it is told to ask again rather than booking. Tell it in the prompt to collect and confirm the email before booking, and to reuse an address you already hold as a [call variable](/assistants/variables) instead of asking twice.
  </Accordion>

  <Accordion title="Calendly: &#x22;Specified location kind is not configured for this event type&#x22;">
    The event type's only location in Calendly is a video-conferencing link (Google Meet, Zoom, Teams), and the voice agent can't generate meeting links. In Calendly, edit the event type and add **Custom** or **Phone Call → Inbound call** as a location — Custom is the safest choice and works in every case. If the event type ends up with more than one location, pick the right one under **Meeting location** in the integration.
  </Accordion>

  <Accordion title="Calendly: some team event types are missing">
    In a Calendly organization, admin and owner accounts see every member's event types, including Round Robin and Collective events; a regular member account only sees its own.
  </Accordion>

  <Accordion title="Bookings behave differently in a browser test than on a real call">
    A **Web Call** test runs without a phone number, so anything the booking flow derives from the caller's number (sending a scheduling link by SMS, looking an appointment up by phone) can't work the same way. Use **Test → Call** in the assistant header for a realistic run: the assistant dials a number you enter, or you dial its inbound number yourself.
  </Accordion>
</AccordionGroup>

Still stuck? Contact support with the integration's name, the error shown in the assistant editor, and a transcript of the call that failed to book.

## API & MCP

Everything above is available in the [public REST API](/api-reference/introduction) and as MCP tools at `https://<your-domain>/mcp`:

| REST                                                                          | MCP tool                                                                                                 | Scope                              |
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `GET/POST /api/v1/integrations`, `GET/PATCH/DELETE /api/v1/integrations/{id}` | `list_integrations`, `get_integration`, `create_integration`, `update_integration`, `delete_integration` | `integrations:read/write`          |
| `POST /api/v1/integrations/calendly/oauth-url`                                | `create_calendly_oauth_url`                                                                              | `integrations:write`               |
| `GET /api/v1/integrations/calendly/connections`                               | `list_calendly_connections`                                                                              | `integrations:read`                |
| `GET /api/v1/integrations/calendly/event-types?connection_id=…`               | `list_calendly_event_types`                                                                              | `integrations:read`                |
| `POST /api/v1/integrations/acuity/oauth-url`                                  | `create_acuity_oauth_url`                                                                                | `integrations:write`               |
| `GET /api/v1/integrations/acuity/connections`                                 | `list_acuity_connections`                                                                                | `integrations:read`                |
| `GET /api/v1/integrations/acuity/appointment-types?connection_id=…`           | `list_acuity_appointment_types`                                                                          | `integrations:read`                |
| `GET /api/v1/integrations/acuity/calendars?connection_id=…`                   | `list_acuity_calendars`                                                                                  | `integrations:read`                |
| `GET/PUT /api/v1/assistants/{id}/integrations`                                | `get_assistant_integrations`, `set_assistant_integrations`                                               | `integrations:*` or `assistants:*` |

Event types, connections, and booking records for the built-in engine are covered in [Built-in calendar](/assistants/native-calendar).
