# Adding your first app
Source: https://cal.com/help/apps-and-integrations/adding-first-app
Head over to the **apps** page, where you'll find our app store. We suggest firstly adding a calendar integration, then optionally a video conferencing platform, and then try out the other apps.
Find the app you'd like to install, and either click **Install** in the top right of that app's card to add it right away, or click on the app's card to view more details.
In the details page you can read more about each app, then click **Install** in the top right of the page to add it to your account.
If the app requires authentication, for instance to connect your Google Account, a dialog will be opened prompting you to authenticate. Once complete, the app will be successfully installed.
# App Store
Source: https://cal.com/help/apps-and-integrations/app-store
The whole idea behind Cal.com is to make scheduling easy, we want it to be an effortless process, and we want everybody to be able to access it.
With this in mind, we built an app store. Our apps let you extend cal.com features, and makes integrating other services effortless. This makes it easy to customize your cal.com experience. Apps can be used to do things like add extra calendar connections or host a virtual team-building session.
The Cal app store also makes it easy to coordinate things like podcast production, twitch streaming, and CMS outreach. With Cal.com, calendar scheduling is simple, effortless and whenever you need it to be fun.
Currently, we have 45+ apps in our app store which can assist you in your scheduling experience, from Calendar apps to Automation apps. You can use the built-in search bar to look for the app quickly if you'd prefer that.
# Apps
Source: https://cal.com/help/apps-and-integrations/apps
Apps are extensions within Cal.com that extend the functionality of the software. Most commonly, apps are integrations with various calendar providers, video conferencing software and other platforms. However, apps also provide the ability to add extra features to the software, such as the *Wipe my cal* app which offers the ability to mass-reschedule your entire day. Check out the Cal.com [app store](https://cal.com/apps) now
**Looking to build an app for Cal.com?** Check out our [guide](https://cal.com/docs/how-to-guides/how-to-build-an-app) for more information on building an app for our app store.
Clicking **Apps** in the sidebar will take you to the app store, which is the marketplace to find and install apps. They are divided into categories which you can browse through.
You can click on any app's card to view the detailed view, which gives you a description for the app, as well as additional information about it. If you want to install it, simply hit the **Install** button and it will be added. If the app requires authentication, for instance to connect your Google Account, a dialog will be opened prompting you to authenticate. Once complete, the app will be successfully installed.
Clicking on **Installed apps** in the sidebar takes you to a page detailing which apps you have installed and any relevant settings for them. Here, you can do things like enabling and disabling certain calendars, adding webhooks, uninstalling apps and more.
# Assign people to a call from a CRM or database
Source: https://cal.com/help/apps-and-integrations/assign-people
## Option #1 Based on CRM integration
If you are working with a CRM such as Salesforce, Hubspot, Close.com or similar, you can use our integrations to connect to your apps.
We're using the Assignee APIs from each service to understand which person is assigned to an email of a new lead.
By prefilling your booking link with ?email=[name@acme.com](https://cal.com/help/en/articles/) our integration will look up who has spoken to [name@acme.com](https://cal.com/help/en/articles/) before and skip all round-robin logic.
Here is an example URL: i.cal.com/sales/exploration?email=[name@acme.com](https://cal.com/help/en/articles/)
This works with Embeds as well, just add the parameter to your CalLink property.
## Option #2 Based on Emails
If you are using a different product that we don't integrate with, or you need something more custom you can also achieve this with our Organization plan.
We've built our Organization system in a way where every email can be turned into a scheduling link with your company subdomain:
[jane@acme.com](https://cal.com/help/en/articles/) → acme.cal.com/jane (or schedule.acme.com/jane)
This means if you have a table:
| **User** | **AccountExecutive** |
| ------------------------------------------------- | -------------------------------------------------- |
| [peer@cal.com](https://cal.com/help/en/articles/) | [jane@acme.com](https://cal.com/help/en/articles/) |
You could show [peer@cal.com](https://cal.com/help/en/articles/) an embed inside your application simply by using the value from AccountExecutive to build the link:
[jane@acme.com](https://cal.com/help/en/articles/) → acme.cal.com/jane either with a string replace function or a simple regex.
# How to Cal.com with Attio
Source: https://cal.com/help/apps-and-integrations/attio
To use Cal.com with Attio, you only need two things:
1. You need to have an account on both platforms
2. You need to connect Google Calendar to Attio
3. You need to connect Google Calendar to Cal.com
# Build a greeter app
Source: https://cal.com/help/apps-and-integrations/build-greeter-app
## Building a **Greeter** app
**Step 1:** Create an app with the title "**Greeter".** Run the following command and provide the information it is looking for.
```
yarn app-store create
```
**Step 2:** App is created now. Go and install it.
**Step 3:** The app is installed but it doesn't do anything because we haven't written any code to make it do something. Let's add a button in the main navigation that greets the user
1. Create a component `greeter/components/GreeterButton.tsx` - You can name it whatever you want.
2. Import this component in `Shell.tsx` and add it wherever you want to so that the button is available on all pages.
```js theme={null}
/**
* GreeterButton.tsx
* It creates a button that can be added anywhere. The button is visible only if the app is installed.
*/
import useApp from "@calcom/lib/hooks/useApp";
import showToast from "@calcom/lib/notification";
import { Button } from "@calcom/ui";
import useMeQuery from "@lib/hooks/useMeQuery";
export default function GreeterButton() {
const { data: user } = useMeQuery();
const { data: greeterApp } = useApp("greeter");
// Make sure that greeterApp is installed. We shouldn't show the button when app is not installed
if (!user || !greeterApp) {
return null;
}
return (
);
}
```
```; theme={null}
/**
* Shell.tsx
*/
// ...
import GreeterButton from "@calcom/app-store/greeter/components/GreeterButton";
// ...
;
```
A sample line where I used the component in the demo
That's it. You now have a fully functional Greeter app. This is the simplest possible demonstration of how you can build an app and what it can do. There are simply no restrictions on what an app can achieve.
# How to build an app
Source: https://cal.com/help/apps-and-integrations/how-to-build-an-app
We are ready to bring your ideas to life through a collaborative partnership. If you need a tailored solution, our team will work directly alongside you to design, develop, and launch your application.
**How to get started:**
* Visit [cal.com/feature](http://cal.com/feature)
* Fill the form and submit a request
We will build the app with you.
# HubSpot and Cal.com
Source: https://cal.com/help/apps-and-integrations/hubspot
With our HubSpot integration you can sync data between Cal.com and your instance of HubSpot.
## Basic functionality
* On booking, we create a meeting record in HubSpot and associate it with the attendee's contact record
* On reschedule, we update the meeting record's dates and set the outcome to "Rescheduled"
* On cancellation, we update the meeting outcome to "Canceled"
## Event Type Options
#### Do not create new records for guests added to the booking
If this option is enabled, we will only handle creating meetings under the main attendee of the event and not additional guests.
#### Skip creating contacts if they do not exist in HubSpot
If this option is enabled, skip creating new contacts if they do not exist in HubSpot already. We search for contacts based on the attendee email.
#### Set booking organizer as contact owner
When this option is enabled, the booking organizer will be set as the HubSpot owner of the contact record. This requires the organizer's email to match a HubSpot user.
#### Overwrite existing contact owner
This option is available when [Set booking organizer as contact owner](#set-booking-organizer-as-contact-owner) is enabled. If this option is enabled, the contact owner will be overwritten even if the contact already has an owner. If disabled, the owner will only be set when the contact does not have an existing owner.
#### If attendee exists in HubSpot, book directly with the owner
This option is available for round robin events. When this option is enabled, you can pass `?email` as a URL param in the round robin booking link, Cal.com searches HubSpot for the contact owner. If the contact owner is a host of the round robin event, then only that owner's availability is presented and the attendee books directly with the owner.
#### If attendee has a free email domain, skip the ownership check and round robin as normal
If this option is enabled, if the attendee has a free email domain (ex. gmail.com) then ignore any HubSpot ownership checks.
#### On booking, write to event object
To use this feature, your HubSpot account must be enrolled in the [Meetings index page and custom meeting properties](https://app-eu1.hubspot.com/l/product-updates/?rollout=195886) beta program.
When a booking is created, you can write to specific fields on the meeting record. To write to a field you need the following:
* The API field name ex. `custom_field`
* The field type in HubSpot. We currently support the following types:
* Text
* Date
* Phone
* Checkbox
* Custom (ignores field validations)
* The value that you want to pass to the field ([Mapping data from Cal.com to HubSpot](#mapping-data-from-cal-com-to-hubspot))
* For checkbox fields, you can choose whether to pass true or false
## Appendix
#### Mapping data from Cal.com to HubSpot
When writing to fields in HubSpot, you can pass data from different sources in Cal.com:
* To pass a static value, input the value in the `Value` field
* To pass a value from a booking question, wrap the identifier of the booking question in `{}` brackets. For example, if you have a booking question with the identifier `productInterest` you would input `{productInterest}` in the `Value` field
* To pass a `utm_parameter`, pass the parameter name as `{utm:parameter}` in the value field. We currently support the following:
* `utm_source` as `{utm:source}`
* `utm_medium` as `{utm:medium}`
* `utm_campaign` as `{utm:campaign}`
* `utm_term` as `{utm:term}`
* `utm_content` as `{utm:content}`
# How to use OAuth to authorize apps with Cal.com accounts
Source: https://cal.com/help/apps-and-integrations/oauth
Set up OAuth to let your app access Cal.com on behalf of users, with scoped permissions for bookings, calendars, schedules, webhooks, routing forms, workflows, and more.
As an example, you can view our OAuth flow in action on Zapier. Try to connect your Cal.com account [here](https://zapier.com/apps/calcom/integrations). To enable OAuth in one of your apps, you will need a Client ID, Client Secret, Authorization URL, Access Token Request URL, and Refresh Token Request URL.
## OAuth client credentials
You can create an OAuth client from your [developer settings](https://app.cal.com/settings/developer/oauth). The OAuth client starts in a "pending" state and must be reviewed by a Cal.com admin before it can be used. You must select at least one scope when creating the client. You can register up to 10 redirect URIs per client.
## OAuth scopes
Scopes control which API endpoints your OAuth token can access. When a user authorizes your client, the issued access token can only call endpoints covered by the granted scopes. Any request to an endpoint outside those scopes is rejected.
You must select your scopes when creating your OAuth client, and include them in the authorization URL.
### Available scopes
| Scope | Description | What it covers |
| -------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `EVENT_TYPE_READ` | View event types | Listing and viewing event types and their private links |
| `EVENT_TYPE_WRITE` | Create, edit, and delete event types | Creating, updating, deleting event types and managing private links |
| `BOOKING_READ` | View bookings | Listing bookings, viewing recordings, transcripts, calendar links, and references |
| `BOOKING_WRITE` | Create, edit, and delete bookings | Adding guests, updating locations, confirming, declining, and reassigning bookings |
| `SCHEDULE_READ` | View availability | Listing and viewing schedules |
| `SCHEDULE_WRITE` | Create, edit, and delete availability | Creating, updating, and deleting schedules |
| `APPS_READ` | View connected apps and calendars | Listing connected calendars, checking busy times, checking ICS feeds, and verifying calendar connections |
| `APPS_WRITE` | Connect and disconnect apps | Saving ICS feeds, connecting calendars via OAuth, saving Apple calendar credentials, and disconnecting calendars |
| `PROFILE_READ` | View personal info | Viewing the authorized user's profile |
| `PROFILE_WRITE` | Edit personal info | Updating the authorized user's profile |
| `WEBHOOK_READ` | View webhooks | Listing and viewing webhooks |
| `WEBHOOK_WRITE` | Create, edit, and delete webhooks | Creating, updating, and deleting webhooks |
| `VERIFIED_RESOURCES_READ` | View verified emails and phone numbers | Listing verified email addresses and phone numbers |
| `VERIFIED_RESOURCES_WRITE` | Verify emails and phone numbers | Requesting verification codes and verifying email addresses and phone numbers |
Some endpoints like creating, cancelling, and rescheduling bookings are public and do not require any scope.
### Team scopes
Team scopes control access to team-level resources. These apply to endpoints under `/v2/teams/:teamId/...` and `/v2/organizations/:orgId/teams/:teamId/...`.
| Scope | Description |
| ------------------------------- | ---------------------------------------------------- |
| `TEAM_EVENT_TYPE_READ` | View team event types |
| `TEAM_EVENT_TYPE_WRITE` | Create, edit, and delete team event types |
| `TEAM_BOOKING_READ` | View team bookings |
| `TEAM_BOOKING_WRITE` | Create, edit, and delete team bookings |
| `TEAM_SCHEDULE_READ` | View team schedules |
| `TEAM_SCHEDULE_WRITE` | Create, edit, and delete team schedules |
| `TEAM_PROFILE_READ` | View team profiles |
| `TEAM_PROFILE_WRITE` | Create, edit, and delete teams |
| `TEAM_MEMBERSHIP_READ` | View team memberships |
| `TEAM_MEMBERSHIP_WRITE` | Create, edit, and delete team memberships |
| `TEAM_APPS_READ` | View team connected apps |
| `TEAM_APPS_WRITE` | Connect and disconnect team apps |
| `TEAM_ROUTING_FORM_READ` | View team routing forms |
| `TEAM_ROUTING_FORM_WRITE` | Create, edit, and delete team routing form responses |
| `TEAM_WORKFLOW_READ` | View team workflows |
| `TEAM_WORKFLOW_WRITE` | Create, edit, and delete team workflows |
| `TEAM_VERIFIED_RESOURCES_READ` | View team verified emails and phone numbers |
| `TEAM_VERIFIED_RESOURCES_WRITE` | Verify emails and phone numbers for teams |
### Organization scopes
Organization scopes control access to organization-wide resources. These apply to endpoints under `/v2/organizations/:orgId/...` that do not target a specific team.
An `ORG_` scope automatically grants the corresponding `TEAM_` scope. For example, a token with `ORG_PROFILE_READ` can also access endpoints that require `TEAM_PROFILE_READ`.
| Scope | Description |
| ------------------------ | ------------------------------------------------------------ |
| `ORG_EVENT_TYPE_READ` | View all event types across the organization |
| `ORG_EVENT_TYPE_WRITE` | Create, edit, and delete event types across the organization |
| `ORG_BOOKING_READ` | View all bookings across the organization |
| `ORG_BOOKING_WRITE` | Create, edit, and delete bookings across the organization |
| `ORG_SCHEDULE_READ` | View schedules across the organization |
| `ORG_SCHEDULE_WRITE` | Create, edit, and delete schedules across the organization |
| `ORG_PROFILE_READ` | View organization teams |
| `ORG_PROFILE_WRITE` | Create, edit, and delete organization teams |
| `ORG_MEMBERSHIP_READ` | View organization memberships and users |
| `ORG_MEMBERSHIP_WRITE` | Create, edit, and delete organization memberships and users |
| `ORG_ROUTING_FORM_READ` | View organization routing forms |
| `ORG_ROUTING_FORM_WRITE` | Create, edit, and delete organization routing form responses |
| `ORG_WEBHOOK_READ` | View organization webhooks |
| `ORG_WEBHOOK_WRITE` | Create, edit, and delete organization webhooks |
## Authorize
To initiate the OAuth flow, direct users to the following authorization URL:
```
https://app.cal.com/auth/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&state=YOUR_STATE&scope=BOOKING_READ%20BOOKING_WRITE
```
### Rotating client secrets
You can rotate your OAuth client secret without downtime. Cal.com supports up to two active secrets per client at the same time, so you can transition gracefully.
In your Cal.com dashboard, go to your OAuth client settings and create a new secret. Both your old and new secrets are now valid.
Replace the old `client_secret` value in your application with the new one. Verify that token exchanges and refreshes work with the new secret.
Once your application is using the new secret, delete the old one from your OAuth client settings.
You cannot delete your last remaining secret. Confidential OAuth clients must always have at least one active secret.
### Authorization URL
**URL parameters:**
| Parameter | Required | Description |
| ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `client_id` | Yes | Your OAuth client ID |
| `redirect_uri` | Yes | Where users will be redirected after authorization. Must match one of your registered redirect URIs. |
| `state` | Recommended | A securely generated random string to mitigate CSRF attacks |
| `scope` | Yes | Space or comma-separated list of scopes (e.g. `BOOKING_READ BOOKING_WRITE`). Must be a subset of scopes enabled on your OAuth client. |
| `code_challenge` | For public clients | PKCE code challenge (S256 method) |
After users click **Allow**, they are redirected to your `redirect_uri` with the authorization `code` as a URL parameter. If you included a `state` parameter in the authorization URL, it is returned unchanged so you can verify the response matches the original request.
## Exchange token
Exchange the authorization code for access and refresh tokens.
**Endpoint:** `POST https://api.cal.com/v2/auth/oauth2/token`
**Request body:**
| Parameter | Description |
| --------------- | ------------------------------------------------------------- |
| `client_id` | Your OAuth client ID |
| `client_secret` | Your OAuth client secret |
| `grant_type` | Must be `authorization_code` |
| `code` | The authorization code received in the redirect URI |
| `redirect_uri` | Must match the redirect URI used in the authorization request |
**Response:**
```json theme={null}
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 1800,
"scope": "BOOKING_READ BOOKING_WRITE"
}
```
Access tokens expire after 30 minutes. Use the refresh token to get a new access token.
## Refresh token
Refresh an expired access token using your refresh token.
**Endpoint:** `POST https://api.cal.com/v2/auth/oauth2/token`
**Request body:**
| Parameter | Description |
| --------------- | ------------------------------------------------ |
| `client_id` | Your OAuth client ID |
| `client_secret` | Your OAuth client secret |
| `grant_type` | Must be `refresh_token` |
| `refresh_token` | The refresh token from a previous token response |
**Response:**
```json theme={null}
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 1800,
"scope": "BOOKING_READ BOOKING_WRITE"
}
```
Scopes are preserved from the original authorization. You do not need to re-request scopes when refreshing tokens.
## Client secret rotation
You can rotate your client secret with zero downtime. Cal.com allows up to 2 active secrets at a time, so you can deploy a new secret before revoking the old one.
Go to your [OAuth client settings](https://app.cal.com/settings/developer/oauth) and generate a new secret. Your old secret continues to work.
Use the new secret in all token exchange and refresh requests.
Once you've verified the new secret works, revoke the old one from the settings page. Revocation takes effect immediately.
Existing access and refresh tokens remain valid after secret rotation. Rotation only affects requests that require `client_secret` (token exchange and refresh).
## Verify access token
To verify the correct setup and functionality of OAuth credentials, use the following endpoint: `GET https://api.cal.com/v2/me`
**Headers:**
* Authorization: Bearer *YOUR\_ACCESS\_TOKEN*
## Legacy client migration
If your OAuth client was created before scopes were introduced, it is a legacy client. Tokens from legacy clients can access any resource on behalf of the authorizing user without scope restrictions.
You can migrate a legacy client to use explicit scopes without creating a new client:
Add a `scope` parameter to your authorization URL before changing any client settings. New tokens will carry only the scopes you specify.
Once your authorization URL is updated and working, open your OAuth client settings and select the matching scopes. After saving, scope validation is enforced for all new authorization requests.
Do not update the client scopes before updating your authorization URL. Doing so will break the authorization flow for any user visiting the old URL without a `scope` parameter.
Tokens issued before the migration continue to work until users re-authorize.
# Pipedrive and Cal.com
Source: https://cal.com/help/apps-and-integrations/pipedrive
With our Pipedrive integration you can sync data between Cal.com and your Pipedrive account, so every booking, reschedule, and cancellation is automatically reflected in your CRM.
## Basic functionality
* On booking, we create an activity in Pipedrive and associate it with the attendee's person record
* On reschedule, we update the activity's date and time
* On cancellation, we mark the activity as deleted
## Installing Pipedrive
You can install the Pipedrive app for your personal account or for a team you administer.
### Personal install
1. Go to the [App Store](https://app.cal.com/apps) and select **Pipedrive CRM**.
2. Click **Install**.
3. You'll be redirected to Pipedrive to authorize Cal.com.
4. After approving, you'll be returned to Cal.com and the app will be available on your event types.
### Team install
If you're an admin or owner of a team, you can install Pipedrive for the team so that bookings on team event types sync to a shared Pipedrive workspace.
1. Go to your team's **Apps** page in Cal.com.
2. Find **Pipedrive CRM** and click **Install**.
3. Select the team you want to install the app on.
4. Authorize Cal.com in Pipedrive when redirected.
Only team admins and owners can install or remove the Pipedrive credential on a team. Once installed, the team's Pipedrive credential is available to any team event type.
## Event type options
#### Do not create new records for guests added to the booking
If this option is enabled, we will only handle creating activities under the main attendee of the event and not additional guests.
#### Skip creating contacts if they do not exist in Pipedrive
If this option is enabled, skip creating new person records if they do not exist in Pipedrive already. We search for contacts based on the attendee email.
## Required permissions
When you authorize Cal.com, Pipedrive grants the following scopes:
* `deals:read`, `deals:write`
* `persons:read`, `persons:write`
* `activities:read`, `activities:write`
These permissions allow Cal.com to look up attendees, create activities for bookings, and update or delete activities when bookings change.
# Salesforce and Cal.com
Source: https://cal.com/help/apps-and-integrations/salesforce
With our Salesforce integration you can sync data between Cal.com and your instance of Salesforce.
## Basic functionality
* On booking, we create an event record under a lead/contact record
* On reschedule, we adjust the event record's dates
* On cancellation, we delete the event record
## Event Type Options
#### On booking, add events on and new attendees as
Choose which record to create Salesforce events under or if the attendee does not exist in Salesforce as the selected record create a new record of the chosen type. We search for records based on the attendee email.
**Options**
* Contact
* Lead
* Contact under an account
#### Do not create new records for guests added to the booking
If this option is enabled, we will only handle creating events under the main attendee of the event and not additional guests
#### Skip creating contacts if they do not exist in Salesforce
This option is available when [adding events on contacts](#on-booking,-add-events-on-and-new-attendees-as). If the option is enabled, skip creating new contacts if they do not exist in Salesforce already.
#### Create event on contact, if it exists. Else fallback to lead
This option is available when [adding events on leads](#on-booking,-add-events-on-and-new-attendees-as). If this option is enabled, we check if a contact already exists with the attendee's email. If it does, create the event on the contact record. If it does not exist, then we create the event on an existing lead record or create a new lead
#### Create a new contact under an account based on email domain of attendee and existing contacts
This option is available when [adding events on leads or a contact under an account](#on-booking,-add-events-on-and-new-attendees-as). If this option is enabled, we create a new contact under an account if it does not already exist then create an event under that new contact.
[Determining which account an attendee belongs to](#determining-if-an-attendee-belongs-under-an-account)
#### If the contact does not exist under an account, create new lead from attendee
This option is available when [adding events on contacts under an account](#on-booking,-add-events-on-and-new-attendees-as). If a contact under an account does not exist, then create a new lead record.
#### On booking, write to event object
When a booking is created, you can write to specific fields on the event record. To write to a field you need the following:
* The API field name ex. `Custom_Field__c`
* The value that you want to pass to the field ([Mapping data from Cal.com to Salesforce](#mapping-data-from-cal-com-to-salesforce))
#### On booking, write to a custom field on the attendee record
This option writes to fields on the type of record that is set [to create events on](#on-booking,-add-events-on-and-new-attendees-as). To write to a field you need the following:
* The API field name ex. `Custom_Field__c`
* The field type in Salesforce. We current support the following types:
* Text (`text`, `textarea` )
* Date (`date`, `datetime`)
* Phone
* Checkbox
* Picklist
* Custom (ignores field validations)
* The value that you want to pass to the field ([Mapping data from Cal.com to Salesforce](#mapping-data-from-cal-com-to-salesforce))
* For checkbox fields, you can choose whether to pass true or false
* For picklist fields, the value passed needs to match the value of a picklist option
* When to write to the field
* When the field is empty
* On every booking, overwriting the previous values
#### Change record owner on booking
If you have an integration account that is creating records in Salesforce, you can pass the integration account name and Cal.com will change the owner of the attendee record to the organizer of the booking.
#### If attendee exists in Salesforce, book directly with the owner
This option is available for round robin events. When this option is enabled, you can pass `?email` as a URL param in the round robin booking link, Cal.com searches Salesforce for the record owner. If the record owner is a host of the round robin event, then only that owner's availability is presented and the attendee books directly with the owner.
Options to search ownership against
* Lead
* Contact
* Account — Cal.com uses the full [account resolution waterfall](#determining-if-an-attendee-belongs-under-an-account) to find the matching account. If the initial lookup returns no results, Cal.com automatically falls back to normalized website matching and, when enabled, [fuzzy cross-TLD matching](#cross-tld-fuzzy-domain-matching). This means attendees with regional email domains (for example, `user@acme.co.uk`) can still be matched to the correct account owner even if the account's website is listed as `acme.com`.
When this option is enabled, you can also turn on **Show banner with CRM contact owner** to display a banner at the top of the booking page confirming who the attendee is booking with (for example, "Booking directly with [jane@acme.com](mailto:jane@acme.com)"). The banner only appears when a matching CRM contact owner is resolved for the attendee; otherwise the booking page renders as usual.
#### If attendee has a free email domain, skip the ownership check and round robin as normal
If this option is enabled, attendees with free email domains (for example, gmail.com, yahoo.com, or outlook.com) skip the Salesforce ownership check entirely and go through normal round robin assignment. This applies to all ownership lookup types, including Account-based lookups.
## Viewing routing traces for Salesforce-routed bookings
When a booking is routed through Salesforce ownership — even without a routing form — Cal.com records a routing trace that shows how the host was selected. You can view the trace from the bookings list (via the actions menu) or from the booking detail page.
This is useful for verifying that Salesforce-based routing resolved to the correct owner and for troubleshooting assignment issues.
For more details on routing traces, see [Routing overview](/help/routing/routing-overview#5-routing-trace).
#### On cancelled booking, write to event record instead of deleting event
When this option is enabled, instead of deleting the event record we write to specific fields. To write to a field you need the following:
* The API field name ex. `Custom_Field__c`
* The field type in Salesforce. We current support the following types:
* Text (`text`, `textarea` )
* Date (`date`, `datetime`)
* Phone
* Checkbox
* Picklist
* Custom (ignores field validations)
* The value that you want to pass to the field ([Mapping data from Cal.com to Salesforce](#mapping-data-from-cal-com-to-salesforce))
* For checkbox fields, you can choose whether to pass true or false
* For picklist fields, the value passed needs to match the value of a picklist option
* When to write to the field
* When the field is empty
* On every booking, overwriting the previous values
#### On cancelled booking, write to a custom field on the attendee record
When this option is enabled, cancelling a booking updates fields on the attendee's contact or lead record in Salesforce. This is useful when you want to track cancellation status directly on the person's record rather than (or in addition to) the event record.
To configure, provide:
* The API field name ex. `Custom_Field__c`
* The field type in Salesforce. We current support the following types:
* Text (`text`, `textarea` )
* Date (`date`, `datetime`)
* Phone
* Checkbox
* Picklist
* Custom (ignores field validations)
* The value that you want to pass to the field ([Mapping data from Cal.com to Salesforce](#mapping-data-from-cal-com-to-salesforce))
* For checkbox fields, you can choose whether to pass true or false
* For picklist fields, the value passed needs to match the value of a picklist option
* When to write to the field
* When the field is empty
* On every cancellation, overwriting the previous values
You can use both the "write to event record" and "write to attendee record" options together. For example, you might mark the event as cancelled while also updating a status field on the contact or lead.
#### Match accounts by base domain across TLDs (fuzzy matching)
This option is available when adding events on **Account** or **Lead** records. When enabled, Cal.com uses fuzzy domain matching to find the right Salesforce account even when the attendee's email domain uses a different top-level domain (TLD) than the account's website.
For example, if an attendee's email is `user@acme.co.uk` and the Salesforce account has `acme.com` as its website, Cal.com strips the TLD from both and matches them by the base domain (`acme`). This is useful for companies that use country-specific email domains.
Fuzzy matching runs only after exact and normalized website matching have been attempted. Free email domains (e.g. `gmail.com`) are excluded automatically.
#### Send no show attendee data to event object
When this option is enabled, we set the specific checkbox field to true when an attendee is marked as no-show in Cal.com
## Record type filtering
Salesforce objects can have multiple record types — for example, your contacts may include both "Business Contact" and "Person Account" types. You can exclude specific record types so that Cal.com only looks up or creates records of the types you want.
Navigate to the event type's **Apps** tab and expand the Salesforce section.
Below the attendee record type selector, look for the **Exclude Record Types** setting.
Cal.com fetches the available record types from your Salesforce org. Select any record types you want to skip during contact or lead lookups. Records matching excluded types are filtered out of results.
Save your event type. Future bookings only match records whose record type is not in the exclusion list.
Record type matching is case-insensitive. This setting applies to both lookups and record creation — Cal.com does not create records with an excluded record type.
## Field mapping validation
Cal.com validates your Salesforce field mappings when you save event type settings. If a field mapping has a type mismatch — for example, a non-boolean value mapped to a checkbox field, or an empty value for a required text field — Cal.com displays an inline error and prevents the save.
| Field type | Validation rule |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Checkbox | Value must be a boolean (`true` or `false`) |
| Date | Must reference a valid dynamic date value (e.g., `booking_start_date`, `booking_created_date`, or `booking_cancel_date`) |
| Text, phone, picklist, textarea | Value must be a non-empty string |
| Custom | No automatic validation — values are passed through as-is |
## Sync error notifications
When a Salesforce sync fails at booking time — for example, due to a permission error or an invalid field — Cal.com stores the error and displays a diagnostic notification on the Salesforce settings tab. The notification includes:
* The error code and message
* Which fields were dropped from the sync
* A timestamp of when the error occurred
This helps you identify and fix integration issues without needing to check Salesforce logs directly.
## Cross-TLD fuzzy domain matching
When using the **Contact under Account** attendee record type, Cal.com resolves the attendee's Salesforce account by matching their email domain against account `Website` fields. By default, this lookup requires an exact domain match — `acme.com` only matches accounts whose website is on `acme.com`.
With **cross-TLD fuzzy domain matching** enabled, Cal.com also matches across different top-level domains. An attendee with an `@acme.co.uk` email can be matched to a Salesforce account whose website is `acme.com`, `acme.de`, or any other TLD variant sharing the same base domain.
Fuzzy domain matching is a per-credential toggle — enable it in your Salesforce connection settings, and it applies to all event types using that credential.
### How account resolution works
Cal.com resolves the attendee's Salesforce account using a multi-step waterfall:
1. **Exact match** — Look for an account whose `Website` exactly matches the attendee's email domain (for example, `acme.com`)
2. **Normalized match** — Strip URL prefixes like `www.`, `http://`, and trailing paths, then retry the exact match
3. **Contact email match** — Search for existing contacts whose email domain matches, and use their linked account
4. **Fuzzy cross-TLD match** — Extract the base domain (for example, `acme` from `acme.co.uk`) and match it against all account websites regardless of TLD
Cal.com uses the first match found. If multiple accounts match at any step, the [tiebreaker waterfall](#tiebreaker-waterfall) runs to select the best candidate. If no account is resolved at any step, the integration falls back to the behavior configured in your event type settings.
This same resolution waterfall also runs for [Account-based round robin ownership lookups](#if-attendee-exists-in-salesforce,-book-directly-with-the-owner). If the initial Account lookup returns no results, Cal.com falls back through normalized and fuzzy matching to find the correct account owner.
Fuzzy matching applies to the **Contact under Account** attendee record type and to **Account-based round robin ownership lookups**. It does not affect contact-only or lead-only lookups.
### When to use fuzzy matching
Fuzzy domain matching is useful when:
* Your Salesforce accounts have websites on a single TLD (for example, `acme.com`) but attendees book from regional email domains (for example, `@acme.co.uk`, `@acme.de`)
* You want to automatically link international attendees to the correct parent account without creating duplicate records
* Your organization operates across multiple country domains under the same brand
### Tiebreaker waterfall
When multiple Salesforce accounts match a domain during account resolution, Cal.com runs a tiebreaker waterfall to select the best candidate. This is especially relevant for round robin event types where the resolved account owner determines which host receives the booking.
You can customize which tiebreaker rules are active and the order in which they run. By default, all nine rules are enabled in the order shown below. The first criterion that produces a single winner ends the waterfall:
| Default priority | Rule | Category | Description |
| ---------------- | --------------------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| 1 | Sub-region match | Geo | Account whose custom sub-region field matches the booker's sub-region (geo tiebreaker only) |
| 2 | Country + state + zip match | Geo | Account whose billing address matches the booker's country, state, and postal code (geo tiebreaker only) |
| 3 | Country + state match | Geo | Account whose billing country and state match the booker's (geo tiebreaker only) |
| 4 | Country match | Geo | Account whose billing country matches the booker's (geo tiebreaker only) |
| 5 | Most child accounts | Size | Account with the highest number of child accounts in its hierarchy |
| 6 | Most opportunities | Size | Account with the highest number of related opportunities |
| 7 | Most contacts | Size | Account with the most related contact records |
| 8 | Most recent activity | Recency | Account with the most recent `LastActivityDate` |
| 9 | Oldest account | Age | Account with the oldest `CreatedDate` (longest-standing relationship) |
Geo rules (1–4) only apply when a booking comes through a routing form that collects the booker's location. They are skipped for direct bookings. If geo tiebreaker is not configured, those rules are skipped. If all active criteria result in a tie, Cal.com falls back to round robin assignment.
#### Configuring tiebreaker rules
You can enable, disable, reorder, add, and remove tiebreaker rules from your event type's Salesforce settings.
Navigate to the event type's **Apps** tab and expand the Salesforce section.
Scroll to **Tiebreaker Priority Rules**. Use the toggle to enable or disable the entire tiebreaker waterfall.
Hover over a rule and use the arrow buttons to move it up or down. Rules at the top are evaluated first.
Click the trash icon on any rule you do not need. Removing a rule means it is skipped during account resolution.
Click **Add rule** below the list to add a rule that was previously removed. Select the rule from the dropdown — each rule shows a description and category to help you decide.
Save your event type. The updated rule order and selection apply to new bookings immediately.
If no tiebreaker rules resolve the tie, Cal.com falls back to standard round robin assignment. You can see which rule decided a booking in the [routing trace](/help/routing/routing-overview#5-routing-trace).
#### Host filtering
For round robin event types, candidates are filtered before the tiebreaker runs. Only account owners who are hosts on the event type are eligible. If this filter removes all candidates, Cal.com falls back to standard round robin assignment.
### Geo tiebreaker
The geo tiebreaker lets Cal.com prefer the Salesforce account that is geographically closest to the booker when multiple accounts match. It compares the booker's location against each candidate account's billing address fields (`BillingCountry`, `BillingState`, `BillingPostalCode`) and an optional custom sub-region field. The closest geographic match wins before any size or recency-based tiebreakers run.
Geo tiebreakers only apply when a booking comes through a routing form — they are skipped for direct bookings.
#### Convention-based field identifiers
The simplest way to enable geo tiebreakers is to add fields to your routing form using the standard identifiers below. Cal.com detects these automatically with no per-route configuration required.
| Field identifier | Description | Matches against | IP fallback |
| ---------------- | --------------------------------------- | ------------------------------------ | ----------- |
| `country` | The booker's country (ISO code or name) | Account `BillingCountry` | Yes |
| `state` | The booker's state or region | Account `BillingState` | Yes |
| `zip` | The booker's ZIP or postal code | Account `BillingPostalCode` | No |
| `sub_region` | A custom sub-region value | A custom field on the Account object | No |
Use the exact identifier shown (lowercase, snake\_case). The field label displayed to the booker can be anything you want.
When a `country` or `state` form field is missing or left blank, Cal.com automatically falls back to the booker's IP geolocation to determine their country and state. ZIP and sub-region do not have an IP fallback.
When any geo tiebreaker rule is active, a **"How do geo tiebreakers read booker location?"** link appears in the tiebreaker rules section. Click it to see the field identifiers and which rules use each field.
### Route to custom lookup field
When routing form routes are set to **Route to custom lookup field**, Cal.com resolves the host by reading a **user lookup field** on the attendee's Salesforce account, instead of using the account's owner. This is useful when you assign bookings to a rep tracked outside of `Account.OwnerId` — for example a `Region_Manager__c` field, or a manager on a related record like a parent account or region.
Enter the field's API name in **Lookup field name**. Two syntaxes are supported:
* **Flat field on the Account** — the API name of a user lookup field defined directly on the Account object, for example `Region_Manager__c`.
* **Dot-notation to a connected object** — a path that hops through a relationship on the Account and ends at a user lookup field on the connected object, for example `Region__r.Owner__c` or `Parent.Owner__c`.
In a dot-notation path, each intermediate segment is a **relationship name** (custom relationships end in `__r`; standard relationships such as `Parent` or `Owner` are also allowed), and the final segment is the API name of the user lookup field to read on that related object. Only letters, numbers, and underscores are allowed in each segment. Cal.com validates the syntax as you type and shows an inline error if the name is malformed.
Cal.com follows the first target of a polymorphic lookup. If the resolved value is not a valid user ID — for example the field is empty or the traversal hits a missing record — routing falls back to standard round robin assignment for the event.
#### Configuring geo tiebreaker per route
You can also configure the geo tiebreaker on individual routes within a routing form. This is available when the Salesforce routing option is set to **Route to custom lookup field** and gives you control over the field mapping on a per-route basis.
Navigate to **Routing Forms** and select the form you want to configure.
Choose the route where you want to enable geographic tiebreaking. The route must use the **Route to custom lookup field** Salesforce option.
Toggle **Geo tiebreaker** on. A configuration panel appears with the following fields.
Enter the routing form field identifiers that capture the booker's location. These are the identifiers of fields on your routing form, not Salesforce field names.
| Setting | Description | Example value |
| --------------------------------------- | --------------------------------------------------------- | ------------- |
| Booker country field identifier | The form field that captures the booker's country | `country` |
| Booker state field identifier | The form field that captures the booker's state or region | `state` |
| Booker zip/postal code field identifier | The form field that captures the booker's postal code | `zip` |
| Booker sub-region field identifier | (Optional) A form field for a custom sub-region value | `sub_region` |
If you use a custom sub-region field on the Account object in Salesforce, enter its API name in the **Salesforce sub-region field API name** setting (for example, `Sub_Region_DV__c`). This enables priority 1 matching in the tiebreaker waterfall.
Toggle **Use IP geolocation as fallback** if you want Cal.com to use the booker's IP address to determine their country and state when the routing form fields are empty. This uses standard geolocation headers from the hosting provider.
Save your changes. The geo tiebreaker takes effect for new bookings routed through this form.
#### How geo matching works
When the geo tiebreaker is enabled, Cal.com compares the booker's location against each candidate account's Salesforce billing address in this order:
1. **Sub-region** — If configured, check whether the account's custom sub-region field matches the booker's sub-region value. This is useful for organizations that segment territories by custom regions.
2. **Country + state + zip** — Match the account's `BillingCountry`, `BillingState`, and `BillingPostalCode` against the booker's location.
3. **Country + state** — Match on country and state only, ignoring postal code.
4. **Country** — Match on country only.
The first level that narrows candidates to a single account wins. If multiple accounts still tie after all geographic checks, the waterfall continues with size and recency-based criteria (child accounts, opportunities, contacts, recent activity, and creation date).
The geo tiebreaker only applies when bookings come through a routing form. It does not apply to direct bookings or event type-level Salesforce settings. Per-route configuration is only available when the route uses the **Route to custom lookup field** Salesforce option.
## Field mapping validation
Cal.com validates your Salesforce field mappings at two points to help you catch configuration issues early.
### Inline validation
When you add or edit a field mapping entry, Cal.com checks that the value you provide is compatible with the selected field type:
* **Checkbox** fields require a boolean value (True or False). Entering text triggers an error.
* **Date** fields require a valid date reference (such as Booking Start Date or Booking Created Date).
* **Text**, **Phone**, **Picklist**, and **Custom** fields require a non-empty text value.
If a value is invalid, an error message appears directly below the field mapping row so you can correct it before saving.
### Save-time validation
When you save your event type settings, Cal.com connects to your Salesforce org and validates each field mapping against the actual Salesforce schema. The following checks run automatically:
* **Field existence** — the API field name must exist on the Salesforce object.
* **Writability** — the field must not be read-only.
* **Type compatibility** — if you configured a field as Checkbox, the Salesforce field must be a boolean (and vice versa).
* **Picklist values** — for Picklist fields, the value you entered must match one of the active picklist options in Salesforce.
* **Field name casing** — the field name must match the exact casing used in Salesforce (for example, `Custom_Field__c` instead of `custom_field__c`).
If any check fails, the save is blocked and you see an error message describing which field has the problem and what needs to be fixed.
If your Salesforce connection is inactive or unreachable, save-time validation is skipped so that you can still save other event type settings. Reconnect Salesforce to re-enable validation.
### Sync error notifications
If a booking triggers a write to Salesforce and it fails at runtime, Cal.com stores the error details and displays a diagnostic notification banner at the top of the Salesforce settings tab for that event type. The banner includes:
* **Error code** — the Salesforce error code (for example, `FIELD_CUSTOM_VALIDATION_EXCEPTION`).
* **Error message** — a description of what went wrong.
* **Dropped fields** — if custom fields caused the failure, the fields that were removed from the write so the booking could still be created.
* **Timestamp** — when the error occurred.
You can dismiss the banner after reviewing the error. To prevent the error from recurring, update your field mappings using the guidance in the error message.
## Appendix
#### Determining if an attendee belongs under an account
Cal.com resolves the attendee's Salesforce Account using a multi-step waterfall:
1. **Exact website match** — Check Account `Website` fields for an exact domain match against the attendee's email domain
2. **Normalized website match** — Strip protocols, paths, ports, and trailing slashes from Account `Website` values before comparing. This means accounts with website values like `https://www.acme.com/about/` or `HTTP://ACME.COM:443/en/` still match an attendee with an `@acme.com` email.
3. **Contact email match** — Search for existing contacts whose email domain matches, and use their linked Account
4. **Fuzzy cross-TLD match** — Extract the base domain (for example, `acme` from `acme.co.uk`) and match it against all Account websites regardless of TLD
Cal.com uses the first match found. If multiple Accounts match at any step, the [tiebreaker waterfall](#tiebreaker-waterfall) runs to select the best candidate. If no Account is resolved at any step, the integration falls back to the behavior configured in your event type settings.
#### Tiebreaker waterfall
When multiple Salesforce Accounts match a domain during account resolution, Cal.com runs a configurable tiebreaker waterfall to select the best candidate. This is especially relevant for round-robin event types where the resolved Account owner determines which host receives the booking.
You can customize which rules are active and their priority order in your event type's Salesforce settings under **Tiebreaker Priority Rules**. See [Configuring tiebreaker rules](#configuring-tiebreaker-rules) for step-by-step instructions.
By default, all nine rules are enabled. The first criterion that produces a single winner ends the waterfall:
| Default priority | Rule | Category | Description |
| ---------------- | --------------------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| 1 | Sub-region match | Geo | Account whose custom sub-region field matches the booker's sub-region (geo tiebreaker only) |
| 2 | Country + state + zip match | Geo | Account whose billing address matches the booker's country, state, and postal code (geo tiebreaker only) |
| 3 | Country + state match | Geo | Account whose billing country and state match the booker's (geo tiebreaker only) |
| 4 | Country match | Geo | Account whose billing country matches the booker's (geo tiebreaker only) |
| 5 | Most child accounts | Size | Account with the highest number of child Accounts in its hierarchy |
| 6 | Most opportunities | Size | Account with the highest number of related Opportunities |
| 7 | Most contacts | Size | Account with the most related Contact records |
| 8 | Most recent activity | Recency | Account with the most recent `LastActivityDate` |
| 9 | Oldest account | Age | Account with the oldest `CreatedDate` (longest-standing relationship) |
Geo rules (1–4) only apply when a booking comes through a routing form that collects the booker's location. They are skipped for direct bookings. If geo tiebreaker is not configured, those rules are skipped. If all active criteria result in a tie, Cal.com falls back to round-robin assignment.
For round-robin event types, candidates are filtered before the tiebreaker runs. Only Account owners who are hosts on the event type are eligible. If this filter removes all candidates, Cal.com falls back to standard round-robin assignment.
#### Record type filtering
You can exclude specific Salesforce record types from account resolution. When record type filtering is enabled, Accounts with excluded record types are skipped during the resolution waterfall. This prevents Cal.com from matching against Accounts that are not relevant to booking routing, such as partner or vendor accounts.
Configure record type filtering in the Salesforce section of your event type's **Apps** tab.
#### When to use fuzzy matching
Fuzzy domain matching is useful when:
* Your Salesforce org has accounts with different TLDs (for example, `acme.com` and `acme.co.uk`)
* Attendees book from regional email domains that differ from the main account website
* You want Cal.com to match attendees to the correct account without manually maintaining every domain variant
Fuzzy matching applies to the **Contact under Account** attendee record type and to **Account-based round robin ownership lookups**. It does not affect Contact-only or Lead-only lookups.
#### Field mapping validation
Cal.com validates your Salesforce field mappings when you save event type settings. If a field mapping has a type mismatch — for example, a non-boolean value mapped to a checkbox field, or an empty value for a required text field — Cal.com displays an inline error and prevents the save.
If a sync error occurs at runtime (for example, a field was deleted in Salesforce after configuration), Cal.com stores the error and displays a diagnostic notification on the Salesforce settings tab. The notification includes the error code, message, any dropped fields, and a timestamp to help you troubleshoot.
| Field type | Validation rule |
| ------------------------------- | ---------------------------------------------------------------------- |
| Checkbox | Value must be a boolean (`true` or `false`) |
| Date | Must reference a valid dynamic date value (e.g., `booking_start_date`) |
| Text, phone, picklist, textarea | Value must be a non-empty string |
| Custom | No automatic validation — values are passed through as-is |
#### Mapping data from Cal.com to Salesforce
When writing to fields in Salesforce, you can pass data from different sources in Cal.com
* To pass a static value, input the value in the `Value` field
* To pass a value from a booking question, wrap the identifier of the booking question in `{}` brackets. For example, if you have a booking question with the identifier `productInterest` you would input `{productInterest}` in the `Value` field
* To pass a value from a routing form, wrap the identifier of the field of you want to pass in `{}` and add the `form:` prefix. For example, if the field identifier is `productInterest` you would input `{form:productInterest}` in the `Value` field
* To pass a `utm_parameter`, pass the parameter name as `{utm:parameter}` in the value field. We currently support the following:
* `utm_source` as `{utm:source}`
* `utm_medium` as `{utm:medium}`
* `utm_campaign` as `{utm:campaign}`
* `utm_term` as `{utm:term}`
* `utm_content` as `{utm:content}`
# How to sync third party apps with a self-hosted Cal.com instance
Source: https://cal.com/help/apps-and-integrations/syncing-third-party
1. Add the required variables in your `.env` file
1. `CALCOM_WEBHOOK_SECRET`
1. You can generate this by running `openssl rand -base64 32`. This is required when sending 3rd party app credentials from your platform to your instance of Cal.com.
2. On your self-hosted instance of Cal.com visit settings/admin/apps under an admin account. Here you can enable/disable apps on Cal.com and set the app keys (client id, client secret, etc.). These keys should match the ones on your platform.
3. `CALCOM_WEBHOOK_HEADER_NAME`
1. The header name is expected to contain the webhook secret. The default is `calcom-webhook-secret`
4. `CALCOM_CREDENTIAL_SYNC_ENDPOINT`
1. The endpoint on your platform that your instance of [Cal.com](http://Cal.com) will make a request to if the 3rd party app credentials are expired.
5. `CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY`
1. When sending 3rd party app credentials between your platform and your instance Cal.com, we expect these to be encrypted using AES256. When you encrypt the 3rd party app credentials, ensure the same key is used.
2. When a user adds a 3rd party app on your platform, you should send the credentials that are created to your instance of [Cal.com](http://Cal.com) to `${CALCOM_WEBAPP_URL}/api/webhook/app-credential` . The payload should contain the following
```javascript theme={null}
{
// UserId of the Cal.com user
userId: number;
// The app slug that is on Cal.com.
// Can be found in the Cal.com database in the App table
appSlug: string;
// The credentials from the 3rd party app. (ex. Access token, refresh token).
// Ideally it should contain the access token and expiry date
// AES256 encrypted with CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY
keys: string;
}
```
3. When [Cal.com](http://Cal.com) needs to refresh the app credentials it will make a request to `CALCOM_CREDENTIAL_SYNC_ENDPOINT`. The request contains the following.
```javascript theme={null}
{
calcomUserId: string;
// App slug on Cal.com
appSlug: string;
}
```
This only works if you have integrated [Cal.com](http://cal.com/) into your platform. Users **must** consent to give access to your platform, and you are simply using [Cal.com](http://cal.com/)'s code within your platform.
# Setting up OIDC with okta
Source: https://cal.com/help/auth-and-provision/oidc-with-okta
1. Set SAML\_DATABASE\_URL to a Postgres database. Please use a different database than the main Cal instance since the migrations are separate for this database. For example `postgresql://postgres:@localhost:5450/cal-saml`. If you are using a self-signed certificate for Postgres then use the `sslmode=no-verify` query param in the database URL. For example `postgresql://postgres:@localhost:5450/cal-saml?sslmode=no-verify`.
2. Set SAML\_ADMINS to a comma separated list of admin emails who can configure the OIDC.
3. Create an application with your OIDC provider. For example, in Okta, once you create an account, you can click on Applications on the sidebar menu:
4. Click on `Create App Integration`
5. Select OIDC in the modal form, along with Web App and click Next.
6. Enter the Sign in redirect URL (or auth URL) as
```
{BASE_URL}/api/auth/oidc
```
And the sign out URL as
```
{BASE_URL}/auth/login
```
where is your app's base URL, and click save.
Please replace `{BASE_URL}` here with respective URL, such as `localhost:3000` for localhost testing, for example.
7. Now you should have the Client Secret and Client ID with you. You would also need the Well Known URL which for Okta is generally of the type:
```
https://{yourOktaDomain}/.well-known/openid-configuration
```
So, if your okta domain is `dev-123456.okta.com`, your well known URL would be
```
https://dev-123456.okta.com/.well-known/openid-configuration
```
8. Now spin up cal.com on your server and login with the Admin user (the email ID of which was provided in step 2 for SAML\_ADMINS environment variable).
9. Visit `{BASE_URL}/settings/security/sso` and you should see something like this:
10. Click on Configure SSO with OIDC, and then enter the Client Secret, Client ID and Well known URL from the Step 7, and click save.
# Setting up SCIM with Okta
Source: https://cal.com/help/auth-and-provision/scim-okta
1. Set SAML\_DATABASE\_URL to a Postgres database. Please use a different database than the main Cal instance since the migrations are separate for this database. For example `postgresql://postgres:@localhost:5450/cal-saml`. If you are using a self-signed certificate for Postgres then use the `sslmode=no-verify` query param in the database URL. For example `postgresql://postgres:@localhost:5450/cal-saml?sslmode=no-verify`.
2. Set SAML\_ADMINS to a comma separated list of admin emails who can configure the OIDC.
3. Create an application with your OIDC provider. For example, in Okta, once you create an account, you can click on Applications on the sidebar menu:
4. Click on `Create App Integration`
5. Select SAML or OIDC in the modal form, along with Web App and click Next.
* Note you will have to fill in the appropriate fields for the SAML or OIDC setup to continue.
* [SAML Setup](/help/docs/introduction/quick-start/self-hosting/sso-setup#setting-up-saml-login)
* [OIDC Setup](/help/docs/how-to-guides/how-to-setup-oidc-with-okta)
6. Once the application is created, under General -> App Settings, click "Edit" and click the checkbox "Enable SCIM provisioning
"
7. Next go to your instance of Cal.com and navigate to `{BASE_URL}/settings/organization/dsync` and click configure.
8. In the "Configure Directory Sync" from choose a directory sync name and choose "Okta SCIM v2.0" as the "Directory Provider"
9. Take note of the "SCIM Base URL" and "SCIM Bearer Token"
10. Okta go to your application. Navigate to the "Provisioning" tab and click "Integration" under "Settings".
* Under "SCIM connector base URL" enter the "SCIM Base URL" from Cal.com
* Under "Unique identifier field for users" enter "email"
* Under "Supported provisioning actions" enable:
* "Import New Users and Profile Updates"
* "Push New Users"
* "Push Profile Updates"
* "Push Groups"
* Under "Authentication Mode" choose "HTTP Header"
* Under "Authentication" enter the "SCIM Bearer Token" from Cal.com
* When you hit save it will make a test call to the "SCIM Base URL"
11. When you hit save navigate to "To App" settings, still under the "Provisioning" tab
12. Under "Provisioning to App" click "Edit" and enable:
* "Create User"
* "Update User Attributes"
* "Deactivate User"
13. Under "`{Your application name}` Attribute Mapping", remove all fields except for:
* "username"
* "givenName"
* "familyName"
* "email"
* "displayName"
14. Set each of these of these properties to "Map from Okta Profile" and the related field. Under "Apply On" select "Create and Update"
15. You can now assign users and groups to the app.
## Mapping Okta Groups to Cal.com Teams
When provisioning groups to your organization, Okta groups can be mapped to teams within your organization and users will be auto assigned to these teams.
On `{BASE_URL}/settings/organization/dsync` there is a table with the teams under your organization. Click on "Add group name" to map the Okta group to the team. **Note:
The group name must be spelt exactly as it is shown on Okta.**. When you push the group to your organization then those users will automatically be added to the team.
# Add New Availability
Source: https://cal.com/help/availabilities/add-new-availability
How to add a new availability schedule
The availability dashboard is the area within your account where you can create new availability schedules. In order to do this, simply follow the steps below:
1. Click the button marked "+ New" in the upper right-hand corner of the screen.
2. Doing this will cause a pop-up to appear.
3. Within this pop-up is a field where you can add the name of your new availability schedule.
4. Once you've typed in the name, click the button marked "Continue."
5. Doing this will create your availability schedule and redirect you to a new page.
The page you've been redirected to is the settings area for your availability schedule. Each availability schedule you create will have its own settings page. This is the area where you can specify the days and hours for this availability schedule. From here, you can choose the timezone the availability schedule references, as well as set up any date overrides and troubleshoot.
As always, please remember to click the save button in the upper right-hand corner once you have finished making your changes to your availability schedule.
**Learn more about:**
* [Date Overrides](https://cal.com/help/availabilities/date-overrides)
* [Multiple Schedules](https://cal.com/help/availabilities/multiple-schedules)
* [Multiple Slots](https://cal.com/help/availabilities/multiple-slots)
* [Team Availability](https://cal.com/help/availabilities/team-availability)
* [Edit Availability](https://cal.com/help/availabilities/edit-availability)
# Availability Dashboard
Source: https://cal.com/help/availabilities/availability-dashboard-overview
A quick overview of Cal.com's availability dashboard
Your availability dashboard is where you can create an availability schedule. Availability schedules are used to define the hours of operation that each bookable event type cross-references when offering appointment slots.
There is no limit to the number of availability schedules Cal.com account holders can create.
From within your availability dashboard is the place where you'll be able to create, delete, duplicate, and edit your account's availability schedules. This also includes team availability schedules if you're subscribed to a team, organization, or Enterprise plan.
**Learn more about:**
* [Date Overrides](https://cal.com/help/availabilities/date-overrides)
* [Multiple Schedules](https://cal.com/help/availabilities/multiple-schedules)
* [Multiple Slots](https://cal.com/help/availabilities/multiple-slots)
* [Team Availability](https://cal.com/help/availabilities/team-availability)
* [Add New Availability](https://cal.com/help/availabilities/add-new-availability)
* [Edit Availability](https://cal.com/help/availabilities/edit-availability)
# Date overrides
Source: https://cal.com/help/availabilities/date-overrides
Cal.com allows you to create date overrides so that you can dictate when you wish to be unavailable within your typical schedule. Often times, you become unavailable for various reasons within your regular schedule and you don't have an event created in either Cal.com or any connected calendar, but you are busy to take any meetings. In such cases, you can simply make use of the Date overrides and block your otherwise bookable calendar out as per your requirements, whether it is for a few hours on a particular day, or for entire days at a stretch.
With availability date overrides, you can now pick any date that you're currently available and set specific hours for availability on that day or mark yourself entirely unavailable. Taking a half day next Thursday and Friday to do some last-minute shopping? Simply set an override on those specific days to block yourself off.
# Edit Availability
Source: https://cal.com/help/availabilities/edit-availability
You can edit your availability schedules whenever you need to. The easiest way to do this is by accessing your availability schedule's settings page.
This can be found within your availability dashboard. If you've never accessed your availability schedule settings page before, then just follow the steps below in order to do it:
1. Visit your availability dashboard.
2. Click on the availability schedule you would like to edit.
3. You will now be redirected to that availability schedule's settings page.
4. Make your desired changes.
5. Finally, click the save button in the upper right-hand corner of the screen to save your hard work.
Remember, you can revisit your availability schedule settings page whenever you need to. This means that updating your hours of operation, adding date overrides, and changing your timezone is always a simple and straightforward matter.
**Learn more about:**
* [Date Overrides](https://cal.com/help/availabilities/date-overrides)
* [Multiple Schedules](https://cal.com/help/availabilities/multiple-schedules)
* [Multiple Slots](https://cal.com/help/availabilities/multiple-slots)
* [Team Availability](https://cal.com/help/availabilities/team-availability)
* [Add New Availability](https://cal.com/help/availabilities/add-new-availability)
# Holidays
Source: https://cal.com/help/availabilities/holidays
Automatically block bookings on public holidays for your country.
The Holidays tab lets you select a country and automatically block bookings on its public holidays — no need to create a date override or out of office entry for each one. You can opt out of individual holidays you don't observe.
## When to use it
Use holidays when you want bookings to be blocked on national or public holidays without managing each date manually. Common use cases:
* Solo users who close their calendar on national holidays
* Teams that want to standardise time off around public holidays
* Anyone who wants holidays kept up to date year over year without manual edits
## Set your country
1. Go to **Settings → My account → Out of office**.
2. Open the **Holidays** tab.
3. Select your country from the dropdown. Use the search box to filter the list.
Once a country is selected, Cal.com pulls the public holidays for that country and shows them in a list with each holiday's name and date.
## Enable or disable individual holidays
Each holiday has a switch next to it. Turn it off to allow bookings on that day, or back on to block it. Changes save immediately.
This is useful if you observe most national holidays but still work on a few of them — for example, keeping Black Friday open while blocking Thanksgiving.
## Booking conflict warnings
If you select a country (or change countries) and there are existing confirmed bookings that fall on the newly enabled holidays, a warning appears at the top of the page listing the affected holidays and the number of bookings on each. Existing bookings are not cancelled automatically — review the warning and reschedule or cancel any that conflict with your new holiday settings.
## Change or clear your country
* To switch countries, open the country dropdown and pick a new one. The previous country's holidays are removed and replaced.
* To stop blocking holidays entirely, open the country dropdown and select **Clear**.
## Related
* [Out of office](/help/availabilities/out-of-office)
* [Date overrides](/help/availabilities/date-overrides)
# Multiple schedules
Source: https://cal.com/help/availabilities/multiple-schedules
You can set multiple schedules in the availability section of the application and organize your event types better by customizing your availability, quite simply, by selecting respective schedule as the availability for an individual event type. You can check [Setting up your availability](https://cal.com/help/availabilities/set-up-your-availability) to link your created availability schedule with an event type.
This feature is particularly useful if you wish to dedicate different event types over different time-zones as you can set up an availability schedule for every time-zone you wish to schedule around.
# Multiple time slots per day
Source: https://cal.com/help/availabilities/multiple-slots
Cal.com allows you to break your regular schedule day into multiple slots, allowing you to easily take time out of the calendar for consistent events such as lunch breaks, coffee breaks, or even recreational breaks.
# Out of office
Source: https://cal.com/help/availabilities/out-of-office
Block bookings, redirect them to a teammate, and manage entries for yourself or your team.
Out of office (OOO) lets you mark periods where you're unavailable so people can't book you, with the option to redirect bookings to a teammate while you're away. You can manage entries for yourself, for members of your teams, and configure recurring holidays from a single page.
## When to use it
Use out of office when you need to:
* Take time off (vacation, sick leave, parental leave) without manually editing your schedule
* Forward bookings to a colleague while you're away so leads don't go cold
* Pre-emptively block known travel days, conferences, or focus weeks
* Manage time off for teammates as a team or organization admin
## Open out of office
Go to **Settings → My account → Out of office**.
The page is split into tabs:
* **My OOO** — entries you've created for yourself
* **Team** — entries for members of teams you administer (only visible if you belong to at least one team or organization)
* **Holidays** — country-based public holidays that automatically block your calendar (see [Holidays](/help/availabilities/holidays))
## Add an out of office entry
1. On the **My OOO** tab, select **Add**.
2. Pick a **date range**. Click a start date, then an end date to set a range, or click a single day to block one day.
3. Choose a **reason** from the dropdown (for example, vacation, sick leave, public holiday). Each reason has an emoji that shows on your booking page during the OOO period.
4. (Optional) Add **notes** describing your absence. By default notes are private; toggle **Show notes publicly** if you want bookers to see them on your page.
5. (Optional) Toggle **Forward bookings** and pick a teammate to redirect bookings to while you're away. Forwarding requires a Teams plan.
6. Select **Create** to save.
The entry appears in your list and immediately blocks new bookings for that date range.
## Edit or delete an entry
* **Edit**: select an entry in the list to reopen it in the modal, then change any field and save.
* **Delete**: open the entry's actions menu and choose **Delete**. A confirmation dialog appears before the entry is removed.
## Filter and paginate entries
When you have several OOO entries, use the filters above the list to narrow by reason or by date. The list uses cursor-based pagination — use **Next** and **Previous** to move between pages. Filters and pagination only show when you have enough entries to need them.
## Manage team out of office
If you're an admin or owner of a team or organization, the **Team** tab lists OOO entries for everyone on your teams. From this tab you can:
* Add an OOO entry on behalf of a team member
* Edit or remove an existing team member's entry
* Filter by team or by member
This is useful for managing time off for direct reports or for keeping team-wide coverage visible in one place.
## How OOO affects bookings
While an OOO entry is active:
* New booking attempts on your event types are blocked for the configured dates.
* If forwarding is enabled, bookers see your selected teammate's booking page instead of an "unavailable" state.
* Existing bookings on those dates are not cancelled automatically. Review them and reschedule or cancel as needed.
## Related
* [Holidays](/help/availabilities/holidays)
* [Date overrides](/help/availabilities/date-overrides)
* [Multiple schedules](/help/availabilities/multiple-schedules)
# Team Availability
Source: https://cal.com/help/availabilities/team-availability
How to view your teams availability schedules
**Switching between views**
Paid subscribers have two availability profiles: their personal availability and the team availability. Personal availability schedules can be accessed by clicking on the "My Availability" tab.
If you want to switch to team view, simply click on the tab marked team availability.
From within this area, you can create, delete, and edit team availability schedules, as long as you're an account admin or owner.
**To create a new team availability schedule, simply follow the steps below:**
1. Click the "+ New" button in the upper right-hand side of the screen.
2. This will cause a pop-up window to open.
3. Within this pop-up window is a field labeled "Name."
4. Type the name of your new availability schedule in this field.
5. Next, click on the "Continue" button.
6. Your availability schedule has been created, and you will now be redirected to the settings page where there are additional customization options.
These customization options include things like the days and hours of operation, as well as the timezone that the availability schedule is located within. This is also the area where you can add custom date overrides or choose to make this availability schedule the default one all team events automatically reference.
Once you have finished making all of your changes, just click the save button located in the upper right-hand corner of the screen to save your hard work.
**Learn more about:**
* [Date Overrides](https://cal.com/help/availabilities/date-overrides)
* [Multiple Schedules](https://cal.com/help/availabilities/multiple-schedules)
* [Multiple Slots](https://cal.com/help/availabilities/multiple-slots)
* [Add New Availability](https://cal.com/help/availabilities/add-new-availability)
* [Edit Availability](https://cal.com/help/availabilities/edit-availability)
# Credit System
Source: https://cal.com/help/billing-and-usage/messaging-credits
At Cal.com, you can send SMS and WhatsApp messages, as well as use our AI-powered phone agent, cal.ai, to keep attendees informed about bookings, reminders, and cancellations. While these messages can be funded through various methods (e.g., organization-level billing), credits are one of the available ways to manage usage—especially for teams and smaller accounts.
***
## Overview of Credits
Credits are used **as a flexible payment method** to send:
* **SMS messages** (booking confirmations, reminders, updates)
* **WhatsApp messages** (booking alerts, confirmations)
* \*\*Use [****Cal.ai****](https://cal.com/ai) \*\*(AI-powered phone agent)
While many organization-level accounts may fund messaging centrally or directly via integrations like Twilio, **credits serve as a prepaid way to power messaging**, especially on smaller plans.
***
## Credit Allocation by Plan Type
The number of messaging credits available to your account depends on your plan type:
### **Enterprise plans**
* **Unlimited SMS, WhatsApp, and Cal.ai credits**
* Enterprise organizations are not charged for messaging credits and never run out
* The billing page displays an "Unlimited" badge instead of a numerical balance, and the buy-credits action is hidden
### **Platform organizations**
* **Unlimited credits**, the same as Enterprise
* Platform organizations (and teams under a platform parent organization) are not charged for credits
### **Organizations (non-Enterprise)**
* **1000 credits per team member per month**
* Messaging costs are typically covered through your organization's billing method
* SMS/Whatsapp sending consumes credits (like on any other plan) and you can purchase more in your **Organization billing settings**.
### Team plan
* **750 credits per team member per month**
* Credits reset at the start of each billing cycle
* You can purchase more credits from **Team Settings** as needed.
### **Free Users**
* **No free credits included**
* You can purchase credits manually from your **Billing Settings**
***
## Behavior When Credit Balance Is Exhausted
* **Low credit alerts**: We'll send email warnings when your balance gets low (all admins are notified for teams)
* **Exhaustion fallback**:
* If credits run out, SMS/WhatsApp messages will **automatically stop**
* Cal.com will **fall back to email delivery only** for affected messages
This ensures bookings still go through, but real-time alerts may be delayed if recipients rely on SMS/WhatsApp.
Enterprise and Platform organizations have unlimited credits and are never subject to low-balance alerts or message fallbacks.
Credits are **not the only way** SMS/WhatsApp are funded — they're just the default mechanism for smaller accounts and teams
***
## Messaging Credits
### Credit-Based Messaging Costs
The cost depends on the recipient's location and the delivery method:
#### 🇺🇸 United States & 🇨🇦 Canada
* **SMS and WhatsApp messages are free on the Teams Plan** in these regions
* Credits are **not deducted**
#### 🌍 Other Countries
* **One credit = \$0.01 USD**
* The total credit cost per message is based on:
* Twilio's **region-specific SMS rates**
* A standard **80% processing fee**
📌 *Example*: If Twilio charges \$0.05 per SMS to India, your effective cost is:
```
0.05 + (0.05 * 0.8) = $0.09 = 9 credits
```
You can check up-to-date Twilio pricing here: [Twilio SMS Pricing](https://www.twilio.com/sms/pricing)
### Segment-Based Billing
Credits are charged **per segment**, not per message. Most SMS messages are broken into segments based on character count:
* **Standard segment**: up to **160 characters**
* **Messages with emojis or special characters**: up to **70 characters per segment**
Each segment is treated as a separate message, and credits are then calculated based on the information above.
📎 *Want to check how many segments your message will use?*\
Use [Twilio’s Segment Calculator](https://www.twilio.com/en-us/blog/what-the-heck-is-a-segment-html) to estimate credit usage before sending.
## Cal.ai
Cal.ai pricing is based on credits, with each call consuming a set number of credits based on its length. The cost is 29 credits per minute, which equals \$0.29 per minute.
## AI agent credits
Credits can also be consumed by AI agent interactions through the Cal.com platform API. When you build or use AI agents that integrate with Cal.com, each completed interaction charges credits against your balance.
### How AI agent credits work
* AI agent usage is tracked as a separate credit usage type (`AI_AGENT`) alongside SMS and Cal.ai phone calls
* Credits are deducted from your monthly allocation or purchased balance, following the same priority as other credit types
# Seat billing
Source: https://cal.com/help/billing-and-usage/seat-billing
Understand how seat-based billing works for teams and organizations on Cal.com.
Cal.com bills teams and organizations based on the number of seats used during each billing period. Depending on your plan, you may see one of two billing models in your billing settings: **high water mark billing** or **active user billing**.
## High water mark billing
With high water mark (HWM) billing, you are billed for the **peak number of team members** at any point during your billing cycle — not just the count at the end of the month.
For example, if your team starts the month with 10 members, grows to 15 mid-month, then drops back to 12, you are billed for 15 seats that month.
### What you see in billing settings
When HWM billing is active, the **Seat billing** section appears on your team or organization billing page. It shows:
* **Current members** — the number of members on your team right now
* **Peak seats this period** — the highest member count recorded since the billing period started
* **Billed seats** — the number of seats you are charged for (the higher of current members or peak seats, with a minimum of 1)
The billing period start date is displayed so you can see when the current tracking window began.
## Active user billing
With active user billing, you are billed based on how many team members were **actively involved in bookings** during the billing period — either as a host or an attendee.
### What you see in billing settings
When active user billing is enabled, the **Active users** section appears on your billing page. It shows:
* **Total members** — everyone on your team
* **Active users** — the number of members who hosted or attended at least one booking during the period
* **Minimum seats commitment** — if your plan includes a minimum seat commitment, it appears here
* **Billed seats** — the higher of your active user count or minimum seat commitment
You can also see a table listing each active user, their email, and whether they were active as a **host** or **attendee**. Selecting a user shows their bookings for the period.
## Viewing your seat billing details
Navigate to your **Team Settings** or **Organization Settings** and select **Billing**.
Scroll to the **Seat billing** or **Active users** section (depending on your billing model) to see your current usage and billed seats.
Select **Billing portal** to open Stripe, where you can update your payment method, view invoices, or make changes to your subscription.
Seat billing details only appear for teams and organizations on a paid plan. If you are on a free or trial plan, this section is not shown.
## How seat changes are tracked
Every time a member is added to or removed from your team, Cal.com logs the change. For high water mark billing, the system automatically checks whether the new member count exceeds the previous peak. If it does, the peak is updated. This ensures billing reflects the maximum number of seats used at any point in the period.
Seat tracking resets at the start of each billing cycle.
# Booking Page Analytics
Source: https://cal.com/help/bookings/analytics
## How third-party analytics integrations work
Most third-party analytics apps available on Cal.com (like Google Analytics or Meta Pixel) work by injecting a JavaScript tracking snippet onto your public booking pages.
These apps simply inject the JS snippet provided by the third party onto the booking pages, with the Tracking ID configured in cal.com.
## Limitations of direct analytics integrations
We don't send any booking related events(like `bookingSucccessfulV2`) to any analytics app, except GTM, at the moment. So, events like `bookingSuccessfulV2` and other similar events aren't available to any analytics apps by default.
## Using GTM for robust event tracking
The only way to send booking related events to any analytics app(like Google Analytics/Meta) at the moment is to install GTM app and configure GTM(in GTM app itself) to listen to the events that we send to GTM and send to any analytics app from there.
The process is:
1. Connect the Google Tag Manager app in your Cal.com account.
2. In your GTM account, create triggers to listen for custom events pushed by Cal.com.
3. Create tags in GTM that fire on these triggers and send the data to your chosen analytics platform(s).
### Example: Setting up GA4 tracking for new bookings
A community member has written an excellent, detailed guide on how to set up event tracking in Google Analytics 4 for new Cal.com bookings using GTM. We highly recommend this guide. This article seem to very well document the entire GTM and GA4 setup well and we should have an article of our own for this.
**External guide:** [Set up GA4 event for Cal.com booking confirmation](https://www.garrettdigital.com/set-ga4-event-cal-com-booking-confirmation/)
The guide covers:
* Finding your GTM ID and adding it to Cal.com.
* Using GTM's preview mode to see the events from Cal.com.
* Creating a trigger in GTM for the `bookingSuccessfulV2` event.
* Configuring a GA4 event tag to send the booking data to Google Analytics 4.
By following a similar process, you can send your booking data wherever you need it.
Further Reading:
* [Exhaustive list of events we send to GTM](/help/embedding/embed-events)
# Reschedule with busy slot indicators
Source: https://cal.com/help/bookings/host-reschedule-busy-slots
When hosts reschedule their own bookings, they can see which time slots are busy or free using color-coded indicators.
When you reschedule one of your own bookings, Cal.com shows all available time slots — including ones that overlap with your existing calendar events. Each slot displays a color-coded dot so you can make an informed decision:
* **Green dot** — the slot is free on your calendar
* **Red dot** — the slot conflicts with an existing event
This means you can still choose a busy slot if needed, for example when you want to double-book intentionally or when you know the conflicting event will be cancelled.
### How it works
1. Open a booking from your **Bookings** page and click **Reschedule**.
2. On the rescheduling page, time slots appear with dot indicators next to each time.
3. Green dots indicate free slots. Red dots indicate slots that overlap with events on your connected calendars.
4. Select any slot — busy or free — to reschedule the booking.
### Things to know
* **Hosts only.** Guests do not see busy slot indicators when they reschedule. Slots that conflict with the host's calendar are hidden from guests as usual.
* **Personal event types.** On personal (non-team) event types, all of your time slots are shown when you reschedule, even those that would normally be blocked. This gives you full flexibility to move a booking to any time within your availability window.
* **Team event types.** On collective or round-robin event types, your busy slot indicators still appear, but other team members' availability is still respected. You cannot override another host's calendar conflicts.
* **Calendar data.** The indicators reflect events from all calendars you have connected to Cal.com, including external calendars like Google Calendar or Outlook.
# Insights dashboard
Source: https://cal.com/help/bookings/insights
View booking analytics, track trends, and monitor team performance with the Insights dashboard.
The [Insights dashboard](https://app.cal.com/insights) gives you an overview of your booking activity. You can track how many events are created, completed, cancelled, or rescheduled over time, and review team performance metrics like ratings and no-show rates.
## Key metrics
The dashboard shows two groups of key performance indicators (KPIs):
* **Events** — total events, completed events, rescheduled events, and cancelled events.
* **Performance** — average rating, host no-show rate, guest no-show rate, and CSAT score.
Each metric includes a comparison to the previous period so you can spot changes at a glance.
## Date range filter
Use the date picker at the top right of the dashboard to control which time period you are viewing. You can choose from preset ranges or set a custom date range.
### Preset options
| Preset | Description |
| ------------- | ----------------------------------- |
| Today | Current day only |
| Last 7 days | Previous seven days |
| Last 30 days | Previous thirty days |
| Last 90 days | Previous ninety days |
| Month to date | Start of the current month to today |
| Year to date | Start of the current year to today |
| Next 7 days | Today through the next six days |
| Custom | Pick your own start and end dates |
Hover over the date filter to see a tooltip showing the exact date range and timezone being used.
### Choosing a date target
Inside the date picker, you can also choose which date the filter applies to:
* **Booking time** — filters by when the booking is scheduled to happen (the event start time). This is the default.
* **Created at** — filters by when the booking was originally created.
When you select a future date range like "Next 7 days", the date target automatically switches to "Booking time" since filtering future bookings by creation date would not be useful.
## Viewing upcoming bookings
Select the **Next 7 days** preset to see a forward-looking view of your scheduled bookings. When a future date range is active, the dashboard adapts to show only the metrics that are relevant:
* The first KPI card changes from "Total events" to **Events scheduled**, which counts only confirmed bookings (excluding cancelled and rejected ones).
* The **Events completed** KPI is hidden since those events haven't happened yet.
* The **Performance** section (ratings, no-shows, and CSAT) is hidden.
* The **Event trends** chart only shows Created, Rescheduled, and Cancelled lines — Completed, No-Show (Host), and No-Show (Guest) are removed.
* Tables for most/least completed members, no-show hosts, no-show guests, ratings, and recent feedback are hidden.
This gives you a clean view focused on what's coming up rather than past performance.
## Additional charts and tables
Below the KPI cards, the dashboard includes:
* **Event trends** — a line chart showing daily booking volumes broken down by status.
* **Average event duration** — how long your events typically last.
* **No-show hosts over time** and **CSAT over time** — trend charts for team performance.
* **Popular events** — your most frequently booked event types.
* **Most/least booked team members** — see who has the highest and lowest booking volume.
* **Most/least completed team members** — track completion rates across your team.
* **Cancellation and no-show tables** — identify patterns in cancellations and missed meetings.
* **Rating and feedback tables** — review member ratings and recent feedback.
## Filters
In addition to the date range, you can filter Insights by:
* **Team** — view data for a specific team or across the entire organization.
* **Member** — drill down to an individual team member.
* **Event type** — focus on a specific event type.
Use the **Download** button to export the current view as a CSV file.
# Mark guests as no show
Source: https://cal.com/help/bookings/no-show
You can now mark guests as "No Show" for past bookings where one or more attendees did not attend.
### How to Mark Attendees as No-Show
1. **Navigate to Past Bookings**
* Go to `bookings/past`. By default, past bookings show the last 7 days. Use the date range filter to change the window.
2. **Select the Attendee**
* Click on the name or email of the attendee you wish to mark as "No-Show"
3. **Mark as No-Show**
* From the dropdown menu, select "Mark as No Show"
4. **Unmark if Necessary**
* If you marked an attendee as "No-Show" by mistake, you can easily undo it
* Click on the name or email of the attendee again and select "Unmark as No Show"
### Handling Attendees grouped in 'n' more
For meetings with more than two attendees:
1. **Open the Checklist**
* Click on "& n more" attendees. This will open a checklist
2. **Mark/Unmark Multiple Attendees**
* Use the checklist to mark or unmark multiple guests as "No Show" simultaneously
This feature allows you to accurately record attendance and manage your bookings more effectively.
# Paid Bookings
Source: https://cal.com/help/bookings/paid-bookings
With Cal.com you can monetize your bookings. We offer the best platform to ensure appointment scheduling and payment collection is an effortless process.
From RSVPs to coaching and consultancy sessions, Cal.com makes it easy to get paid before your meeting even starts. Enable our stripe app, and decide which of your bookable events have charges and exactly how much those are.
To learn more about the set up process of paid bookings, please take a look at **[How to set up an event type to receive payments](https://cal.com/help/event-types/how-to-receive-payments)**
# Past bookings date filter
Source: https://cal.com/help/bookings/past-bookings-filtering
When you view past bookings, a default 7-day date range filter is applied automatically to help you find recent bookings faster.
When you navigate to the **Past** tab in your bookings, Cal.com automatically applies a **Last 7 days** date range filter. This means you immediately see your most recent past bookings without needing to scroll through months of history.
The filter appears as a pill at the top of the bookings list, showing the active date range.
## How it works
* **Automatic filter:** When you click the **Past** tab, a "Last 7 days" filter is applied by default.
* **Filter pill:** A visible filter pill appears at the top of the list so you always know what date range you are viewing.
* **Tab-specific:** The date range filter only applies to the Past tab. It does not carry over when you switch to the Upcoming, Recurring, Cancelled, or Unconfirmed tabs.
## Changing the date range
You can adjust the date range to see older bookings:
1. Click the date range filter pill at the top of the bookings list.
2. Choose from one of the preset options:
* **Today**
* **Last 7 days** (default)
* **Last 30 days**
* **Last 90 days**
* **Month to date**
* **Year to date**
* **Custom** — pick your own start and end dates
3. The bookings list updates to show bookings within the selected range.
## Removing the filter
If you want to remove the date range filter and see all past bookings, click the **x** on the filter pill. The filter resets to the default 7-day range the next time you navigate back to the Past tab.
# Pre-fill fields/questions
Source: https://cal.com/help/bookings/prefill-fields
You can pre-fill all the fields/questions on the booking form by using their corresponding **identifiers** that you can see under Advanced -> Booking Questions.
e.g. for the following field(shown in screenshot), the field would show up as *Agree with your rules* and its identifier is *agreed*. So, we would use
[](https://downloads.intercomcdn.com/i/o/1198198797/bfc5b45f2c0ac0a6704f1a40/i1600x899-lK5qA-PWor5w_nda2mw.png?expires=1736325000\&signature=000158c0966e05bb5d50ed593b6a94d04c908568625cc3d18d9a68541f449da6\&req=dSEuHsh3lYZWXvMW1HO4zR%2BTJg3Fl6l4ywMHZCHu9egE5fWqiRo4u%2BWPHXxD%0AfGr0JKz%2B%2BGcs7dmJJh4%3D%0A)
*agreed* as query param name to prefill the field.
This can include the user’s name and email, notes, guests, event location, Reason for reschedule. You can prefill any field added by you as well.
You can add anywhere in the booking flow before the booking form page or in the booking form page itself. Simply add these in the URL and you're good to go!
Pre-filling booking fields can save a lot of time and speed up processes with filling out these forms, and assist with a smooth integration with your existing website or app.
An example URL with a few prefill fields is given below:
`https://cal.com/johndoe/book?type=12345&duration=30&email=johndoe%40example.com¬es=Test+Notes`
You can integrate the prefill-fields with your booking page URL in a similar way.
## Pre-filling all fields
**A sample booking form with various fields prefilled.**
[](https://downloads.intercomcdn.com/i/o/1198198793/7bc4b1b4b584d4824880d5da/i1600x899--qO8QnRKDrjU_kyp2hw.png?expires=1736325000\&signature=10a3362b2faab0ec78c8e2ffa1bbb1fc5f7b9dab0e15298152e335f3661ea6cd\&req=dSEuHsh3lYZWWvMW1HO4za%2ByuRsspnytuNu0%2FFrf6odTakjQnLnHIsBeeJvQ%0ANsCB4u65V8zAB1DolSA%3D%0A)
**Here is how the fields are setup**
[](https://downloads.intercomcdn.com/i/o/1198198798/d0baeba0d2e0e4f3161075ec/i1600x899-0PXSUpvs2z-W_wox48k.png?expires=1736325000\&signature=89f6fde016650f907ef3e033088a45ad16657821dd3941e78ed62ee264b9b714\&req=dSEuHsh3lYZWUfMW1HO4zb4YAwmw7asrMlnecn80g7UbIo4WLX9UdTxHu0J3%0AQjwXhXtQ6eI%2BWusGR%2BY%3D%0A)
Here is the query used to prefill that form above.
```
name=John Doe&email=johndoe@example.com¬es=Test Notes&Text=TEXT&number=123&select=Option 1&Multiselect=Option 1&Multiselect=Option 2&guests=b&phone=+91&agreed=true
```
## Fields with multiple values
For questions that accept multiple values, you can pass them multiple times using same identifier. So, e.g. Multiselect has been passed twice and thus it prefills both the values.
Similarly, you can pass *guests* twice to add one more guest.
## Prefilling location
Different type of locations are selected using different values of location. location param value has to be a valid JSON.
## Pre-filling Attendee Address
```
...other-params...&location={"value":"attendeeInPerson","optionValue":"Delhi"}
```
[](https://downloads.intercomcdn.com/i/o/1198198795/149eb8a19c7c9b87e9207cda/i1600x899-Ty_oorQmXnjJ_cm5ysq.png?expires=1736325000\&signature=b5595771bfc49d36da0b4e67f8440a2c5c874c674c799c6d9023b1593c5fc465\&req=dSEuHsh3lYZWXPMW1HO4zXIZpSF682jQ431%2F0%2B57t2z4o8aUSXcM9w0n8f8e%0Aa5feONJm%2FqwDk3Nxf5g%3D%0A)
## Pre-selecting Organizer Address in Location
```
...other-params...&location={"value":"inPerson","optionValue":""}
```
Note: `optionValue` will remain empty string for Organizer Address.
If there are multiple organizer addresses(say NYC, London, Paris), then the corresponding prefill codes will be
`location={"value":"NYC","optionValue":""}`
`location={"value":"London","optionValue":""}`
`location={"value":"Paris","optionValue":""}`
[](https://downloads.intercomcdn.com/i/o/1198198794/4983c503a9ce5201e0c1bba8/i1600x899-AlmOt5E4diMC_nkjeb4.png?expires=1736325000\&signature=4d46fb2749e119580fab04853978f7338ae1b49f7b47c27bcc0e1496745ad183\&req=dSEuHsh3lYZWXfMW1HO4zfhh%2BpZqpU47epa9VDhCuWvhAe0fXXhWclcsJTld%0AHrJR7dP6os%2FtnThVdsI%3D%0A)
## Pre-filling Attendee Phone - When chosen as one of the locations
When Attendee Phone is chosen as one of the locations as shown in the screenshot below, you can prefill the phone number by using the `location` param.
```
...other-params...&location={"value":"phone","optionValue":"%2B919999999999"}
```
*Note: %2B is encoded form of +*
[](https://downloads.intercomcdn.com/i/o/1198198790/02943b0276723d5effc1ed0b/i1600x899-wVkiblWj8CDH_iwhwrd.png?expires=1736325000\&signature=1244214d7c9fcfd16b6edc4b71a4267c3a0bf9c4ad5c91a93ee447cd65c1b3f9\&req=dSEuHsh3lYZWWfMW1HO4zQf94cG%2FKVtkygk%2BlF1g7HiXVwSfutAPEbSq%2B3Jv%0A3p3Pf5Mj3PVQ%2F3avvp8%3D%0A)
## Pre-filling Attendee Phone - When used as a separate booking question
Another way to ask for the attendee phone number is to toggle on the "Phone number" question in the Advanced -> Booking questions section. In that case, the correct approach to prefill the phone number is to use the `attendeePhoneNumber` param.
```
...other-params...&attendeePhoneNumber=%2B919999999999
```
## Pre-selecting Link Meeting
```
...other-params...&location={"value":"link","optionValue":""}
```
[](https://downloads.intercomcdn.com/i/o/1198198791/0db8619aabbf65a0fa3709fd/i1600x899-sGCDXGlvVYT4_uwhpa8.png?expires=1736325000\&signature=c48817776ddbbe02a9df71b8a9e3f44fcd90c48584ead67834eb2e820f3a1bdc\&req=dSEuHsh3lYZWWPMW1HO4zZBGiRHaqpAigQ%2BNxkzSzI7cRhRRKup7Hujf8NW7%0ATAW65srvCSLYe46eo%2BU%3D%0A)
## Pre-selecting Organizer's Default App
For the Organizer's default conferencing app, you can prefill the location using:
```
...other-params...&location={"value":"conferencing", "optionValue": ""}
```
## Pre-selecting a video meeting
Specify location param like this
```
...other-params...&location={"value":"integrations:{VIDEO_APP_IDENTIFIER}","optionValue":""}
```
| **App Name** | **`{VIDEO\_APP\_IDENTIFIER}`** |
| ------------ | ------------------------------ |
| Zoom | zoom |
| Cal Video | daily |
| Office365 | office365\_video |
| Facetime | facetime\_video |
| Campfire | campfire\_video |
| Around Video | around\_video |
| Ping | ping\_video |
| Riverside | riverside\_video |
| Signal | signal\_video |
| Sirius | sirius\_video |
| Telegram | telegram\_video |
| Whatsapp | whatsapp\_video |
| Whereby | whereby\_video |
# UTM Parameter Tracking
Source: https://cal.com/help/bookings/utm-tracking
Cal.com allows you to track UTM parameters on your booking pages to better understand where your bookings are coming from. This helps you measure the effectiveness of your marketing campaigns and traffic sources.
## Automatic UTM Tracking
Cal.com **automatically tracks** the following standard UTM parameters without any additional setup required:
* `utm_source`
* `utm_medium`
* `utm_campaign`
* `utm_term`
* `utm_content`
Simply include these parameters in your booking links, and Cal.com will automatically capture and store them when someone makes a booking.
**Example:**
```
https://cal.com/rick/get-rick-rolled?utm_source=google&utm_medium=cpc&utm_campaign=summer_sale
```
## Manual Tracking for Custom Parameters
If you need to track **custom or non-standard UTM parameters** beyond the five automatically supported ones listed above, you can use the manual hidden booking fields approach. This is a three-step process:
1. Add hidden questions to your booking page for the custom params you want to track
2. Send those params in the booking link
3. View the custom parameters in the booking details page
### Add hidden questions to your booking page
You can follow [booking-questions](/help/event-types/booking-questions) to know how to add a question to the booking page of an event type.
Create a booking question for each of the **custom** UTM params that you want to track (remember, the standard 5 parameters are tracked automatically).
Make sure to toggle the question to "Hidden"
Ensure the following:
1. Input type is "Short Text"
2. Identifier is one of the **custom** UTM params that you want to track (e.g., `utm_content_variant`)
3. Question is toggled to "Hidden"
4. Required is set to "No"
### Send custom params in the booking link
You need to send your custom params in the booking link. When someone books through that link, both the automatic standard UTM parameters and your custom parameters (for which you have added questions) will be captured.
Example with both automatic and custom parameters:
```
https://cal.com/rick/get-rick-rolled?utm_source=google&utm_medium=cpc&utm_campaign=summer_sale&utm_content_variant=content-variant
```
In this example:
* `utm_source`, `utm_medium`, and `utm_campaign` will be **automatically tracked**
* `utm_content_variant` will be captured via your hidden booking questions
## Viewing UTM Parameters
You can view both automatically tracked and manually tracked UTM parameters in the booking details page when you are logged in to your Cal.com account.
**Note:** Only the hosts of the booking will be able to view the UTM parameters and hidden booking questions' answers.
# What is Cal.ai?
Source: https://cal.com/help/cal-ai/cal-ai-help
Cal.ai is an AI-powered scheduling assistant that automates the management of your meetings. It integrates directly with **Cal.com** workflows, allowing you to book, reschedule, cancel, confirm, and follow up on meetings seamlessly. Through phone calls, Cal.ai communicates with participants on your behalf, ensuring your schedule is always up to date, even when you’re unavailable. It works 24/7, handling scheduling tasks automatically without requiring manual intervention.
## How does Cal.ai work and what are the use cases?
Cal.ai is fully integrated into Cal.com workflows. Once configured, it can automatically:
* Confirm meeting details with participants via phone calls
* Book new appointments based on your availability
* Reschedule or cancel existing meetings when needed
* Follow up with participants to ensure meetings are kept
Since Cal.ai operates within Cal.com workflows, any actions taken by the assistant, such as making calls or sending messages, are directly tied to your account's calendar and settings. This ensures seamless synchronization between your meetings and Cal.ai's scheduling tasks.
## Set up a Cal.ai workflow
Setting up a Cal.ai workflow is simple:
1. [Create a Cal.com account](https://app.cal.com/signup) or [log into your existing account](https://app.cal.com/auth/login).
2. Go to the workflows tab ([app.cal.com/workflows](http://app.cal.com/workflows)) and create a new workflow by clicking on ‘+new’.
3. Select a trigger for the workflow (see triggers), select event type, optionally add the time when the trigger has to happen.
4. Add the action: ‘Call attendee using Cal.ai Voice Agent’.
5. Connect a phone number by either buying or importing one.
6. Configure your AI agent by changing the prompt with the initial message and general prompt (you can add variables in the prompt).
7. Test the Cal.ai Agent! You can test the Cal.ai Agent by calling the phone number or by using the ‘Test Web Call’ functionality. Please be aware that both web calls and phone number calls consume credits.
8. Done! Your AI-powered scheduling assistant is now ready to manage your meetings.
## Available triggers
* Before event starts
* When event is canceled
* When new event is booked
* After event ends
* When event is rescheduled
* When booking is rejected
* When booking is requested
* When booking payment is initiated
* When booking payment is successful
* When booking no-show is updated
## Add a phone number to your Cal.ai workflow
You can easily add a phone number by purchasing one or importing an existing number. At first, follow the previous steps on how to set up a Cal.ai workflow. When clicking on ‘Connect Phone Number’ follow the following steps:
### Buying a phone number
You can buy a phone number from Cal.com by following the below steps:
1. Click on ‘Buy’. A pop-up will appear. You can buy a US phone number for \$5 per month. You can only buy US phone numbers. For other countries, you can import your own Twilio phone number. Supported call destinations are: United States, Australia, Spain, Mexico, Japan, Italy, India, Germany, United Kingdom, France, Canada.
2. Click on ‘Buy US number for \$5/month. You’ll get redirected to a checkout page.
3. Pay for the phone number.
4. Done! Your phone number is added to the workflow.
### Importing a (Twilio) phone number
You can import a Twilio phone number by following the below steps:
1. Click on ‘Import’. A pop-up will appear with instructions to import your number.
2. Add your phone number.
3. Add the Termination URI (The termination URI to uniquely identify your elastic SIP trunk. This is used for outbound calls. For Twilio elastic SIP trunks it always ends with .[pstn.twilio.com](https://pstn.twilio.com)).
4. Add advanced settings if needed with the SIP Trunk User Name, SIP Trunk Password and Nickname.
5. Click on ‘Create’ and you’re done!
6. If you have trouble importing your phone number, check this guide: [https://cal.com/help/importing/import-numbers](https://cal.com/help/importing/import-numbers).
For team workflows, only team admins or owners (or admins/owners of the parent organization) can buy, import, update, or remove phone numbers. Members can still use phone numbers that are already connected, but cannot manage them.
## Add/edit a prompt in your [Cal.ai](https://Cal.ai) workflow?
Prompts define the messages Cal.ai uses when interacting with meeting participants. Prompts also make sure how your agent interpret situations and which steps it should follow. There’s a default prompt in every single workflow, however you can edit the prompt to your liking. To edit a prompt follow the steps on how to set up a Cal.ai workflow. Then follow the additional steps:
1. Navigate to prompt settings within your workflow by clicking on the ‘Edit’ button.
2. Add your initial message: The first message the agent will say when starting a call.
3. Add your general prompt: This prompt defines the agent’s role and primary objectives.
4. Add variables to your prompt: Variables allow you to create personalized messages that Cal.ai uses during phone calls, ensuring that each interaction is tailored to your needs. Learn more about the available variables [here](https://cal.com/help/workflows/workflowsoverview#dynamic-text-variables)
5. Click on ‘Save’ and you’re done editing your prompt.
## How does pricing work for Cal.ai? What is the cost per minute?
Cal.ai pricing is based on the number of credits you use. Each call consumes a set number of credits depending on its length and complexity. The charge per minute is 29 credits, equalling \$0.29 per minute.
To learn about pricing for Cal.ai, please check out our [credit system](https://cal.com/help/billing-and-usage/messaging-credits#cal-ai)
# MCP server
Source: https://cal.com/help/cal-ai/mcp-server
Connect AI assistants like Claude, Cursor, and VS Code to your Cal.com account using the MCP server so you can manage your schedule with natural language.
The Cal.com MCP server lets you connect AI assistants to your Cal.com account through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction). Once connected, you can manage bookings, event types, schedules, and more using natural language — directly from your AI tool.
## What you can do
With the MCP server connected, you can ask your AI assistant things like:
* "What bookings do I have this week?"
* "Create a 30-minute event type called Quick Chat"
* "Cancel my meeting with John tomorrow"
* "Show me my available slots for next Monday"
* "Reschedule my 2pm meeting to Thursday at 3pm"
* "What event types do I have?"
The server supports actions across bookings, event types, schedules, availability, conferencing, routing forms, and organization management.
## Connect using the hosted server
The quickest way to get started is the hosted server at `mcp.cal.com`. When you first connect, your AI client walks you through an authorization flow where you grant the server access to your Cal.com account. No API key is needed.
Add the following to your `claude_desktop_config.json`:
* **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
* **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json theme={null}
{
"mcpServers": {
"calcom": {
"url": "https://mcp.cal.com/mcp"
}
}
}
```
Open **Settings → MCP** and add a new server with the URL `https://mcp.cal.com/mcp`, or add it to your `.cursor/mcp.json`:
```json theme={null}
{
"mcpServers": {
"calcom": {
"url": "https://mcp.cal.com/mcp"
}
}
}
```
Add the server to your VS Code MCP settings:
```json theme={null}
{
"mcpServers": {
"calcom": {
"url": "https://mcp.cal.com/mcp"
}
}
}
```
## Connect using a self-hosted server
If you prefer to run the server locally, you can use an API key instead of the OAuth flow. This option requires Node.js 18 or later.
Go to [Settings → Developer → API Keys](https://app.cal.com/settings/developer/api-keys) in your Cal.com dashboard and create a new key.
Add the following to your MCP client's configuration, replacing `cal_live_xxxx` with your actual API key:
```json theme={null}
{
"mcpServers": {
"calcom": {
"command": "npx",
"args": ["@calcom/cal-mcp@latest"],
"env": {
"CAL_API_KEY": "cal_live_xxxx"
}
}
}
}
```
Never share or commit your API key. If it's been exposed, rotate it immediately in your [Cal.com settings](https://app.cal.com/settings/developer/api-keys).
## Available tools
The MCP server provides 34 tools organized by category:
| Tool | Description |
| ----------- | ----------------------------------- |
| `get_me` | Get your authenticated user profile |
| `update_me` | Update your user profile |
| Tool | Description |
| ------------------- | ------------------------------- |
| `get_event_types` | List all event types |
| `get_event_type` | Get a specific event type by ID |
| `create_event_type` | Create a new event type |
| `update_event_type` | Update an event type |
| `delete_event_type` | Delete an event type |
| Tool | Description |
| ----------------------- | ----------------------------------- |
| `get_bookings` | List bookings with optional filters |
| `get_booking` | Get a specific booking by UID |
| `create_booking` | Create a new booking |
| `reschedule_booking` | Reschedule a booking |
| `cancel_booking` | Cancel a booking |
| `confirm_booking` | Confirm a pending booking |
| `mark_booking_absent` | Mark a booking absence |
| `get_booking_attendees` | Get all attendees for a booking |
| `add_booking_attendee` | Add an attendee to a booking |
| `get_booking_attendee` | Get a specific attendee |
| Tool | Description |
| ---------------------- | ----------------------------- |
| `get_schedules` | List all schedules |
| `get_schedule` | Get a specific schedule by ID |
| `create_schedule` | Create a new schedule |
| `update_schedule` | Update a schedule |
| `delete_schedule` | Delete a schedule |
| `get_default_schedule` | Get your default schedule |
| Tool | Description |
| ------------------ | ----------------------------- |
| `get_availability` | Get available time slots |
| `get_busy_times` | Get busy times from calendars |
| Tool | Description |
| ----------------------- | ------------------------------ |
| `get_conferencing_apps` | List conferencing applications |
| Tool | Description |
| ------------------------------ | ---------------------------------------------- |
| `calculate_routing_form_slots` | Calculate slots based on routing form response |
| Tool | Description |
| -------------------------------- | --------------------------------- |
| `get_org_memberships` | Get all organization memberships |
| `create_org_membership` | Create an organization membership |
| `get_org_membership` | Get an organization membership |
| `delete_org_membership` | Delete an organization membership |
| `get_org_routing_forms` | Get organization routing forms |
| `get_org_routing_form_responses` | Get routing form responses |
# Adding embed to your webpage
Source: https://cal.com/help/embedding/adding-embed
You can get the embed snippet, to install on your webpage, from the Embed Snippet Generator, within the app.
The snippets provided are automatically updated as per the cal.com instance. **So, even when self hosting, you
can simply copy and paste the snippets from there**
There are four ways in which you can embed your [Cal.com](http://Cal.com) event type.
## Inline
Show the embed inline anywhere on the webpage. It let's you show the embed at a particular place in your webpage.
[CodeSandbox link\[React\]](https://codesandbox.io/s/inline-demo-react-for-docs-xps99g?file=/src/App.js)
[CodeSandbox link\[HTML\]](https://codesandbox.io/s/vanillajs-week-view-inline-y9wgxc?file=/index.html)
## Pop-up via element click
Show the embed, on click of any element on your webpage, in a popup
[CodeSandbox link\[React\]](https://codesandbox.io/s/element-click-popup-h5c5v2?file=/public/index.html)
[CodeSandbox link\[HTML\]](https://codesandbox.io/s/popup-on-click-of-an-existing-element-framework-agnostic-forked-7pl95c?file=/index.html)
## Floating button pop-up
Adds a floating button that can be customized and on clicking that the embed shows up in a popup.
[CodeSandbox link\[React\]](https://codesandbox.io/s/floating-button-popup-react-forked-9y5g95?file=/public/index.html)
[CodeSandbox link\[HTML\]](https://codesandbox.io/s/embed-floating-button-popup-framework-agnostic-mg7339?file=/src/index.js)
## What can you embed?
* You can embed your cal.com link for an event type e.g. `rick/get-rick-rolled`. You can get the snippet from the event-type page.
* You can embed your profile page e.g. rick. For this, you can just update the snippet to replace your cal.com event type link with your username. e.g. `rick/get-rick-rolled => rick`
* You can embed your Routing Form e.g. `forms/YOUR_FORM_ID`. You can get the snippet for that from the Routing Form page.
# Adding slots to your email
Source: https://cal.com/help/embedding/adding-slots
You can add the slots to your email as well using `Email Embed`. When composing an email, this method of embedding streamlines the process, allowing you to effortlessly share available time slots with recipients.
This ensures seamless scheduling and improved communication efficiency.
# Auto-forwarding Query Parameters
Source: https://cal.com/help/embedding/embed-auto-forward-query-params
Learn how to automatically forward query parameters from your page to Cal.com embeds
# Auto-forwarding Query Parameters
Cal.com's embedding solution provides a powerful feature that allows you to automatically forward query parameters from your webpage to the embedded booking page.
## How It Works
When you embed Cal.com on your webpage, any query parameters present in the URL of your page will automatically be forwarded to the embedded Cal.com booking page. By default, this feature is disabled and can be enabled by adding the following code right after the code you get from [Embed Snippet Generator](/help/embedding/embed-snippet-generator).
```html theme={null}
```
### Example
Let's say you have Cal.com embedded on your page with this URL:
```
https://your-website-example.com/book?name=John&email=john@example.com
```
These query parameters (`name` and `email`) will automatically be forwarded to the Cal.com embed, pre-filling the corresponding fields in the booking form.
## Use Cases
1. **Pre-filling User Information**: If your users are already logged into your application, you can automatically pass their information to the booking form.
2. **Tracking Sources**: Add UTM parameters or other tracking information that you want to preserve throughout the booking flow.
When this is embedded on a page with query parameters, they will automatically be forwarded to the Cal.com booking flow.
## Security Consideration
Query parameters are passed as-is, so ensure you're not including sensitive information in your URL parameters
## Framer-specific issue
Framer seems to add the custom HTML (with JS) in an iframe of their own, so Cal.com Embed Snippet isn't able to access the query params of the webpage directly.
So, you can't auto-forward query params in Framer websites at the moment, but you can pass any query param using the prefill config as explained [here](/help/embedding/prefill-booking-form-embed).
You can get the value of query param and pass it to the prefill config as shown below:
```js theme={null}
// For Framer websites, auto-forward of query params is not possible.
// So, we need to get the query param from the parent and pass it to the prefill config.
const queryParams = new URLSearchParams(window.parent.location.search);
const myQueryParamValue = queryParams.get('my-query-param');
Cal("inline", {
elementOrSelector: "#my-cal-inline",
config: {
"layout": "month_view",
'my-query-param': myQueryParamValue
},
calLink: "riley/test",
});
```
# Embed Events
Source: https://cal.com/help/embedding/embed-events
## Listening to Events
You can listen to an event that occurs in embedded cal link as follows. You can think of them as DOM events.
```js theme={null}
```
## Usage
Wrong ❌
Correct ✅
Comments
`Cal.ns.yournamespace.on(...)`
`Cal.ns.yournamespace('on', ...)`
To be used when a namespace is used which you can identify by seeing if "init" call has namespace in it.
The Embed snippet you get from the Cal.com app uses a namespace derived from the event type slug.
`Cal.on(...)`
`Cal('on', ...)`
To be used when namespace is not used which you can identify by seeing if the "init" call has no namespace in it.
`Cal("init", { origin: "https://cal.com" })`
## Event Reference
### `eventTypeSelected`
**Description:** When user chooses an event-type from the listing.
**Properties:**
* `eventType`: `object` - Event Type that has been selected
### `bookingSuccessfulV2`
*`It deprecates bookingSuccessful event.`*
**Description:** When a fresh booking is successfully done. It might not be confirmed.
**Properties:**
* `uid`: `string` | `undefined` - Unique identifier for the booking
* `title`: `string` | `undefined` - Title of the booking
* `startTime`: `string` | `undefined` - Start time of the booking
* `endTime`: `string` | `undefined` - End time of the booking
* `eventTypeId`: `number` | `null` | `undefined` - Event type id of the booking
* `status`: `string` | `undefined` - Status of the booking
* `paymentRequired`: `boolean` - Whether payment is required for the booking
* `isRecurring`: `boolean` - Whether the booking is recurring
* `allBookings`: `object` - Array of objects with `startTime` and `endTime`. Applicable only if `isRecurring` is `true`
* `videoCallUrl`: `string` - URL of the video call
### `rescheduleBookingSuccessfulV2`
*`It deprecates rescheduleBookingSuccessful event.`*
**Description:** When a booking is rescheduled.
**Properties:**
* `uid`: `string` | `undefined` - Unique identifier for the booking
* `title`: `string` | `undefined` - Title of the booking
* `startTime`: `string` | `undefined` - Start time of the booking
* `endTime`: `string` | `undefined` - End time of the booking
* `eventTypeId`: `number` | `null` | `undefined` - Event type id of the booking
* `status`: `string` | `undefined` - Status of the booking
* `paymentRequired`: `boolean` - Whether payment is required for the booking
* `isRecurring`: `boolean` - Whether the booking is recurring
* `allBookings`: `object` - Array of objects with `startTime` and `endTime`. Applicable only if `isRecurring` is `true`
### `linkReady`
**Description:** Tells that the link is ready to be shown now.
**Properties:** None
### `linkFailed`
**Description:** Fired if link fails to load.
**Properties:**
* `code`: `string` - Error Code
* `msg`: `string` - Human Readable msg
* `data`: `object` - More details to debug the error (includes url)
### `dryRunBookingSuccessfulV2`
**Description:** When a dry run booking is successfully created (test mode).
**Properties:**
Same properties as `bookingSuccessfulV2` (without `uid`)
### `dryRunRescheduleBookingSuccessfulV2`
**Description:** When a dry run reschedule is successful (test mode).
**Properties:**
Same properties as `bookingSuccessfulV2` (without `uid`)
### `bookingCancelled`
**Description:** When a booking is cancelled.
**Properties:**
* `booking`: `object` - Booking details including cancellationReason
* `organizer`: `object` - Organizer details (name, email, timeZone)
* `eventType`: `object` - Event type details
### `routed`
**Description:** When a routing form routes to an action (event type, external URL, or custom page).
**Properties:**
* `actionType`: `string` - Type of action: "customPageMessage", "externalRedirectUrl", or "eventTypeRedirectUrl"
* `actionValue`: `string` - The value/URL of the action
### `navigatedToBooker`
**Description:** When user navigates to the booker interface.
**Properties:** None
### `bookerViewed`
**Description:** Fires once when the booker becomes visible to the user for the first time. Not fired during prerendering.
**Properties:**
* `eventId`: `number` | `null` - Event type ID (null if slots not loaded)
* `eventSlug`: `string` | `null` - Event type slug (null if slots not loaded)
* `slotsLoaded`: `boolean` - Whether slots are loaded
### `bookerReopened`
**Description:** Fires when the booker is reopened after the modal was closed. Distinguishes between first view and subsequent reopens.
**Properties:**
* `eventId`: `number` | `null` - Event type ID (null if slots not loaded)
* `eventSlug`: `string` | `null` - Event type slug (null if slots not loaded)
* `slotsLoaded`: `boolean` - Whether slots are loaded
### `bookerReloaded`
**Description:** Fires when the booker undergoes a full page reload within the modal.
**Properties:**
* `eventId`: `number` | `null` - Event type ID (null if slots not loaded)
* `eventSlug`: `string` | `null` - Event type slug (null if slots not loaded)
* `slotsLoaded`: `boolean` - Whether slots are loaded
### `bookerReady`
**Description:** Fires when the booker view is loaded and slots are ready for user interaction. Only fires for booker pages (not booking success or other views).
**Properties:**
* `eventId`: `number` - Event type ID
* `eventSlug`: `string` - Event type slug
With GTM App enabled for an Event type, these events are automatically sent to GTM and GTM could be setup to send these events to your desired destination like Google Analytics, etc.
# Embed instructions
Source: https://cal.com/help/embedding/embed-instructions
An instruction is how you configure the embed. These instructions can be added immediately after the embed snippet.
An instruction is technically a function with the same name, that would be called with the given arguments.
You would not normally need to learn about these instructions in detail, as the **Embed Snippet Generator** automatically updates the snippet with these instructions in the way you configure it but still they could be useful.
#### Inline
Appends embed `inline` as the child of the element.
```js theme={null}
```
* `elementOrSelector` - Give it either a valid CSS selector or an HTMLElement instance directly
* `calLink` - Cal Link that you want to embed e.g. john. Just give the username. No need to give the full URL [https://cal.com/john](https://cal.com/john). It makes it easy to configure the calendar host once and use as many links you want with just usernames
#### UI
Configure `ui` for embed. Make it look part of your webpage.
```js theme={null}
```
* `styles` - It supports styling for body and eventTypeListItem. Right now we support just background on these two.
* `hideEventTypeDetails` - When `true`, the event type details card (title, duration, description) is hidden so only the calendar and time slots are shown.
* `showTimezoneWhenEventDetailsHidden` - When `true` and used together with `hideEventTypeDetails: true`, the timezone selector is rendered above the booker. Use this when you have hidden the event type details card but still want bookers to be able to see and change their timezone before picking a slot. Defaults to `false`.
```js theme={null}
```
#### Preload
To open cal link on some action, make it pop open instantly by using `preload`.
```js theme={null}
```
* `calLink` - Cal Link that you want to embed e.g. john. Just give the username. No need to give the full URL [https://cal.com/john](https://cal.com/john)
#### Close modal
Programmatically closes a modal-based embed shown as a pop-up (for example, when opened via an element click or the floating button).
```js theme={null}
```
**Supported embed types:**
* Pop-up via element click
* Floating button pop-up
**Namespaced usage:**
```js theme={null}
```
# Getting Embed Code Snippets
Source: https://cal.com/help/embedding/embed-snippet-generator
You can get code snippets for **React** or **HTML** and also configure many different aspects of embeds using the **Embed Snippet Generator**. The code snippet is automatically updated with the changes you make in it.
Here is how you can access it.
1. Click on three dots of the event type and click on the option `Embed`
2. Configure as you require and then
a. Copy the HTML code snippet
or,
b. Copy the React code snippet
### What can you configure
* Size of embed
* Theme
* Toggle event type details
* Brand color
* Layout
* Floating button text
* Floating button position at the bottom
You can also configure all the custom CSS variables supported by cal.com app. [Here is a list of all the supported CSS variables](https://github.com/calcom/cal.com/blob/main/packages/config/tailwind-preset.js#L18).
Also, [here is the codeSandbox demo](https://codesandbox.io/s/embed-advanced-css-vars-x2sdgy?file=/src/App.tsx) for a configuration where the look and feel of the embed is changed.
# Prefill booking form in Embed
Source: https://cal.com/help/embedding/prefill-booking-form-embed
Booking form inside an embed can be prefilled as well.
## Inline Embed
```js theme={null}
// Prefill Name, Email, Attendee Address and passing metadata - React.
// You can specify config property to do prefilling
// React Demo Link - https://codesandbox.io/s/react-prefill-attendee-address-email-sqhf7r
```
```js theme={null}
// Prefill Name, Email, Attendee Address and passing metadata - Vanilla JS
// You can use 'inline' instruction to do the prefill
// VanillaJS Demo link - https://codesandbox.io/s/prefill-embed-fields-vanilla-js-zft44w?file=/index.html
Cal("inline", {
config: {
name: "Name",
email: "booker@example.org",
// You will receive the value in payload.metadata["myKey"] in webhook.
// Also, it would be stored in booking table under metadata column
// It won't be shown on the booking details page.
"metadata[myKey]": "myValue",
location: JSON.stringify({
value: "attendeeInPerson",
// It can be any string that defines an address where the meeting would occur
optionValue: "New York"
})
}
});
```
```js theme={null}
// Prefill Name, Email, Attendee Phonenumber and passing metadata - React
```
```js theme={null}
// Prefill Name, Email and Attendee Phone - Vanilla JS
// You can use 'inline' instruction to do the prefill
Cal("inline", {
config: {
name: "Name",
email: "booker@example.org",
location: JSON.stringify({
value: "phone",
// Any valid phonenumber in here
optionValue: "+919999999999"
})
}
});
```
## Floating button popup
```js theme={null}
// Prefill Name, Email, Attendee Phone and passing metadata - Vanilla JS
// You can use 'floatingButton' instruction to do the prefill
// This is common for React and VanillaJS embeds.
// Note that for React, Cal is not Cal component here it is Cal API.
Cal("floatingButton", {
config: {
name: "Name",
email: "booker@example.org",
// You will receive the value in payload.metadata["myKey"] in webhook.
// Also, it would be stored in booking table under metadata column
// It won't be shown on the booking details page.
"metadata[myKey]": "myValue",
location: JSON.stringify({
value: "phone",
// Any valid phonenumber in here
optionValue: "+919999999999"
})
}
});
```
Other location types and other fields can be prefilled in the similar way. You can find the correct value to give from [here](https://cal.com/docs/core-features/bookings/prefill-fields#fields-with-multiple-values)
# UTM Parameter Tracking in Embeds
Source: https://cal.com/help/embedding/utm-tracking-embed
Cal.com allows you to track UTM parameters on your embedded booking pages to better understand where your bookings are coming from. This helps you measure the effectiveness of your marketing campaigns and traffic sources when using Cal.com embeds.
This guide assumes you have already set up UTM tracking questions as described in the [UTM Parameter Tracking](/help/bookings/utm-tracking) guide. If you haven't done that yet, please follow that guide first to set up your UTM tracking questions.
For embedded calendars, you'll need to modify your embed code to pass the UTM parameters. There are two ways to achieve this:
## Option 1: Using embed `config` to pass UTM parameters
Add data attributes to your embed element for each UTM parameter you want to track:
Depending on the type of embed you are using, you do it in following ways.
a. Element Click type embed:
```html theme={null}
```
b. Inline embed:
```html theme={null}
```
c. Floating pop-up button embed:
```html theme={null}
```
In all cases ensure the following:
1. Make sure to modify the code taken from [Embed Snippet Generator](/help/embedding/embed-snippet-generator) and modify as mentioned below.
2. Make sure to read the UTM parameters yourself from your webpage and pass them in the config. e.g. You could read from the query params as shown below. This would ensure that the parameters like your-website-example.com?utm\_source=source\&utm\_medium=medium\&utm\_campaign=campaign are now passed to the embed.
```html theme={null}
const urlParams = new URLSearchParams(window.location.search);
const utmSource = urlParams.get('utm_source');
const utmMedium = urlParams.get('utm_medium');
const utmCampaign = urlParams.get('utm_campaign');
```
## Option 2: Automatically pass all parameters from the page
You can follow the instructions in [Embed Auto-forwarding Query Parameters](/help/embedding/embed-auto-forward-query-params) to automatically pass all parameters from the page including the UTM parameters.
Once you have enabled this feature, you don't need to pass the UTM parameters in the embed config manually and tracking would work as expected.
#### Security Consideration
Though this is a straightforward implementation, there is a caveat that all parameters from the page are passed to the embed. So, you need to ensure that the parameters you are passing to your webpage are not sensitive and you are fine passing them to the embed.
# Audit logs
Source: https://cal.com/help/enterprise/audit-logs
View a detailed history of booking, routing form, and security events across your organization.
Audit logs give organization admins a complete record of important actions across your organization. This includes a timeline of every change made to bookings and routing forms, as well as security events like email changes and account locks.
Audit logs are included with every Cal.com organization plan and are turned on by default. You must be an organization or team admin to view them.
***
## Booking events
Each booking keeps a history of the following events:
| Event | What it records |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| **Booking created** | When the booking was made, the assigned host, and the time slot |
| **Booking accepted** | When a pending booking was confirmed |
| **Booking rejected** | When a pending booking was declined, including the rejection reason |
| **Booking cancelled** | When a booking was cancelled, including the cancellation reason |
| **Booking rescheduled** | The original and new date/time, with a link to the new booking |
| **Reschedule requested** | When a reschedule was requested, including the reason |
| **Booking reassigned** | When a booking was moved to a different host, the assignment type (manual or round robin), and the previous host |
| **Attendee added** | When new attendees were added to the booking |
| **Location changed** | The previous and new meeting location |
| **No-show updated** | When a host or attendee was marked as a no-show |
| **Seat booked** | When someone booked a seat on a seated event |
| **Seat rescheduled** | When a seat was moved to a different time |
If the booking was created through a routing form, the form submission is also shown in the timeline.
***
## Security events
Cal.com also tracks security-related actions for your organization. These events help admins monitor account activity and maintain compliance.
| Event | What it records |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Email changed** | When a member changes their email address, including the previous and new email |
| **Account locked** | When an admin locks a user account |
| **Account unlocked** | When an admin unlocks a previously locked user account |
| **Login** | When a user signs in, including both successful logins and failed login attempts (for example, wrong password, locked account, or failed two-factor verification) |
| **Password changed** | When a user updates their password |
| **Two-factor enabled** | When a user turns on two-factor authentication |
| **Two-factor disabled** | When a user turns off two-factor authentication |
| **Impersonation started** | When an admin begins impersonating another user |
| **Impersonation stopped** | When an admin stops impersonating another user |
***
## Routing form history
Each routing form keeps a history of every change made to its configuration. This helps organization admins audit who edited a form, when the change happened, and exactly what was updated.
The following changes are recorded:
| Event | What it records |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Form created** | When the form was created, including the initial form name |
| **Form modified** | Any change to the form's name, description, fields, routes, or settings, including before and after values |
| **Form deleted** | When the form was removed |
| **Router-sync change** | When an edit to a router form propagated field changes to a connected form |
Each entry shows the actor who made the change, when it happened, and a structured diff of what was updated — including field additions and renames, route condition changes, and updates to attribute mappings or team members in `sendUpdatesTo`.
### How to view routing form history
Go to **Routing** from the main navigation and open the form you want to review.
In the form editor, open the actions dropdown menu.
Choose **Form history** to open the history sheet and view the timeline of changes.
***
## How to view booking audit logs
Go to **Bookings** from the main navigation.
Click any booking to open the booking details panel.
Select the **History** tab at the top of the panel to view the audit log timeline.
***
## Reading the timeline
The timeline displays events in reverse chronological order (newest first). Each entry shows:
* **Action icon** — a visual indicator of the event type
* **Description** — what happened (for example, "Booking rescheduled from Jan 10 to Jan 15")
* **Who made the change** — the person's name and role (such as guest or attendee)
* **When it happened** — a relative timestamp (for example, "2 hours ago"), with the exact date and time available on hover
You can expand any entry to see additional details, including:
* **Source** — whether the change was made from the web app, an API call, a webhook, or the system
* **Impersonation info** — if someone performed the action on behalf of another user
* **Raw data** — the full event data in JSON format
***
## Filtering audit logs
Two filters are available above the timeline:
* **Search** — filter entries by keyword across action names, actor names, and event details
* **Actor** — filter by the person who made the change using the dropdown menu
***
## Who can access audit logs
Audit log access is controlled by your organization's permission settings. Booking audit logs and routing form history are gated independently, so an admin can grant one without the other.
* **Organization admins and owners** can view audit logs for all bookings, routing forms, and security events in the organization by default.
* **Team admins and owners** can view audit logs for bookings and routing forms owned by their team.
* **Regular members** do not have access to audit logs by default.
To grant a custom role access to routing form history, enable one or both of the following permissions on the role:
* **View team routing form audit logs** — history for forms owned by teams the member belongs to.
* **View organization routing form audit logs** — history for every routing form in the organization.
Both permissions require the base **View routing forms** permission.
If you see a message that a form's history is not available, contact your organization admin to request access.
***
## Frequently asked questions
Audit logs are currently viewable within Cal.com. Export functionality is not available at this time.
Audit logs are recorded from the point your organization was created or the feature became available. Changes made before audit logging was active are not tracked.
Yes, as long as the booking owner is a member of your organization and you have the appropriate admin permissions.
Actions performed automatically by Cal.com (rather than by a specific person) are attributed to "Cal.com" as the actor.
Security events help organization admins monitor sensitive account activity such as email changes, account locks, login attempts (including failed sign-ins), and authentication changes. These events support compliance and security monitoring across your organization.
# Custom SMTP for organizations
Source: https://cal.com/help/enterprise/custom-smtp
Send booking emails from your own domain using a custom SMTP server.
Organizations on Cal.com can configure a custom SMTP server so that booking-related emails (confirmations, reminders, cancellations, and more) are sent from your own domain instead of Cal.com's default email address.
This helps keep your communications on-brand and can improve deliverability for your team's emails.
Custom SMTP is only available for organizations. Individual users and teams cannot configure their own SMTP settings.
***
## How it works
When you set up a custom SMTP configuration, Cal.com routes supported email types through your SMTP server. If your server is temporarily unreachable, Cal.com automatically falls back to its default email service so that no emails are lost.
Each organization can have one SMTP configuration at a time.
***
## Supported email types
Custom SMTP applies to booking-related emails, including:
* **Booking confirmations** — sent to both the attendee and the organizer
* **Cancellations and reschedules** — notifications when bookings change
* **Booking requests** — emails for events that require approval
* **Payment emails** — no-show fee notifications
* **Recording and transcript links** — download links after meetings
* **Workflow emails** — messages triggered by your custom workflows
* **Routing form responses** — emails from routing form submissions
Account-level emails such as password resets or login verifications are not sent through your custom SMTP server.
***
## What you need
Before configuring custom SMTP, have the following details from your email provider:
| Setting | Description | Example |
| --------------------- | -------------------------------------------- | --------------------------- |
| **SMTP host** | Your mail server address | `smtp.yourcompany.com` |
| **SMTP port** | The port your server uses | `465` (SSL) or `587` (TLS) |
| **Username** | The account used to authenticate | `noreply@yourcompany.com` |
| **Password** | The password or app-specific password | — |
| **Secure connection** | Whether the server uses SSL/TLS | Yes for port 465, typically |
| **From email** | The address that appears in the "From" field | `noreply@yourcompany.com` |
| **From name** | The display name next to the email address | `Your Company` |
Make sure your SMTP server allows sending from the "From email" address you configure. If there is a mismatch, emails may fail or be rejected by recipient mail servers.
***
## Set up custom SMTP
To configure custom SMTP for your organization, contact your Cal.com account representative or reach out through the [support portal](https://go.cal.com/support) with your SMTP details. The Cal.com team will enable the feature for your organization.
Once enabled, you can send a test email to confirm that your SMTP configuration is working correctly before it goes live.
***
## Test your configuration
After your SMTP settings are configured, a test email is sent to verify the connection. This test email confirms:
* Your SMTP server is reachable
* Authentication credentials are valid
* Emails can be delivered from the configured "From" address
If the test fails, double-check your SMTP host, port, username, and password with your email provider.
***
## Automatic fallback
If your SMTP server becomes temporarily unavailable, Cal.com automatically retries the email using its default email service. This ensures that booking emails are always delivered, even if there is an issue with your mail server.
***
## Frequently asked questions
No. Custom SMTP is configured at the organization level and applies to all teams and members within the organization.
All emails will be sent from Cal.com's default email address going forward. No previously sent emails are affected.
Cal.com does not require specific DNS changes, but your email provider may require SPF, DKIM, or DMARC records to authorize the sending server. Check with your email provider for their requirements.
Any provider that supports standard SMTP (such as Google Workspace, Microsoft 365, Amazon SES, SendGrid, or Postmark) is compatible.
# Delegation Credential
Source: https://cal.com/help/enterprise/delegation-credential
Automatically connect calendars for every organization member using a single admin-managed credential.
Delegation Credential allows organization admins to connect Google Workspace or Microsoft 365 for all members at once. Instead of each member individually authorizing calendar access, the admin sets up a single credential that acts on behalf of every user whose email matches the configured domain.
***
## Why use Delegation Credential
Without Delegation Credential, every organization member must manually connect their calendar through OAuth. This creates friction during onboarding and means members who haven't completed setup won't have calendar integration.
With Delegation Credential:
* **Calendars are auto-connected** for all members whose email matches the configured domain (Google Calendar for Google Workspace, Outlook Calendar for Microsoft 365)
* **No individual authorization required** — members don't need to go through OAuth
* **New members get instant calendar access** as soon as they're added to the organization
* **Admins maintain central control** over the calendar integration
***
## How it works
1. An organization admin creates a Delegation Credential by providing service account credentials for Google Workspace, or by registering an app for Microsoft 365
2. The admin authorizes the credential in the Google Workspace Admin Console or the Microsoft Entra admin center
3. Once enabled, Cal.com uses the credential to access calendars on behalf of all organization members whose email matches the configured domain
4. Members' availability is automatically checked and new booking events are created in their calendars
***
## Who can manage Delegation Credentials
* **Creating** a Delegation Credential — organization owners and admins only
* **Enabling** a Delegation Credential — organization owners and admins only, and the admin's email must belong to the configured domain
* **Members** cannot disconnect a delegation-managed calendar credential, but they can still connect additional calendars manually
***
## What changes for members
Once a Delegation Credential is enabled:
* The matching calendar is automatically installed — members see it as connected without any action on their part. For Google Workspace this is Google Calendar; for Microsoft 365 this is Outlook Calendar.
* Members can select which calendars to check for conflicts during [onboarding](/help/enterprise/members-onboarding)
* Google Meet is also available as a booking location automatically when using Google Workspace
* Members cannot disconnect the delegation-managed credential
***
## Getting started
Follow the setup guide:
Connect Google Calendar and Google Meet for your organization using a Google Cloud service account.
Connect Outlook Calendar for your organization using a Microsoft Entra ID application.
***
## Disabling a Delegation Credential
Disabling a Delegation Credential:
* Immediately stops auto-connecting calendars for members who haven't manually connected their calendar
* Preserves existing calendar preferences (selected calendars and destination calendar)
* Background jobs clean up delegation-specific records over time
Members who need calendar access after disabling will need to [connect their calendar manually](/help/quick-start/calendar) through the Cal.com app store.
***
## Frequently asked questions
The Delegation Credential takes priority for the matching domain. The member's manual connection is preserved but the delegation-managed credential is used for calendar operations.
No. Members cannot disconnect a delegation-managed calendar credential. However, they can still connect additional calendars from other providers manually.
No. Delegation Credential is an organization-level feature. Only organization owners and admins can create and manage them.
# Delegation Credential — Google Workspace
Source: https://cal.com/help/enterprise/delegation-credential-google-workspace
Connect Google Calendar for all organization members using a single service account.
Delegation Credential lets organization admins connect Google Calendar for every member at once, without each person needing to authorize individually. It uses a Google Cloud service account with domain-wide delegation to read availability and create events on behalf of your organization's users.
Only organization owners and admins can create and enable a Delegation Credential. The admin's email must belong to the Google Workspace domain being configured.
***
## What you need
Before starting, make sure you have:
* **Organization admin access** in Cal.com
* **Google Cloud Console access** for your organization's Google Cloud project
* **Google Workspace Admin Console access** to authorize domain-wide delegation
***
## Step 1: Set up a Google Cloud project
If you already have a Google Cloud project with the Google Calendar API enabled, skip to Step 2.
Go to the [Google Cloud Console](https://console.cloud.google.com/) and select **Create Project**. Give your project a name and click **Create**.
In the Google Cloud Console, go to **API & Services → Library**. Search for **Google Calendar API** and click **Enable**.
***
## Step 2: Create a service account
A service account acts on behalf of your organization's users to access their calendars.
In the Google Cloud Console, go to **IAM & Admin → Service Accounts**.
Click **Create Service Account**. Enter a name and description, then click **Create and Continue**. You can skip the optional steps.
Select your newly created service account, go to the **Keys** tab, click **Add Key → Create new key**, select **JSON**, and download the file. Keep this file safe — you will paste its contents into Cal.com.
***
## Step 3: Create the Delegation Credential in Cal.com
In Cal.com, go to **Settings → Organization → Delegation Credential**.
Click **Add delegation credential**.
* **Domain**: Enter your Google Workspace domain (e.g. `acme.com` if your emails are `@acme.com`)
* **Workspace Platform**: Select **Google Workspace**
* **Service Account Key**: Paste the contents of the JSON key file you downloaded in Step 2
Click **Create**. The credential will be created but not yet enabled.
***
## Step 4: Copy the Client ID and scope
After creating the credential, the list view shows:
* **Client ID** — a numeric identifier (e.g. `123456789012345678901`)
* **Scope** — `https://www.googleapis.com/auth/calendar`
Copy both values using the copy buttons. You will need them in the next step.
***
## Step 5: Authorize in Google Workspace Admin Console
Use the Client ID and scope from Step 4 to authorize domain-wide delegation in your Google Workspace.
Go to [admin.google.com](https://admin.google.com) and sign in with your Google Workspace admin account.
Go to **Security → Access and Data Controls → API Controls → Manage Domain-Wide Delegation**.
Click **Add new** and paste the **Client ID** you copied from Cal.com.
In the **OAuth scopes** field, paste:
```
https://www.googleapis.com/auth/calendar
```
This grants full access to Google Calendar, which Cal.com uses to read availability and create/update events in members' calendars.
Click **Authorize** to save.
***
## Step 6: Enable the Delegation Credential
Go back to **Settings → Organization → Delegation Credential**.
Toggle the credential to **Enabled**. Cal.com will verify that the Client ID has been authorized in your Google Workspace. If the verification succeeds, the credential becomes active.
The admin enabling the credential must have an email address that belongs to the configured Google Workspace domain, and that email must be verified in Cal.com.
***
## What happens after enabling
Once the Delegation Credential is enabled:
* **Google Calendar is auto-connected** for all organization members whose email matches the configured domain — they do not need to connect it manually
* **Google Meet is available as a location** for booking events, even if members haven't completed [onboarding](/help/enterprise/members-onboarding)
* **New members** added to the organization automatically get Google Calendar connected
* Members **cannot disconnect** the delegation-managed Google Calendar credential (they can still connect additional calendars manually)
***
## Disabling the Delegation Credential
Disabling a Delegation Credential:
* Immediately stops auto-connecting calendars for members who haven't manually connected Google Calendar
* Preserves existing calendar preferences (selected calendars and destination calendar) for members who had them configured
* Background jobs will clean up delegation-specific credential records over time
***
## Frequently asked questions
No. Google Calendar is automatically connected for all members whose email matches the domain. Members can optionally complete [onboarding](/help/enterprise/members-onboarding) to select which calendars to check for conflicts.
The Delegation Credential takes priority for the matching domain. The member's manual connection is preserved but the delegation-managed credential is used for calendar operations.
The service account only has access to the Google Calendar API scope (`https://www.googleapis.com/auth/calendar`). It can read availability and create/update calendar events for members in the configured domain.
# Delegation Credential — Microsoft 365
Source: https://cal.com/help/enterprise/delegation-credential-microsoft-365
Connect Microsoft 365 calendars for all organization members using a single Microsoft Entra ID application.
Delegation Credential lets organization admins connect Microsoft 365 (Outlook) calendars for every member at once, without each person needing to authorize individually. It uses a Microsoft Entra ID (formerly Azure AD) application with admin-granted permissions to read availability and create events on behalf of your organization's users.
Only organization owners and admins can create and enable a Delegation Credential. The admin's email must belong to the Microsoft 365 domain being configured.
***
## What you need
Before starting, make sure you have:
* **Organization admin access** in Cal.com
* **Microsoft Entra admin access** to register an application and grant admin consent
* **A Microsoft 365 tenant** with the domain you want to configure
***
## Step 1: Register an application in Microsoft Entra ID
Go to [entra.microsoft.com](https://entra.microsoft.com) and sign in with your Microsoft 365 admin account.
Go to **Identity → Applications → App registrations** and click **New registration**. Give your application a name (for example, `Cal.com Delegation Credential`).
Select **Accounts in this organizational directory only (single tenant)**. You don't need to add a redirect URI for this flow.
Click **Register**. You'll land on the application's overview page, which shows the **Application (client) ID** and **Directory (tenant) ID**. Keep this page open — you'll need both values shortly.
***
## Step 2: Add API permissions
The application needs two Microsoft Graph **application permissions** so Cal.com can read and write calendars and resolve users by email. A third permission, `Application.ReadWrite.OwnedBy`, is only required if you want Cal.com to rotate the client secret automatically before it expires.
| Permission | Why Cal.com needs it |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Calendars.ReadWrite` | Read availability and create or update calendar events for members in the tenant. |
| `User.Read.All` | Resolve the Microsoft 365 user for a Cal.com member by their email address. |
| `Application.ReadWrite.OwnedBy` | Automatically rotate the client secret on the app registration Cal.com owns, before it expires. Also requires [making the application an owner of itself](#make-the-application-an-owner-of-itself). **Not required** if you [opt out of automatic secret rotation](#client-secret-rotation) and manage rotation manually. |
From your application page, go to **API permissions** and click **Add a permission**.
Choose **Microsoft Graph**, then **Application permissions** (not delegated).
Search for and add:
* `Calendars.ReadWrite`
* `User.Read.All`
* `Application.ReadWrite.OwnedBy` — skip this one if you plan to [opt out of automatic secret rotation](#client-secret-rotation); if you keep it, also complete [Make the application an owner of itself](#make-the-application-an-owner-of-itself) below
Back on the API permissions page, click **Grant admin consent for \** and confirm. The status column should show a green check mark next to each permission you added.
Without admin consent, Cal.com cannot use the application to access calendars. Make sure the permissions you added show **Granted** before continuing.
### Make the application an owner of itself
Only needed if you want automatic secret rotation. `Application.ReadWrite.OwnedBy` lets the application manage app registrations it **owns**, so granting the permission is not enough on its own — the application's own service principal has to be added as an owner of its app registration. Skipping this is the most common reason rotation looks configured but keeps failing.
The portal's **Owners** blade only accepts users, so add the ownership with the [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli), using two different object IDs:
| Value | Where to find it |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| App registration **Object ID** | **App registrations → your app → Overview → Object ID**. This is *not* the Application (client) ID. |
| Service principal **Object ID** | **Enterprise applications → the same app → Overview → Object ID**. A different value from the app registration's Object ID. |
```bash theme={null}
az login --tenant --allow-no-subscriptions
az ad app owner add \
--id \
--owner-object-id
# verify the service principal now shows up as an owner
az ad app owner list --id --query "[].id"
```
This step needs a work or school (Entra ID) tenant — Microsoft Graph rejects it for personal/consumer Microsoft accounts.
***
## Step 3: Create a client secret
From your application page, go to **Certificates & secrets** and click **New client secret**.
Add a description (for example, `Cal.com DWD`) and choose an expiration period that suits your security policy.
Click **Add**, then immediately copy the **Value** column — not the Secret ID. You won't be able to view this value again after you leave the page.
Cal.com creates its own replacement secrets with a **180-day** lifetime. If your tenant has an app management policy that caps client secret lifetimes below 180 days, Microsoft rejects every rotation attempt — exempt this app registration from the policy, raise the cap to at least 180 days, or [opt out of automatic secret rotation](#client-secret-rotation) and rotate manually.
***
## Step 4: Create the Delegation Credential in Cal.com
In Cal.com, go to **Settings → Organization → Delegation Credential**.
Click **Add delegation credential**.
* **Domain**: Enter your Microsoft 365 domain (for example, `acme.com` if your emails are `@acme.com`)
* **Workspace Platform**: Select **Microsoft 365**
* **Client ID**: Paste the **Application (client) ID** from Step 1
* **Tenant ID**: Paste the **Directory (tenant) ID** from Step 1
* **Client Secret**: Paste the secret **Value** you copied in Step 3
Click **Create**. The credential will be created but not yet enabled.
***
## Step 5: Enable the Delegation Credential
On the Delegation Credential list, toggle the new credential to **Enabled**. Cal.com verifies that the application can authenticate against your tenant and access calendars before the credential becomes active.
The admin enabling the credential must have an email address that belongs to the configured Microsoft 365 domain, and that email must be verified in Cal.com.
***
## What happens after enabling
Once the Delegation Credential is enabled:
* **Microsoft 365 Calendar is auto-connected** for all organization members whose email matches the configured domain — they do not need to connect it manually
* **New members** added to the organization automatically get their calendar connected
* Members **cannot disconnect** the delegation-managed calendar credential (they can still connect additional calendars manually)
* **Cal.com creates its own client secret** on the app registration and stages it as *pending*, so it can rotate that secret later. The secret you entered stays the active one until Cal.com has validated the new one — within about an hour — and swaps it in. This is why the app registration shows an extra `Cal.com managed` secret shortly after enabling, and why the secret you created isn't the one in use a day later.
***
## Client secret rotation
Microsoft Entra client secrets expire, so the credential needs a new secret before that happens. By default, Cal.com handles this automatically.
* **Automatic rotation (default)**: With `Application.ReadWrite.OwnedBy` granted and [the app owning itself](#make-the-application-an-owner-of-itself), Cal.com creates a new client secret about a week before the current one expires, validates it, and promotes it once it's confirmed to work — no action needed from you. Replacement secrets get a 180-day lifetime, and the secret being replaced is left to expire on its own instead of being deleted. See [Set up automatic secret rotation](/help/enterprise/delegation-credential-microsoft-365-secret-rotation) for how to enable this on a credential you already have, how to check its state through the API, and what each failure code means.
* **Manual rotation (opt-out)**: You can opt a credential out of automatic rotation if you'd rather manage secrets yourself, for example to keep full control over your app registration's credentials. This is currently only available through the [Cal.com API v2](https://cal.com/docs/api-reference/v2/introduction) — set `optOutAutoSecretRotation: true` when creating or updating the delegation credential. There is no toggle for this in the Cal.com dashboard yet.
Automatic secret rotation only applies to Microsoft 365 delegation credentials. Google Workspace delegation credentials use a service account key that doesn't expire, so there's no rotation to opt out of.
### What happens after opting out
Once a credential has opted out of automatic rotation, Cal.com stops minting and promoting secrets for it. Instead, it sends a reminder: about 14 days before the current secret expires, Cal.com fires a `DELEGATION_CREDENTIAL_ROTATION_REQUIRED` [webhook](/help/webhooks) so you can rotate the secret yourself before the credential stops working. The reminder keeps repeating while the secret is close to expiry or recently expired, and stops once the secret has been expired for more than 30 days.
To act on the reminder:
1. Create a new client secret for the application in the Microsoft Entra admin center (see [Step 3](#step-3-create-a-client-secret) above).
2. Update the delegation credential in Cal.com with the new secret value, either from **Settings → Organization → Delegation Credential** or via the API.
If you opted out, you don't need to grant `Application.ReadWrite.OwnedBy` — Cal.com never attempts to modify the app registration's secrets for an opted-out credential.
***
## Disabling the Delegation Credential
Disabling a Delegation Credential:
* Immediately stops auto-connecting calendars for members who haven't manually connected Microsoft 365
* Preserves existing calendar preferences (selected calendars and destination calendar) for members who had them configured
* Background jobs clean up delegation-specific credential records over time
If you no longer need the underlying app registration, you can also remove the client secret or delete the application in the Microsoft Entra admin center.
***
## Frequently asked questions
No. Microsoft 365 Calendar is automatically connected for all members whose email matches the domain. Members can optionally complete [onboarding](/help/enterprise/members-onboarding) to select which calendars to check for conflicts.
The Delegation Credential takes priority for the matching domain. The member's manual connection is preserved but the delegation-managed credential is used for calendar operations.
The application is granted up to three Microsoft Graph application permissions:
* **Calendars.ReadWrite** — read availability and create or update calendar events for members in the configured tenant.
* **User.Read.All** — resolve the Microsoft 365 user for a Cal.com member by their email address.
* **Application.ReadWrite.OwnedBy** — rotate the client secret on the app registration Cal.com owns before it expires. Only needed if you use [automatic secret rotation](#client-secret-rotation); skip it if you opt out and rotate secrets manually.
Cal.com cannot read mail, files, or any other Microsoft 365 data, and `Application.ReadWrite.OwnedBy` is scoped to applications the credential owns — it cannot modify other apps in your tenant.
With `Application.ReadWrite.OwnedBy` granted, Cal.com automatically rotates the client secret before it expires — you do not need to create a new secret manually. If you've [opted out of automatic rotation](#client-secret-rotation), or the permission is not granted (or admin consent is revoked), the credential stops working once the secret expires. Create a new client secret in the Microsoft Entra admin center and update the credential in Cal.com from the Delegation Credential settings.
`GET /v2/organizations/{orgId}/delegation-credentials/{credentialId}` returns the credential's rotation state, including `secretRotationErrorCode` (for example `missing_permission` or `tenant_lifetime_policy`), whether rotation is blocked, and the active and pending secret dates. [Set up automatic secret rotation](/help/enterprise/delegation-credential-microsoft-365-secret-rotation#when-rotation-fails) explains each code and how to clear a blocked credential.
Yes. A Conditional Access policy that blocks app-only (`client_credentials`) token requests stops Cal.com from validating a newly created secret, so rotation fails at the promotion stage even though the permissions and ownership look correct.
Yes. See [Client secret rotation](#client-secret-rotation) above — this is currently only available via the API v2, not the dashboard. Opted-out credentials get a `DELEGATION_CREDENTIAL_ROTATION_REQUIRED` webhook about 14 days before their secret expires, as a reminder to rotate it manually.
# Set up automatic secret rotation (Microsoft 365)
Source: https://cal.com/help/enterprise/delegation-credential-microsoft-365-secret-rotation
Hand client secret rotation for an existing Microsoft 365 Delegation Credential over to Cal.com, and diagnose it when it stops working.
If you already have a working Microsoft 365 [Delegation Credential](/help/enterprise/delegation-credential-microsoft-365), you can let Cal.com replace its Microsoft Entra client secret before it expires, instead of rotating it by hand every few months. This page covers the setup for a credential that already exists — including credentials created before automatic rotation was available.
Automatic rotation applies to Microsoft 365 delegation credentials only. Google Workspace delegation credentials authenticate with a service account key that doesn't expire, so there's nothing to rotate.
***
## What you need
* **Organization admin access** in Cal.com
* **Microsoft Entra admin access** for the tenant that owns the app registration, in a **work or school** tenant (this setup cannot be completed with a personal/consumer Microsoft account)
* The [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli)
***
## Step 1: Grant the rotation permission
Cal.com rotates the secret by calling Microsoft Graph `addPassword` on your app registration, which requires the `Application.ReadWrite.OwnedBy` application permission.
In the [Microsoft Entra admin center](https://entra.microsoft.com), open your app registration, go to **API permissions → Add a permission → Microsoft Graph → Application permissions**, and add `Application.ReadWrite.OwnedBy`.
Click **Grant admin consent for \** and confirm that the permission shows as granted.
***
## Step 2: Make the app an owner of itself
`Application.ReadWrite.OwnedBy` only lets the application manage app registrations it **owns**. Granting the permission is not enough on its own — the application's own service principal has to be an owner of its app registration. This is the most common reason rotation looks configured but keeps failing.
The **Owners** blade in the portal only accepts users, so the ownership has to be added with the Azure CLI.
You need two different object IDs:
| Value | Where to find it |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| App registration **Object ID** | **App registrations → your app → Overview → Object ID**. This is *not* the Application (client) ID. |
| Service principal **Object ID** | **Enterprise applications → the same app → Overview → Object ID**. This is a different value from the app registration's Object ID. |
```bash theme={null}
az login --tenant --allow-no-subscriptions
az ad app owner add \
--id \
--owner-object-id
# verify the service principal now shows up as an owner
az ad app owner list --id --query "[].id"
```
***
## Step 3: Check your tenant secret lifetime policy
Cal.com creates each replacement secret with a **180-day** lifetime. If your tenant has an [app management policy](https://learn.microsoft.com/graph/api/resources/tenantappmanagementpolicy) that caps client secret lifetimes below 180 days, Microsoft rejects every attempt and rotation never succeeds.
If that applies to you, either exempt this app registration from the policy, relax the cap to at least 180 days, or keep rotating the secret manually by opting the credential out of automatic rotation.
***
## Step 4: Make sure the credential isn't opted out
Automatic rotation is on by default. If the credential was explicitly opted out, turn that off with [API v2](https://cal.com/docs/api-reference/v2/introduction) — there's no toggle for this in the dashboard yet:
```http theme={null}
PATCH /v2/organizations/{orgId}/delegation-credentials/{credentialId}
Content-Type: application/json
{ "optOutAutoSecretRotation": false }
```
A `GET` on the same endpoint shows the current value.
***
## Step 5: Hand the current secret over to Cal.com
Cal.com can only rotate a secret it created itself — it has no way to learn the expiry date of a secret you pasted in. So a credential that has never had a Cal.com-managed secret needs one staged once, which happens when a credential is enabled:
Go to **Settings → Organization → Delegation Credential** and toggle the credential off.
Toggle it back on. Cal.com verifies the credential, then creates a Cal.com-managed secret on the app registration and stages it as **pending** — your own secret stays the active one, so nothing breaks in the meantime.
Within about an hour, Cal.com validates the pending secret with an app-only token request and promotes it to active. From then on, Cal.com knows the expiry and rotates it automatically about a week before it runs out.
If you'd rather replace the secret at the same time, updating the client secret through API v2 disables the credential as part of the update — enabling it again then stages the managed secret.
***
## Step 6: Verify it worked
`GET /v2/organizations/{orgId}/delegation-credentials/{credentialId}` returns the rotation state:
```json theme={null}
{
"optOutAutoSecretRotation": false,
"secretRotationBlocked": false,
"secret": { "expiresAt": "2026-08-19T10:12:00.000Z" },
"pendingSecret": { "createdAt": null, "expiresAt": null },
"secretRotationErrorCode": null
}
```
* `secret.expiresAt` filled in and roughly 180 days out means a Cal.com-managed secret is active and rotation is set up.
* `pendingSecret.createdAt` set means a replacement is staged and waiting for validation.
* `secretRotationErrorCode` tells you why the last attempt failed — see below.
In the Microsoft Entra admin center you'll see the old secret still listed under **Certificates & secrets**. That's expected: Cal.com leaves it to expire on its own rather than deleting it, so requests already in flight aren't disrupted.
***
## When rotation fails
Cal.com retries a failing rotation for **48 hours**. After that it stops trying, sets `secretRotationBlocked` to `true` and fires a `DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED` [webhook](/help/webhooks) whose `error.code` is `SECRET_MINT_FAILED` (Microsoft refused to create the replacement) or `SECRET_PROMOTION_FAILED` (the replacement was created but never authenticated successfully).
| `secretRotationErrorCode` | What it means | What to do |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `missing_permission` | Microsoft rejected the call as unauthorized — the permission isn't consented, or the app doesn't own itself. | Redo [Step 1](#step-1-grant-the-rotation-permission) and [Step 2](#step-2-make-the-app-an-owner-of-itself). |
| `tenant_lifetime_policy` | A tenant policy rejects the 180-day secret lifetime. | See [Step 3](#step-3-check-your-tenant-secret-lifetime-policy). |
| `transient` | A temporary Microsoft Graph error (throttling or a 5xx). | Nothing — Cal.com retries on the next run. |
| `pending_secret_mint_failed` | Creating the replacement secret failed for 48 hours and rotation is now blocked. | Fix the underlying cause, then reset rotation. |
| `pending_secret_promotion_failed` | The replacement secret was created but couldn't be validated for 48 hours. | Check that nothing blocks app-only token requests, then reset rotation. |
| `unknown` | A failure that doesn't match any of the above. | Contact [support](https://cal.com/support) with the credential's domain. |
Treat any value you don't recognize as `unknown` — new codes can be added over time.
Once you've fixed the underlying problem, clear the block from **Settings → Organization → Delegation Credential → ⋯ → Reset rotation** (only selectable while a credential is blocked), or with `POST /v2/organizations/{orgId}/delegation-credentials/{credentialId}/reset-rotation`. Rotation then resumes on the next scheduled run.
A Conditional Access policy that blocks app-only (`client_credentials`) token requests breaks rotation even when the permissions and ownership are correct: the new secret is created but can never be validated, so it shows up as a promotion failure.
***
## Audit rotations with webhooks
Three [webhook](/help/webhooks) triggers cover the rotation lifecycle:
* `DELEGATION_CREDENTIAL_SECRET_ROTATED` — a managed secret was validated and promoted to active. Useful as an audit trail.
* `DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED` — rotation reached a terminal failure and the credential is blocked. Subscribe to this if you rely on automatic rotation.
* `DELEGATION_CREDENTIAL_ROTATION_REQUIRED` — sent for credentials that opted **out** of automatic rotation, as a reminder to rotate manually.
# Guest notification settings
Source: https://cal.com/help/enterprise/guest-notification-settings
Control which booking email notifications are sent to attendees across your organization.
Organization admins can disable specific booking email notifications for attendees (guests) across all bookings in the organization. When a notification type is disabled, attendees no longer receive that email, but organizers continue to receive their notifications as normal.
Guest notification settings are only available for organizations. You must be an organization admin to access them.
***
## Available settings
You can disable individual email types or turn off all guest booking emails at once using the master toggle.
Disabling guest emails means attendees will not receive those notifications for any bookings in your organization. Make sure your team has an alternative way to communicate important booking details if needed.
| Email type | What it controls |
| ----------------------- | -------------------------------------------------------------------------- |
| **Confirmation** | Booking confirmation emails sent to attendees when a booking is created |
| **Cancellation** | Emails sent to attendees when a booking is cancelled |
| **Rescheduled** | Emails sent to attendees when a booking is rescheduled |
| **Request** | Emails sent to attendees when a booking requires approval |
| **Host reassignment** | Emails sent to attendees when a booking is reassigned to a different host |
| **Awaiting payment** | Emails sent to attendees when payment is required for a booking |
| **Reschedule request** | Emails sent to attendees when the organizer requests a reschedule |
| **Location change** | Emails sent to attendees when the meeting location changes |
| **Guest added** | Emails sent to attendees when they are added to an existing booking |
| **Cal Video recording** | Recording download emails sent to attendees after a Cal Video meeting ends |
These settings only affect emails sent to attendees. Organizers always receive their booking notifications regardless of these settings.
***
## How to configure
Navigate to **Settings** → **Organization** → **Guest notifications**.
Use the checkboxes next to each email type to enable or disable it. Disabling an email type triggers a confirmation prompt before saving.
Use the **Disable all booking emails to guests** toggle at the top to turn off all notification types at once. You can re-enable individual types afterward if needed.
Changes take effect immediately for all future bookings in your organization.
***
## When to use this
These settings are useful when your organization:
* Has privacy or compliance requirements that restrict sharing certain booking details with external attendees
* Wants to limit the distribution of meeting recordings or transcriptions
* Manages attendee communications through a separate system (such as a CRM or marketing platform)
* Prefers to share booking details manually through a controlled process
***
## Prerequisites
* You must have an organization plan
* You must be an organization admin or owner
* For Cal Video recording emails, video recording must be enabled on your plan
* To control recording and transcription behavior at the event-type level, see [Cal Video advanced settings](/help/event-types/calvideo-advanced-settings)
***
## Frequently asked questions
No. Organizers always receive their booking notifications, even when guest notifications are disabled.
Changes take effect for all future bookings. Emails for bookings that already happened are not affected.
These settings apply organization-wide. To control recording and transcription behavior at the event-type level, use the [Cal Video advanced settings](/help/event-types/calvideo-advanced-settings) on each event type.
You can re-enable individual email types at any time. Only the types you have enabled will be sent to attendees.
# Instant Meetings
Source: https://cal.com/help/enterprise/instant-meetings
Instant Meetings let someone request a meeting with your team immediately, without choosing a future time. The booker selects **Connect now**, enters their details, and waits while a team member accepts the request.
Instant Meetings are available for team event types in a Cal.com organization. They cannot be enabled on personal event types.
## Required setup
You only need an organization team event type with **Instant booking** enabled. The other settings on the Instant booking page are optional.
From **Event Types**, select an existing team event type or create a new one.
Select **Instant booking** from the event type settings, then turn on the **Instant booking** toggle.
Select **Save**. You can now share the team event type link or make the event type public on your team's profile.
Instant Meetings always use Cal Video, even when the event type has a different location configured for scheduled bookings. No additional meeting location is required.
Instant Meetings cannot be enabled for an event type that has payments enabled.
## Optional settings
The following settings are not required to use Instant Meetings. Use them only when you need to customize how Instant booking works for this event type.
### Host join window
The host join window controls how long a host has to accept the instant meeting before the join link expires. A value is already provided when you enable Instant booking, so you only need to change it if your team needs more or less time.
Choose 30, 60, 90, or 120 seconds, or enter a custom duration of at least 10 seconds.
Allow enough time for the meeting request to reach a host and for the host to open the join link.
### Webhooks
Webhooks provide a reliable way to notify hosts that an attendee is waiting. Without a notification method, a host may not know that someone has requested an Instant Meeting.
Team members who have enabled Cal.com browser notifications can receive a push notification when a request is created. However, browser notifications depend on each member granting notification permission. Configure a webhook if your team needs requests delivered through another channel, such as Slack, Microsoft Teams, email, or an internal alerting system.
We recommend configuring an **Instant Meeting Created** webhook before sharing the event type. Use it to alert the hosts who can accept the meeting and include the connect-and-join link from the webhook payload in the notification.
The available instant meeting triggers are:
* **Instant Meeting Created** — fires when the booker submits an instant meeting request. Use this trigger to notify available hosts that an attendee is waiting.
* **Instant Meeting Accepted** — fires when the first host accepts the request. Use this trigger to stop additional alerts or update an external system. It does not fire again if another host tries to accept the same meeting.
The webhook does not notify hosts by itself. Its receiving service must turn the webhook event into the notification your team uses.
#### Example: notify hosts in Slack with Zapier
A common setup is to use Zapier as the receiving service and send each new request to a Slack channel:
In Zapier, create a Zap with **Webhooks by Zapier → Catch Hook** as the trigger. Copy the webhook URL that Zapier provides.
Under **Instant booking → Webhooks**, select **New webhook**, use the Zapier URL as the subscriber URL, and choose **Instant Meeting Created** as the trigger.
Add a Slack action to the Zap and choose the channel that should receive Instant Meeting requests.
Include the attendee information and `connectAndJoinUrl` from the webhook payload in the Slack message. Hosts can then open the link directly from Slack to accept and join the meeting.
This creates a Slack notification whenever an attendee is waiting, without requiring hosts to keep the Cal.com event page open.
For instructions on creating a webhook and working with its payload, see [Webhooks](/help/webhooks).
### Require URL parameter values
Add required URL parameter values when an Instant Meeting should only appear for particular links. Cal.com shows **Connect now** only when every value configured here appears as a query-parameter value in the event type URL. This is useful when a routing form, campaign, or application should control who can request an immediate meeting.
Leave this setting empty to show Instant booking on every version of the event type link.
For example, if you add `support`, share a URL whose query string contains that value:
```text theme={null}
https://cal.com/team/your-team/your-event?source=support
```
### Auto translate instant meeting title
Turn this on to translate the instant meeting title into the booker's language.
This setting is enabled by default. Turn it off to keep the title in English.
### Availability
Availability controls when the **Connect now** prompt appears on the booking page.
* If you leave this setting empty, the prompt appears every time the event type is opened, provided any configured URL parameter values are present.
* If you select a schedule, the prompt only appears when the current time and the full meeting duration fit within that schedule.
When the prompt is not available, the booker can still use the event type's regular scheduling flow to select a future time.
## What the booker experiences
When Instant booking is available, a **Don't want to wait? Connect now** prompt appears on the booking page. The booker can still select a future time or select **Connect now** to request an immediate meeting.
After selecting **Connect now**, the booker enters their name and contact information. Once they submit the request, they see a waiting screen until one of these happens:
* A host accepts the request and joins the meeting.
* The host join window expires.
The booker does not need a Cal.com account. After a host accepts, the booker is redirected to the Cal Video room.
### Cooldown after an Instant Meeting request
After an Instant Meeting request is created successfully, Cal.com starts a 10-minute cooldown for that event type. During the cooldown, **Connect now** remains visible but is disabled, preventing the same booker from immediately submitting another request.
The cooldown is stored in the booker's browser and tracked separately for each event type. It therefore applies when the booker reloads or revisits the event type in the same browser, but it does not carry over to another browser or device.
## Manage Instant Meetings across your organization
Instant Meeting settings apply to the event type where you configure them. Organization admins can use a managed event type to distribute the same Instant Meeting setup to multiple team members and keep its locked settings consistent.
# Members Onboarding
Source: https://cal.com/help/enterprise/members-onboarding
### 👋 Welcome!
Welcome aboard! This guide is for team members who have been invited to use [Cal.com](http://Cal.com) through their organization.
***
## ✅ Step 1: Accept Your Invitation
Look for an invite link in your inbox to join your organization's [Cal.com](http://Cal.com) workspace.
When you click the invite:
* Create a new account or log in to your existing [Cal.com](http://Cal.com) account
* Your profile will be automatically linked to your organization
You might also be invited to other teams within the organization, in which case, you can always visit [Teams](https://app.cal.com/teams) page and accept the invites.
> 🔐 If your organization uses SSO (Single Sign-On), simply log in with your work email.
***
## 📆 Step 2: Connect Your Calendar
If your organization uses [Delegation Credential](/help/enterprise/delegation-credential), your calendar may already be connected automatically. You can skip to selecting which calendars to check for conflicts.
Connect your work calendar to manage availability and prevent double bookings:
1. Go to [App Store → Calendars](https://app.cal.com/apps/categories/calendar)
2. Search for your provider and authorize access
3. Select which calendars [Cal.com](http://Cal.com) should check for conflicts (toggle them on) and where to place booked events (Set as destination Calendar)
***
## 📅 Step 3: Set Up Your Booking Page
Please check with your organization admin if they have already assigned events to you.
Your booking link allows clients and teammates to schedule time with you. Here's how to configure it:
1. Go to [Event Types](https://cal.com/event-types)
2. Create or edit an event (e.g., "1:1 Coaching Session"). Note that any events assigned to you by your admin might be read-only and not editable by you.
3. Customize:
* Duration (e.g., 30 minutes)
* Location (Zoom, Google Meet, in-person, phone)
* Availability (set working hours)
* Buffer times and limits
> 🎨 Your company's default settings and branding may already be in place — you only need to personalize if desired.
***
## 🔗 Step 4: Share Your Booking Link
After setting up your event types, share your link through:
* Your email signature
* Inside Slack or Microsoft Teams
* On internal tools or client dashboards
Example: `https://cal.com/yourname/1-1-session`
For round-robin teams or routed events, your admin may provide a team-wide link that automatically assigns bookings.
***
## ✉️ Step 5: Set Up Reminders
[Cal.com](https://app.cal.com/) can automatically send:
* Email confirmations
* Reminders (Please check with your admin if they have already set up reminder workflows. In any case, you can create new workflows for your event types. You can create workflows by visiting the [workflows page](https://app.cal.com/workflows))
***
## 🔒 Step 6: Review Privacy & Security
Your calendar data is private — only availability is shared with bookers.
[Cal.com](http://cal.com) is compliant with major data regulations including:
* GDPR
* SOC 2
* HIPAA (on request for healthcare orgs)
You can control:
* Which calendars [Cal.com](http://cal.com) can access
* Who sees your availability
* Whether your events are public or private
[Read more about our security practices →](https://cal.com/security)
***
## 📊 Optional: Track Your Bookings
You can visit the [Bookings](https://app.cal.com/bookings) page in the cal.com dashboard to view your:
* Upcoming bookings
* Past bookings
* Cancelled bookings
And also mark guests as No-Show ([Learn more](https://cal.com/help/bookings/no-show#mark-guests-as-no-show))
You can also access the [Insights Dashboard](https://app.cal.com/insights) to view your booking related insights.
***
## Leaving a team
If you no longer need to be part of a team, you can remove yourself without requiring an admin.
Go to the [Teams](https://app.cal.com/teams) page and select the team you want to leave.
Scroll down to the **Danger zone** section and select **Leave team**. Confirm when prompted.
Leaving a team removes your access to that team's event types, routing forms, and shared resources. If your organization uses [seat-based billing](/help/billing-and-usage/seat-billing), your departure may affect the team's seat count.
***
## 🤝 Need Help?
If you have questions or encounter issues:
* Check out our [Help Center](https://cal.com/help)
* Reach out to your team admin to confirm the support plan with us and the best way to reach us.
***
## 🏁 You're All Set!
# Adding events to your calendar
Source: https://cal.com/help/event-types/add-events
Cal.com offers the possibility of automatically adding events to the calendars connected to your account. You can follow the video in case you don't have a calendar connected to your cal.com account yet.
If you have connected a calendar with your Cal account, you can easily select where the events should be created, in case anyone books you through Cal.
You can select default calendar to add the booked events to by going to **`/settings/my-account/calendars`**
You can even select different connected calendars for different links to create events on, in case that's preferable. Thus, offering you complete control of where your booked events are created, helping you organize your events as you please.
# Adding Zoom as the Meeting Location for Your Link
Source: https://cal.com/help/event-types/adding-zoom
To add Zoom as the meeting location for your link, you need to follow these steps:
* Install the [Zoom](https://app.cal.com/apps/zoom) app in our app store
* Go to the **Basics** settings of your link
* Select Zoom Video in the Location dropdown
* Once selected, click **Save** in the top right corner of the UI
That's it!
# Allow rescheduling past events
Source: https://cal.com/help/event-types/allow-rescheduling
Enabling this option allows past events to be rescheduled, giving attendees the flexibility to book a new time if they missed the original event.
For example, if a meeting was scheduled but the attendee didn’t show up, they can reschedule it instead of having to book a new event from scratch. This helps keep the booking flow smooth and reduces the need for manual follow-ups.
# Booker Active Booking Limit
Source: https://cal.com/help/event-types/booker-active-booking-limit
Limit the number of upcoming bookings a single booker can have for this link.
### Overview
The **Booker Active Booking Limit** lets you control how many active (upcoming) bookings a person can have at the same time for a specific link. Once a booker reaches the limit, they won’t be able to schedule another event through this link until one of their existing bookings is either **completed** or **canceled**.
### Example
If you set the limit to **1**:
* The booker can only have **one active booking** at a time.
* Once that event is **over** or **canceled**, they can book again.
> Example: If someone books a session and you’ve set the limit to 1, they can’t schedule another one until the current event is finished.
***
### Offer to reschedule existing booking
If a booker tries to book another time while they already have an active booking, you can choose to **offer them a reschedule** option instead of blocking the booking.
When enabled, this feature will:
* Detect that the booker already has an active booking.
* Prompt them to **reschedule their existing booking** to the new time slot they selected.
This helps avoid duplicate bookings while still letting them easily move their appointment.
### Why use it
* Limit repeat sessions to one at a time.
* Control the flow of upcoming meetings.
### Notes
* The limit applies **per link**.
* **Canceled** and **past** events don’t count toward the limit.
* The setting affects the **booker**, not the host or team members.
* The limit resets automatically once the event passes or is canceled.
* The **reschedule option** only applies if the booker has an existing booking for the same link.
### How to set it
1. Go to **Links** in your Cal.com dashboard.
2. Select the link you want to edit.
3. Open the **Advanced** tab.
4. Go to Limits settings
5. Scroll to **Booker Active Booking Limit**.
6. Set the number of active bookings allowed.
7. (Optional) Enable **Offer to reschedule last active booking** if you want bookers to be able to move their existing booking.
***
# Booking frequency
Source: https://cal.com/help/event-types/booking-frequency
We feel that our users must have a feature that will help them limit their booked events on a daily basis and deal better with the stresses of modern life. Every event carries different weight of stress and burnout, and so the events that lead to higher burnout should ideally be controllable in the frequency per day.
If you don't want more than five bookings of any specific event per day so you can focus on other things or control stress and burnout through certain events, you can do just that with this feature.
You can set the booking frequency of your link in the **Limits & buffers** section of your link settings.
# Booking Questions
Source: https://cal.com/help/event-types/booking-questions
When you create a new link, a few basic booking questions are already created for your new link.
If you'd like to collect more information about your attendees, you can use our booking questions feature and get the necessary information filled out by your attendees when booking. The booking questions can be either required or optional, depending on your needs.
Let's say that you require the phone number of each attendee. You must select the correct input type, write up your placeholder and label, and tick the requirement.
A new field will appear on the booking page where attendees enter the booking details.
You can also make use of the booking questions feature to allow prefilling the [**booking fields**](https://cal.com/docs/core-features/bookings/prefill-fields)
## Booking field identifier
The **`identifier`** for booking questions is a unique text input that users provide when creating a booking question. This identifier serves as a distinctive key for each specific booking question, establishing a clear and unique reference that can be used throughout the platform wherever that question is addressed or its answers are processed.
The primary utility of the identifier emerges when individuals schedule meetings. As they fill out booking forms, the responses they provide are tied back to the specific booking questions via these identifiers. This system ensures precision and clarity, as each answer is unmistakably linked to its corresponding question, eliminating any potential confusion especially when similar or related questions are present.
By utilizing the **`identifier`** for booking questions, users benefit from a more organized, efficient, and error-resistant way of handling booking data, both within the platform and in conjunction with external systems. This streamlined approach not only enhances data management and integrity but also contributes significantly to the overall user experience.
## Phone-based bookings
By default, the booking form requires an attendee's email address to confirm a booking. With phone-based bookings, you can require a phone number instead, so attendees can book using only their phone number without providing an email.
This is useful when SMS is your primary channel for confirmations and reminders, when your audience is more likely to share a phone number than an email, or for regions and workflows where phone contact is the standard way to reach attendees.
To enable phone-based bookings, go to the **Confirmation** section at the top of your link's booking questions and switch the toggle from **Email** to **Phone**. This sets the phone number as the required field your booker must provide to receive confirmations, instead of an email address. Once you've selected **Phone**, click **Save**.
# Booking Success Redirect Parameters
Source: https://cal.com/help/event-types/booking-success-page-query-params
Complete reference guide for query parameters forwarded to custom success pages after successful bookings
When a booking is successfully created in Cal.com, users can be redirected to a custom success page by enabling `Redirect on booking`option in the Confirmation tab of the Booking experience section of the link settings. This guide documents all the query parameters that are forwarded to your custom success URL when 'Forward parameters' option is enabled (which is the default).
## Overview
Cal.com automatically appends booking information as query parameters to your custom success redirect URL. These parameters allow you to display booking details, or integrate with your own systems.
**Example redirect URL:**
```text theme={null}
https://yoursite.com/booking-success?uid=abc123&title=30min%20Meeting&startTime=2024-01-15T14%3A00%3A00.000Z&attendeeName=John%20Doe&email=john%40example.com
```
## Quick Reference
| Parameter | Always Included | Description |
| ------------------- | --------------- | ------------------------------------------------ |
| `uid` | ✅ | Unique booking identifier |
| `title` | ✅ | Lin title |
| `startTime` | ✅ | Start time in UTC |
| `endTime` | ✅ | End time in UTC |
| `email` | ✅ | Primary attendee email |
| `isEmbed` | ✅ | Boolean flag indicating embed booking |
| `description` | ⚠️ | Event description (when available) |
| `location` | ⚠️ | Meeting location (when set) |
| `hostName` | ⚠️ | Host name(s) (when available) |
| `hostStartTime` | ⚠️ | Start time in host timezone (when available) |
| `attendeeName` | ⚠️ | Attendee name (when available) |
| `attendeeStartTime` | ⚠️ | Start time in attendee timezone (when available) |
| `attendeeFirstName` | ⚠️ | First name from booking form (when provided) |
| `attendeeLastName` | ⚠️ | Last name from booking form (when provided) |
| `guestEmails` | ⚠️ | Guest emails (when guests added) |
| `phone` | ⚠️ | Phone number (when provided) |
## Core Booking Parameters
**`uid`** - Unique identifier for the booking
* Always included
* Example: `9ybDCbazSYpJHthpxG5EDM`
* Usage: Use this to fetch additional booking details via API or store in your database
`title` - The link title
* Always included
* Example: `30 Minute Meeting`
`description` - Link description
* Included when event has description
* Example: `Quick sync meeting to discuss project updates`
**`startTime`** - ISO 8601 formatted start time in UTC
* Always included
* Example: `2024-01-15T14:00:00.000Z`
**`endTime`** - ISO 8601 formatted end time in UTC
* Always included
* Example: `2024-01-15T14:30:00.000Z`
**`location`** - Meeting location or video conference URL
* Included when location is set
* Example: `integrations:daily` (Cal Video), `integrations:zoom` (Zoom). More possible values [here](../bookings/prefill-fields#pre-selecting-a-video-meeting)
## Host/Organizer Parameters
**`hostName`** - Host name(s), comma-separated for multiple hosts
* Included when host information available
* Example: `Jane Smith,Mike Johnson`
**`hostStartTime`** - Start time formatted in host's timezone
* Included when host timezone available
* Example: `2024-01-15T09:00:00-05:00`
## Attendee Parameters
**`attendeeName`** - Name of the person who booked
* Included when primary attendee name available
* Example: `John Doe`
**`attendeeStartTime`** - Start time in attendee's timezone
* Included when attendee timezone available
* Example: `2024-01-15T06:00:00-08:00`
**`attendeeFirstName`** - First name from booking form
* Included when first name provided in booking form
* Example: `John`
**`attendeeLastName`** - Last name from booking form
* Included when last name provided in booking form
* Example: `Doe`
**`guestEmails`** - Comma-separated list of guest emails
* Included when additional guests added
* Example: `guest1@example.com, guest2@example.com`
## Booking Context Parameters
**`email`** - Primary attendee's email address
* Always included
* Example: `john@example.com`
**`phone`** - Phone number from booking form
* Included when phone number provided
* Example: `+1234567890`
## System Context Parameters
**`isEmbed`** - Boolean flag indicating if booking was made via embed
* Always included
* Example: `false`
## Troubleshooting
### Common Issues
**Missing Parameters**
* Some parameters are only included when data is available
**URL Encoding Issues**
* Always use `decodeURIComponent()` in JavaScript or equivalent in other languages
* Special characters like `@`, `+`, spaces are URL encoded
**Date/Time Handling**
* `startTime` and `endTime` are always in UTC (ISO 8601 format)
* `hostStartTime` and `attendeeStartTime` include timezone information
* Convert to local time as needed for display
### Security Considerations
* Always validate and sanitize parameters before using in database queries
* Don't trust parameter values - validate against your expected data types
# Cal.Video Location: Advanced Settings
Source: https://cal.com/help/event-types/calvideo-advanced-settings
When you pick [**Cal.Video**](http://Cal.Video) as the location for an event type, you can reveal extra configuration options by selecting **Show advanced settings**. These controls let you manage recording, transcription, guest permissions, and the post-call experience.
Once you select CalVideo for your Event Type, you can access these settings by clicking on "Show advanced settings" below the dropdown.
## Recording
### Disable recording for guests
Prevents the guest from starting a recording inside the meeting.
### Disable recording for organizer
Blocks organizers from starting a recording. Useful for teams where only the owner should control recordings.
### Automatic recording
Starts recording automatically as soon as the organizer joins the room. This removes the need for any manual action.
Organization admins can disable Cal Video recording download emails for all attendees across the organization. This setting is found under **Organization Settings → Guest notifications**. When enabled, attendees will not receive recording download links, but organizers will still get their recording emails.
### Viewing recordings on cal.eu
On the EU region (`cal.eu`), the **View recordings** action is available on any past, confirmed Cal Video booking, even if Cal.com did not detect a recording file for that meeting. This lets organizers open the recordings dialog and check whether a recording is available whenever they suspect one exists.
On `cal.com` and other regions, **View recordings** is only enabled when a recording was captured for the booking.
## Transcription
### Transcription on join
Enables transcription automatically after the organizer enters the call.
### Disable transcription for guests
Guests cannot turn transcription on.
### Disable transcription for organizer
Stops organizers from enabling transcription when this must be controlled manually.
### Transcription language
Choose the language used for AI transcription on this event type. English is the default. Select **Multilingual (auto-detect)** for meetings where participants switch between languages, or pick a specific language when you know it in advance to improve accuracy.
Supported languages include Arabic, Bulgarian, Catalan, Chinese (Cantonese), Croatian, Czech, Danish, Dutch, English, Finnish, Flemish, French, French (Canada), German, German (Switzerland), Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Malay, Norwegian, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Serbian, Slovak, Slovenian, Spanish, Spanish (Latin America), Swedish, Thai, Turkish, Ukrainian, and Vietnamese.
Transcription settings, including language selection, are available on team plans.
### Guest Access
**Require email to join**
Guests must provide an email address before entering the call. This works as a simple verification step.
### Post-Call Behavior
**Redirect URL**
Send participants to any URL after the meeting ends. Common use cases include thank you pages, surveys, or onboarding flows.
# Collective Events
Source: https://cal.com/help/event-types/collective-events
Collective event types are ideal when the booker needs to book a meeting with several team members at one time. With Cal.com Teams, you can easily create a team event type and select collective scheduling as the scheduling type. You can then pick exactly which team members should co-host this event type collectively.
[](https://downloads.intercomcdn.com/i/o/1198415245/17cad46157f1e76e621fd9c4/i1600x899-mIkRTG3JZGA-_t2q4de.png?expires=1736325000\&signature=23aa1e5df707fe86cbedd8ca76557261ab0ddf5394ffa7a4ccb298c471a9a4ec\&req=dSEuHs1%2FmINbXPMW1HO4zc%2BQhQ6N1u12gGNXud8OL2HWw%2FiHm13enr9VaIBj%0AZ%2B6%2FYd9Z13GLMPcKfP0%3D%0A)
Cal.com then evaluates availability on the basis of each member's availability by default. However, you also have an option to put forward a common schedule for this specific event type which will be used as the availability and over-ride each member's availability for this event type.
[](https://downloads.intercomcdn.com/i/o/1198415242/81e383ef1ad8f3e70cdadb91/i1600x899-C7et3rTz2nGC_zkie4g.png?expires=1736325000\&signature=43fc3e00c6ea9d350bc59c65b0f58d7479309f022e861a85d1e67c36c037b6f8\&req=dSEuHs1%2FmINbW%2FMW1HO4zRJuiACbPhZnvVY8S0WiTS3gy%2BPssvqX2wPEZE5k%0A7n3wYZmf9TWaJcDdeEE%3D%0A)
When you need a group of team members to attend the same meeting, collective events are fantastic. Seeking a convenient time for all of your team members to attend the meeting is a breeze with this method.
# Create your first event type
Source: https://cal.com/help/event-types/create-first-event
A quick walkthrough of how to create event types.
## The basics
Head over to the **event types** page, then click the **New event type** button in the top right.
You'll now be presented with the create event type dialog, which prompts you to enter in the basic information needed to get a working event type set up:
* Title
* URL (e.g. cal.com/bailey/**example-event**)
* Description
* Length
[](https://downloads.intercomcdn.com/i/o/1195433173/459d590315726cde2c3da6a6/i973x933-2xQuLlTcg2xz_cvs7li.png?expires=1736301600\&signature=cb4a1bc917705b98367e3e8b391fcde42d13240eeb044c61f2d3805509eec0e5\&req=dSEuE819noBYWvMW1HO4zdvMofsCtCGMAPo%2BOL%2BAzF%2B0SWwGv6se8fklfFKd%0ARDLOujK%2Boq3LGcxdQ5Q%3D%0A)
New event type dialog
This is all you need to get an event type up and running, but you can configure additional settings for greater control.
# Create a phone-only event type
Source: https://cal.com/help/event-types/create-phone-only-event-type
Now available for every version of Cal.com
A phone-only event type asks bookers for their phone number instead of their email address to receive confirmations. With the latest event type settings redesign, you no longer need to manually edit individual booking questions. The switch now happens in a single step.
1. Open the event type you want to edit.
2. In the left sidebar, under **Booking experience**, select **Booking form**.
3. At the top of the page, find the **Confirmation** section labeled "What your booker should provide to receive confirmations". It has an **Email** / **Phone** toggle.
4. Switch the toggle from **Email** to **Phone**.
5. Click **Save**.
That's it. Once you switch to **Phone**, the booking form automatically replaces the email field with a phone number field, so bookers provide their phone number to receive confirmations.
This setup is perfect for scenarios where you only need the attendee's phone number for communication.
# Create a recurring event
Source: https://cal.com/help/event-types/create-recurring
Recurring event types are ideal when the booker needs to schedule a meeting that happens on a regular basis. With Cal.com, you can easily create an event type and select recurring scheduling as the scheduling type. You can then define the frequency and duration of the recurring meetings and customize the availability settings to fit your needs. This makes managing ongoin
# Create a secret event type
Source: https://cal.com/help/event-types/create-secret
Cal.com offers you the possibility of creating secret events also known as **hidden** events. A hidden event is a bookable appointment that can only be accessed via a private link. By default, this means that a hidden event won't show up on your Cal.com booking page. Hidden events are just like regular events in that they can occur in-person, over the phone, or via video chat. Hidden events are a handy tool to use as part of your scheduling infrastructure arsenal. Since they don't show up on your main booking page, they are ideal for meetings of a sensitive or personal nature.
You can use hidden events for everything from auditioning talent to organizing surprise parties or hosting breakaway rooms at virtual conferences. You can easily share the hidden event type by copying the URL and then sharing via email, sms or any other form of communication.
Please note that when this toggle is enabled, it means that the event type **will** show up in your public page and to hide them, they need to be **toggled off.**
# Custom event name in the booking
Source: https://cal.com/help/event-types/custom-name
Custom event names allow bookings to take in information from the booking and add it to the title. This feature allows the option to breaks away from the default "Event name" with "Attendee".
[](https://downloads.intercomcdn.com/i/o/1195339126/934290c58548d3f5a4620cb4/i1600x900-hFpSqIX3Hvsw_gsg746.png?expires=1736299800\&signature=b09aa4b7123b081b8670ef3e86542adbb66028e618b1c3f64aec3ad2eee81730\&req=dSEuE8p9lIBdX%2FMW1HO4zcnyVy187R6euhJKPXdNBy%2FBBk6%2FRnFtGhnUDMOV%0AYCkEbtLzNr73rWdLy%2Fo%3D%0A)
You can currently use the following variables here:
| **Name** | **Definition** | **Example** |
| ---------------- | ------------------------------ | -------------- |
| Event type title | The event type name | Weekly Meeting |
| Organiser | Your full name | John Doe |
| Scheduler | The full name of the scheduler | Jane Doe |
| Location | The location of the event | Acme Cafe |
# Custom Reply-to
Source: https://cal.com/help/event-types/custom-reply-to
The Custom Reply-To feature lets you choose which email address appears in the **Reply-To** field of your confirmation and workflow emails. When an attendee replies to a booking email, their response goes to the address you select here.
#### Where to find it
Go to your **Event Type → Confirmation** tab and enable **Custom Reply-To**.
#### Which emails show up in the dropdown
The dropdown only shows emails that are already verified on your [Cal.com](http://Cal.com) account. This includes your primary email plus any additional emails you've added to your profile.
You can't type in an arbitrary address here—it has to be one of your verified emails.
#### How to add more emails to the dropdown
If you want a different address to appear as an option, add and verify it first:
1. Go to your **Profile / Account Settings**.
2. Under your email section, select **Add verified email** and enter the new address.
3. Open the verification email sent to that address and confirm it.
4. Head back to your **Event Type → Confirmation** tab. The newly verified email will now appear in the Custom Reply-To dropdown.
#### Good to know
Once you select a custom Reply-To address, it's used in place of your organizer email for outgoing confirmation and workflow emails. If you've also turned on the option to hide your organizer email, only the custom Reply-To address will be used.
# Custom time-slot intervals
Source: https://cal.com/help/event-types/custom-time-slots
Using the custom time-slot interval feature in your account settings, you can change the way your bookable appointment slots are displayed in your public booking page. The time slot intervals indicate the slots available for booking; therefore a smaller interval will mean lots of little slices, while a larger interval will mean a smaller amount of bigger durations.
This change allows you to have more freedom in case of long event types by increasing the number of potential slots available, and in case of small event types, you can put a good amount of breather between them.
By default, a time-slot interval is of the same length as the event type. However, within each individual event-type, you have the option to choose a different time-slot interval. Here's how to do that:
Select your event type where you wish to customise the time-slot interval
To change the time-slot interval, click on the Limits & buffers tab.
Then, click on the time-slot interval select box to view the interval options in minutes and select the time interval of your choice
Click on Update to save your changes. Your event type should now consider the newly added time-slot interval
# Disabling Cancelling and Rescheduling
Source: https://cal.com/help/event-types/disable-canceling-rescheduling
[Cal.com](http://Cal.com) allows you to control whether events can be cancelled or rescheduled after they've been booked. These options apply to **both the organizer and the guest**.
#### **Disable Cancelling**
When this setting is enabled:
* Guests will no longer be able to cancel their booking via calendar invite links or email.
* Organizers will also lose the ability to cancel the event from within the [Cal.com](http://Cal.com) dashboard or via calendar/email links.
This is useful when bookings must remain fixed once confirmed — for example, in high-demand or tightly scheduled environments.
#### **Disable Rescheduling**
When this setting is enabled:
* Guests can no longer reschedule their booking using the links provided in their confirmation email or calendar event.
* Organizers are also prevented from rescheduling the event through the dashboard or calendar tools.
Enable this if you need to lock in meeting times and avoid last-minute changes.
These settings apply to the **entire event**, and affect both parties. Use with caution if flexibility is important for your scheduling flow.
# Disable confirmation email for attendees/host
Source: https://cal.com/help/event-types/disable-confirmation
Users who wish to disable booking confirmation emails sent from Cal.com to attendees or the organizer can do so provided they have a workflow enabled to send an email to attendees/organizer upon booking for that specific event type. Follow the steps below to disable confirmation emails:
**Steps to Disable Confirmation Email:**
Users must have a workflow enabled that sends an email to attendees or the organizer (depending on which email they want to disable) upon booking for the specific event type. This workflow serves as an alternative method of confirmation. Make sure you select the correct event type for that workflow.
You will find that toggle in the Confirmation tab of the \`Booking experience\` section of the event type settings.
After disabling confirmation emails, remember to save your changes to ensure they take effect.
# Disable guests
Source: https://cal.com/help/event-types/disable-guests
If you do not wish for your booker to add other guests to your event type, you can make use of this feature to disable adding guests to the event during the booking of this event.
[](https://downloads.intercomcdn.com/i/o/1195341348/d2d8b869fda0990ad0d810f8/i1600x900-0UQQmiszv6Ol_pz3ogv.png?expires=1736299800\&signature=9bd2f4ed8da52f7b22bb7255cbc8505e04d75cbf20515fe67a2c0164880ce492\&req=dSEuE8p6nIJbUfMW1HO4zZmFRiEQe%2FmvLShNjDQR8WrjzS1rqweVFi5wuB1r%0ARK8eBgvIpsrvGrA0iAU%3D%0A)
It is part of the booking questions that you can make use of. By default, it is allowed for the booker to add guests. By default, the Add guests toggle is enabled which allows the booker to add guests to the booking. If you wish to disable it, simply toggle it off.
**Please note that they may still be able to invite guests using their personal calendar invites.**
# Event type slot display issues
Source: https://cal.com/help/event-types/display-issues
When encountering discrepancies in slot availability on the cal.com event type/booking page, follow these steps to troubleshoot and resolve the problem: **If Booking Slots Are Available When You Are Unavailable:**
* Review your connected calendar for events marked as "free" instead of
"busy," particularly all-day events such as vacations or out-of-office days.
Some calendar providers, like Google Calendar, default to marking such
events as free. - Navigate to your cal.com settings under “**Settings**” >
“**Calendars**” and ensure that the calendar containing busy events is
toggled to be checked by cal.com for conflicts.
* If you've set up date overrides in the availability settings, ensure they
are configured correctly. Date overrides may override your availability for
specific time periods.
### If Booking Slots Are Unavailable When You Are Available:
* Check your connected calendar to confirm that events marked as free are indeed marked as busy during your desired booking times.
* Verify the time intervals set for your event type. If your availability starts or ends at non-standard intervals (e.g., 8:15 - 11:30), adjust the time intervals accordingly. By default, cal.com displays slots starting on the hour only. Increasing intervals to 30 or 15-minute increments will display additional slots. Refer to the **[time slot interval documentation](https://cal.com/docs/core-features/event-types/custom-time-slot-intervals)** for more information.
* Review buffer times applied before or after meetings. Buffers subtract time before or after a meeting, potentially affecting slot availability. Refer to the **[buffer time documentation](https://cal.com/docs/core-features/event-types/event-buffer#an-example)** for guidance.
* Ensure that the booking frequency limit is set appropriately. Adjust settings accordingly if there are restrictions on how frequently bookings can be made. Refer to the **[booking frequency documentation](https://cal.com/docs/core-features/event-types/booking-frequency)** for assistance.
* Review the "Limit Future Bookings" setting to ensure it aligns with your availability preferences. Adjust this setting if necessary to allow for future bookings. Refer to the **[limit future bookings documentation](https://cal.com/docs/core-features/event-types/limit-future-bookings)** for more details.
By following these steps and checking each aspect meticulously, you should be able to effectively identify and resolve issues with slot availability on the cal.com event type/booking page. If the problem persists, don't hesitate to contact cal.com support for further assistance.
# Dynamic Group Links
Source: https://cal.com/help/event-types/dynamic
With dynamic group links, bookers can dynamically create group links by adding users using + between their usernames.
This feature allows you to append virtually unlimited number of Cal.com users by simply adding their usernames with a **`+`** between adjoining usernames, and have a collective group. Try it now with Bailey and Peer, visit [cal.com/elon+zuck](http://cal.com/elon+zuck)
This is an opt-in feature where a cal.com user can enable/disable if they wish to participate in this and allow the bookers to add them as part of a dynamic collective group.
Learn more about dynamic links here:
Dynamic group links are enabled by default. If you wish to disable this feature in your account, you can head to [**settings/my-account-general**](https://cal.com/settings/my-account/general) and switch the toggle.
# Require/Exclude Email Domains (Booking Question)
Source: https://cal.com/help/event-types/email-bookingq
Control who can book by requiring or excluding specific email domains like @company.com or public domains like @gmail.com.
The **Email** field in Cal.com’s booking questions supports **domain-level restrictions**, allowing you to control who can (or can't) book time with you based on their email address.
### Use Case
This is useful when:
* You only want people from a specific company (e.g., `@company.com`) to book.
* You want to **exclude free/public domains** like `@gmail.com` or `@yahoo.com`.
* You're running internal meetings and only want your organization's members to access them.
### How to Configure
Go to your Booking form settings of your Event type setup. Under \*\*Booking questions, \*\*find the Email field. Click on `Edit`next to the booking question, and you’ll see options to:
* Require emails that contain (...)
* Exclude emails that contain (...)
Simply use the fields to specify or exclude email domains for your specific use case.
# Event buffers
Source: https://cal.com/help/event-types/event-buffer
Learn how event buffers block time before and after meetings to prevent back-to-back bookings.
Event buffers are a great way to maintain a breathing space between multiple events in a day. Buffers are taken into consideration while booking a Cal event, if that Cal event has a buffer time selected. This simply means that buffers cannot overlap Cal events and thus a Cal event with buffer time can only be booked respecting the buffer time (before event, after event or both).
Event buffers automatically block time **before and/or after your meetings** so you don't get booked back-to-back.
You can configure buffers per event type. For example:
* Add buffer **before meetings** to prepare
* Add buffer **after meetings** to take notes, travel, or follow up
When buffers are enabled, Cal.com treats that extra time as **busy**, so new bookings cannot overlap it.
## How to set a buffer time
You can either set a before event buffer time, an after event buffer time, or both. Here's how to do that:
Select your event type where you wish to add the buffer time
To add a buffer time, click on the Limits & buffers tab of the event type settings.
Then, click on the before event, or after event select box to view the buffer time options in minutes and select the buffer time of your choice
Click on Update to save your changes. Your event type should now consider the newly added buffer time
## How buffers work
Every meeting creates a **protected time window** around it.
```text theme={null}
| buffer before | meeting time | buffer after |
```
Other meetings cannot be scheduled inside this protected window.
## Buffers can stack
When someone tries to book a new meeting near an existing one, Cal.com considers:
* Buffers of the **existing meeting**
* Buffers of the **new meeting being scheduled**
This ensures **both meetings get the space they require**.
This is why you may sometimes see **more time blocked than the buffer value itself**.
# Event Types
Source: https://cal.com/help/event-types/event-types
Event types are your pre-set meetings, events, consultations, etc., which you can share with potential attendees. You can create as many event types as you need with each account, and each event type is customizable in terms of its name, URL, duration, availability, and location of the event.
A deep dive into the advanced settings of each event type.
Event types allow you to create different events for different occasions when booking a time with you in your calendar. These can be named differently, have different time durations and configurations.
**For example:** A HR person could have a "Job Interview" event type lasting 30 minutes, a "Performance Review" event type for 60 minutes both with different settings on each.
You can create event types either for your personal Cal.com link, or for your team (if you've joined one). Personal event types set up a meeting where people can book just you, whereas team event types allow you to either book one person from the team, or multiple people at the same time.
Once you preview the URL of your event type, that event type's availability will show in the form of slots that are available for booking. Your event type can also check your integrated calendar for conflicts; any current events in your calendar will occupy the associated time slot with that calendar event.
# How to find your Event Type ID
Source: https://cal.com/help/event-types/eventtype-id
Event Type ID you can find when you open the settings of your event type. Once you do, look for the numbers between the slashes in the URL bar. That is your Event Type ID.
# Event-Type Specific Checking for Conflicts
Source: https://cal.com/help/event-types/eventtype-specific-checking-for-conflicts
Control which calendars are checked for conflicts on a per-event-type basis to manage availability for different meeting types.
By default, [Cal.com](http://Cal.com) checks for conflicts across all of a user’s connected calendars when determining availability. This ensures that if you already have something scheduled, no matter which event type or calendar it is tied to, you will not be double-booked.
However, sometimes you may want more control. That is where **Event-Type Specific Checking for Conflicts** comes in.
With this setting, you can define conflict-checking rules on a **per–event type** basis. Instead of relying on the global user-level conflict check, you can decide which specific calendars should or should not be taken into account for a particular event type.
### How It Works
* Go to your **Event Type Settings** → **Availability Settings**
* Locate the **Checking for Conflicts** option.
* Switch the drop-down from **User** to **Event Type**.
* Select the calendars you want this event type to check for conflicts.
This way, you can fine-tune availability logic for each event type individually. For example:
* For a **personal coffee chat** event, only check your personal calendar.
* For a **sales demo** event, only check your work calendar.
* For a **VIP event type**, check both but ignore shared team calendars.
### Why Use This?
Event-Type Specific Conflict Checking is helpful if:
* You want to keep personal and professional schedules separate.
* You are running multiple event types that do not need to block each other.
* You need flexibility for certain meetings that do not conflict with all your calendars.
In short, it gives you **granular control** over how availability is managed without being locked into a one-size-fits-all conflict rule.\
\
This feature is only available for individual event types, not team event types, because team events use the default calendar conflict logic of each assigned team member account.
**The event type specific checking for conflicts is only for your native calendar events. Cal.com events/booked slots are making you busy for the same slot across all of your individual events, regardless of the calendar you are adding this event to. That time is busy on your upcoming bookings page.**
# Hide notes in calendar
Source: https://cal.com/help/event-types/hide-notes
Toggling this option in the event type settings will hide additional inputs and notes in the calendar entry. They will still be sent in your email confirmation.
[](https://downloads.intercomcdn.com/i/o/1195343599/396f9884f47ed0dced3d95ec/i1600x900-e7gzhDg2A7wR_hxib3m.png?expires=1736299800\&signature=101dcff39e5129a8ecc03308bfc1564dd293c1ef0b249b8fde74fcf1b3ef940d\&req=dSEuE8p6noRWUPMW1HO4zfvmqQ%2B8IUVJyr7pDFsNo2IDz7nzO7RzPmtX9EvN%0A%2BHb3z6Vd%2Ft8pKIZiuFg%3D%0A)
Most of the entries in notes and additional inputs contain personal information, and if you have a team or shared calendar, for example, you can protect your attendee's privacy by hiding all this info.
# Hide organizer's email
Source: https://cal.com/help/event-types/hideorganizersemail
This setting hides the organizer’s email address from guests—on the booking confirmation page, in email notifications, and on calendar invites. It’s useful when you don’t want the person booking to see or contact the organizer directly.
#### Useful when:
* You don’t want to expose a team member’s email to a third party.
* You’re adding the event to your business calendar but don’t want guests to see the personal email tied to your [Cal.com](http://Cal.com) account—especially if you originally signed up with your personal address (we’ve all been there).
* You want to centralize communication and avoid direct replies to individual inboxes.
#### How to enable:
* Click on the event type to open it's settings
* Go to **Privacy & security** section under **Policies** settings.
* Toggle **Hide organizer’s email**
* Hit **Save** in the top-right corner
# How to add a location to your event type
Source: https://cal.com/help/event-types/how-to-add-location
To add a location to your event type, you simply click on the event type to customise it. Once in, all you need to do is click on the Location select-box and select the location of your choice.
In this example, we're choosing Cal Video, and it shows up as shown in the following image. Finally, click on Save to confirm your selection (marked in green in the following image).
To add any conferencing apps such as Zoom, Google Meet, etc. or messaging apps such as Whatsapp, Signal, etc. as the location of your event type, you would need to install the app from the Cal.com app store prior to following the steps mentioned in this guide.
## Supported location types
Cal.com offers a wide variety of supported locations for your event types. As of V2.0, we offer the following locations:
* **In person** This could be an address and accepts a text input.
* **Link** You can provide a custom meeting link by choosing this location
* **Attendee phone number** Cal will ask the attendee to provide their phone number at the time of booking
* **Organizer phone number** You can provide your phone number as the booking location
* **Cal video** You can use this option to have Cal Video as the booking location.
* **Third party web-conference** You can select from a range of third party web conference apps such as Google Meet, Zoom, Microsoft Teams, etc.
Each event type can have multiple locations, and you can decide which of those (if any) should be visible before the booking is confirmed. If they are hidden at the time of booking, the attendees will only get the location details after the booking confirmation.
# How to set up an event type to receive payments
Source: https://cal.com/help/event-types/how-to-receive-payments
Cal.com uses Stripe to allow you to receive payments when someone books your paid event type.
To start taking payments, please follow these steps:
1. Go to the Cal.com app store -> cal.com/apps
2. Search for Stripe using the Cal.com's app store search
[](https://calcom-inc-0470baa6daee.intercom-attachments-1.com/i/o/1195438478/53cae3464237fe8b5b5732a3/i1600x784-4szl8RRLxFIG_rvkfwz.png?expires=1736302500\&signature=3635138e8ed7605c1e32d37ef38dd7e278949c6b60af33d96569effa81c8dd49\&req=dSEuE819lYVYUfMW1HO4zcdGv441K3iK4tfJRU7p9XL5f1ByiaXpxbigw5gc%0AiRDK%0A)
3\. Click install.
4\. Proceed through to connect your stripe account with Cal.com (if you don't already have an account with stripe, you can do so in this step as well)
5\. Now that stripe is connected to your account, you can either open an existing event type or create a new one
6\. In connected apps, you should see stripe. Simply confirm the price you wish your bookers to pay and click on **`save`**.
[](https://calcom-inc-0470baa6daee.intercom-attachments-1.com/i/o/1195438496/ed5264946d248e316c9ef8c8/i1600x141-u3PhP4xiRb84_qgagos.png?expires=1736302500\&signature=9ee8e0ad21895dd5679a987b269955f6164d41dec3f113e1465cb19f1a16583c\&req=dSEuE819lYVWX%2FMW1HO4zSQBmo484xTPzFvABQEK9J3qXPedIfx5IP8CgO0b%0A2E4k%0A)
7\. That's it. You will receive payments as soon as someone books you using this event type.
# How to require confirmation for your Cal.com bookings
Source: https://cal.com/help/event-types/how-to-requires
By default, any open slot on your booking page can be booked instantly. Requiring confirmation adds a manual approval step: when someone books, the request comes to you first, and the booking is only pushed to your calendar and confirmed to the attendee once you accept it. Until then, the booking stays in a pending state and no confirmation email is sent.
This is useful when you want control over who gets on your calendar, such as screening inbound sales calls, vetting interview requests, or protecting your time from bookings that arrive with very little notice.
**How to enable it**
1. Go to **Links** and open the link you want to change.
2. In the left sidebar, under **Policies**, select **Privacy & security**.
3. Toggle on **Requires confirmation**.
4. Click **Save**.
Once enabled, your booking page will show a "Requires confirmation" label so attendees know their booking is subject to approval.
**Choosing when confirmation is required**
You can decide how strictly this applies:
* **Always** – every booking on this event type needs your approval before it is confirmed.
* **When booked with less than X notice** – only bookings made close to the start time need approval. Set the threshold in minutes, hours, or days. Bookings made further in advance are confirmed automatically, so this is a good option if you only want to review last-minute requests.
**Additional options**
* **Unconfirmed bookings still block calendar slots** – while a booking is waiting for your approval, that time is held and not offered to other bookers. Turn this off if you want the slot to stay open until you confirm.
* **Only require confirmation for free email providers** – bookings from addresses on free providers such as @[gmail.com](http://gmail.com) or @[outlook.com](http://outlook.com) require your approval, while bookings from company domains are confirmed automatically. This is a simple way to filter for business contacts without reviewing every request.
**Managing pending bookings**
Bookings awaiting your approval appear under the **Unconfirmed** tab on your Bookings page. From there you can accept or reject each request. Accepting pushes the event to your calendar and sends the confirmation to the attendee; rejecting notifies them that the booking was declined, and you can optionally include a reason.
# Limit future bookings
Source: https://cal.com/help/event-types/limit-future-bookings
If there is a period in the future after which you think managing your Cal.com events carries some level of uncertainty, with this feature, you can limit how far in the future your event can be booked. You can select how many calendar/business days will be displayed on your booking page as available for booking, or you can select a date range after there will be no slots showing. This can also be useful if you want to keep an eye on your immediate events to ensure no unwanted bookings appear on your calendar.
Let's say you want to be available for bookings only two weeks ahead at any point in time. In your Event Type settings, select a number of days for how far into the future an invitee can book an event with you and set it to 14 calendar days. Now, bookers can only book you for two weeks ahead at any point in time.
[](https://downloads.intercomcdn.com/i/o/1195344503/7bfd63370747d720b993720d/i1600x900-TVdNc-x2ILeF_j1yhir.png?expires=1736299800\&signature=82d78ccc6928fd95cbbc69946f9491ba2ad973a7cb6540c9181237d1a922d51e\&req=dSEuE8p6mYRfWvMW1HO4zZQmmHt0EVFu0sKZNMC3U1%2BmUGv7NmQsdhqs5UwJ%0AcqsAGY8AnbpenNk329g%3D%0A)
# Managed Events
Source: https://cal.com/help/event-types/managed-events
Create and manage shared event types for your team from one place.
Team admins can manage event types for their members, making it easy to create common event types for all members and manage them from one place.
A managed event type comes with certain fields locked by the team admin, and certain fields open to be modified by the team members receiving the managed event.
Managed Events v2 do not currently support Webhooks and Apps. Support for these will be added in a future release.
## Creation
Be sure to be a team admin, and in case you are self-hosting, have the `managed-event-types` operational feature flag turned on.
When creating a team event type, you will get the option to create a Managed Event.
## Management
Once the managed event type is created, you can set all the fields you want to manage as a team admin. You can distinguish fields that will be locked for team members by the "lock" icon next to the field label.
### URL slug
Managed event types do not expose a URL slug field on the parent template. Each assigned team member receives their own copy of the event with a booking link based on their personal username (for example, `cal.com/your-username/30min`), so there is no shared URL to configure on the parent.
## Assignment
A crucial part of a managed event type is the assignment of team members, so managed event types can be created on your behalf.
Think of the managed event you created as a team admin as an event template. Team members will get regular event types from it once they are assigned to it.
Whenever you make changes to locked fields, every team member will also get the same change on their regular event type created from this managed event type. Unlocked fields will not affect already-created event types for assigned members, only new members.
### Slug conflicts
When you assign a managed event type to a team member who already has a personal event type with the same slug (URL), Cal.com will show a confirmation dialog. If you proceed:
* The team member's personal event type is **hidden and renamed** rather than deleted. They can still find it on their event types page if needed.
* The managed event type takes over the booking link at that slug.
* The team member receives an email notification explaining that their booking link has been replaced by a managed event type.
This also applies when you enable the **Assign all team members** toggle. A warning dialog will inform you that any current or future team member with a conflicting slug will have their booking link replaced automatically.
## No-availability notifications
When a booker visits a managed event type and sees no available time slots, organization admins are notified so they can fix the issue. For managed event types, Cal.com sends a single **digest email** instead of individual emails for each affected member. This prevents inbox overload when many members have no availability at the same time.
The digest email includes:
* The name of the managed event type
* A list of all team members who had no availability
* A link to check team availability settings
Digest emails are sent at most once every 24 hours per managed event type. To receive these notifications, an organization admin must enable the **Get notifications when your team has no availability** toggle in organization settings.
This setting applies to the entire organization. Go to **Settings** → **Organization** → **General** and enable the no-availability notifications toggle.
# Minimum notice
Source: https://cal.com/help/event-types/min-notice
Cal.com allows you to set how many minutes, hours, and days are required before someone books your time. This minimum notice allows you to define the exact space of time that you might need as a notice period before any event can be booked.
[](https://downloads.intercomcdn.com/i/o/1195346357/f78fe12313340246526adbc0/i1600x900-b5emq7AZJs03_cnctxl.png?expires=1736299800\&signature=dc03f4887de4dbc85ad116fc9cd4fc20030fe13c85c92d5a588ab3fd7b180d5b\&req=dSEuE8p6m4JaXvMW1HO4zff1wPeNUbdir1Th4xNggL7ZyjjzEjhyvR%2BsVk%2Fk%0AayOs4D2EBysYFG0k5es%3D%0A)
For example, if the potential attendee wants to book the meeting with you tomorrow at 5:00 PM and you have set a minimum notice of 120 minutes (or 2 hours), they need to submit the booking by 3:00 PM at the latest on the same day.
# Multiple durations
Source: https://cal.com/help/event-types/multiple-durations
If you want to allow a client to choose between a meeting of 1 hour and one of 30 minutes, you don't have to create two different meetings; one of 60 minutes and one of 30 minutes. Instead, Cal.com offers you the possibility of using the same event-type and offer meetings with several durations where the booker can pick the preferred duration.
[](https://downloads.intercomcdn.com/i/o/1195347197/f1e403455555384ec38557cc/i1600x900-BgMltGEPb6Na_ovq8ua.png?expires=1736299800\&signature=8ac66befe1b64dd2e3277aa603336a2ba3d39c7fa9d6ba2553a57618c0d09ded\&req=dSEuE8p6moBWXvMW1HO4zW8jTdJYIEvemQ2XLldUYQGjype2juOD0dnBUZaP%0ACR0XuAJqPP9PDF2n8E0%3D%0A)
There are multiple options to choose from, and no limit on the number of durations to offer the booker from these options. You also have a default selectable for situations where the booker doesn't necessarily need to select a duration, just that they have an option to choose one.
# Offer seats
Source: https://cal.com/help/event-types/offer-seats
If you have an event type with the "Offer seats" feature toggled, you can have more than one attendee book a specific slot.
[](https://downloads.intercomcdn.com/i/o/1195347848/5997a6b26c8533e1fbc728a5/i1600x900-V3uoAv_cFR4n_tmadtm.png?expires=1736299800\&signature=3e880f4ec92be0e9f00b62c3186f5a5112254e4aa6f64e3231937ad6728c6e72\&req=dSEuE8p6molbUfMW1HO4zeJNgjpqzF5BsxaeJjowKMaEkNLxe6fM%2BvfGX1yJ%0A%2F8HpdrSWHrbCY6y8xIA%3D%0A)
This feature would be useful for all those businesses, classes, seminars etc. that offer "seats" as in attendance spots. Just select the maximum number of seats in your event-type settings and your attendees will be able to book slots multiple times.
# Optimized Slots
Source: https://cal.com/help/event-types/optimized-slots
**Optimized Slots** help you make the most out of your availability by going beyond fixed, predefined start times. Instead of only starting events on the hour or half-hour, Cal.com intelligently adjusts start times to accommodate as many appointments as possible, while still prioritizing clean start times when they're available.
## How It Works
By default, event slots are generated at predefined intervals (for example, every 60 minutes starting on the hour). This means booking options follow a fixed slot grid, not necessarily the exact start of someone’s availability.
That can sometimes cause confusion. For example, if availability starts at 8:45 and the event length is 60 minutes, the first visible slot may appear at 9:00, because the system is aligning to predefined slot start times rather than the earliest possible start time.
Instead of showing slots at odd times like 9:07 or 10:23, Cal.com rounds to familiar times that are easier to remember. This makes your booking page cleaner and more professional for the people scheduling with you.
* 60-minute intervals start on the hour (9:00, 10:00, 11:00...)
* 30-minute intervals start on the hour and half-hour (9:00, 9:30, 10:00...)
* 20-minute intervals start every 20 minutes (9:00, 9:20, 9:40...)
* 15-minute intervals start on quarter hours (9:00, 9:15, 9:30, 9:45...)
* 10-minute intervals start every 10 minutes (9:00, 9:10, 9:20...)
* 5-minute intervals start every 5 minutes (9:00, 9:05, 9:10...)
Optimized Slots adjust this logic so that availability dynamically adapts around conflicts and real open time, helping ensure no usable time is left behind. In practice, this means booking options can better reflect the actual time someone is free, rather than only fixed interval boundaries.
## Example
**Event Setup**
* Event length: 60 minutes
* Availability: 9:00 AM – 11:30 AM
* Busy time: 10:00 AM – 10:15 AM
**Without Optimized Slots**
```text theme={null}
9:00 AM – 10:00 AM
```
**With Optimized Slots**
9:00 AM – 10:00 AM 10:15 AM – 11:15 AM
With Optimized Slots enabled, Cal.com adjusts the start time of your first slot to 10:15 AM after your busy block, allowing you to capture an extra meeting that would otherwise be impossible.
## Why Use Optimized Slots?
* **Maximize availability:** Fit in more appointments throughout the day.
* **Stay flexible:** Avoid wasted gaps caused by short conflicts.
* **Keep it clean:** Still favors standard start times (on the hour/half-hour) when possible.
## How to Enable Optimized Slots
1. Go to your event type.
2. Open **Availability** section of the event setup.
3. Toggle **Optimized Slots** on.
Once enabled, your scheduling automatically adjusts to create the most efficient slot lineup possible.
# Private Links
Source: https://cal.com/help/event-types/private-links
Private Links let you control access to your event types in a secure and flexible way. They are ideal for invite-only sessions, VIP access, pilot programs, or scenarios where you want to limit visibility and usage.
Unlike standard public links, **Private Links are not discoverable on your public booking page** — and can be configured with advanced **expiration rules**.
## Key Features
* **Multiple Private Links per Event Type**
You can create several private links for the same event type — each with its own unique usage rules.
* **Usage-Based Expiry**
Set a private link to automatically expire after it has been used a specific number of times.
*Example: expires after 2 successful bookings.*
* **Date-Based Expiry**
Set a specific expiry date after which the link will no longer be usable.
*Example: valid until August 31, 2025.*
* **Non-Guessable, Secure URLs**
Each private link is generated as a secure, hash-based URL that cannot be guessed or found publicly.
* **Granular Control via Event Type Settings**
All private links are managed per event type under the **Advanced** tab of the event type settings.
## How to Use Private Links
1. **Open an Event Type**
Go to the **Event Types** section in your dashboard and select the one you want to configure.
2. **Go to the Advanced Tab**
Inside the event type settings, switch to the **Advanced** tab.
3. **Create a Private Link**
* Toggle Private Link if it isn't already
* Click **Add Private Link** to add more links
* Click on the settings (gear) icon in front of the private link and define:
* **Number of allowed uses**, or
* **Expiry date**
* Save the private link configuration
* Save the event Type settings to be able to use the link
4. **Share the Link Securely**
Copy and share the generated link only with the intended invitees.
## What to Expect
* If a private link has usage limit, it will expire **after the set number of bookings are made using the link**.
* If a private link has date limit, it will expire **after the set date**.
* Once expired, the link will:
* No longer be accessible
* Show 404 error page if opened
* Private links **do not appear** on your main booking page or directory
* You can **delete** any private link at any time from the same event type settings
* You can **configure** any active private links from the same event type settings
## Use Case Examples
| Use Case | Setup |
| ------------------------------- | ----------------------------------- |
| Run a 5-person beta program | Set usage limit to 5 |
| Offer limited-time consultation | Set expiry date to end of the month |
If you have any questions or need help configuring private links, reach out to our support team — we’re here to help!
# Redirect when accessed without a routing form
Source: https://cal.com/help/event-types/redirect-on-no-routing-form
Send visitors who open an event type directly, without going through a routing form, to a URL you control.
This setting lets you send visitors to a URL of your choice when they open an event type directly instead of arriving through a routing form. It's useful for event types that are only meant to receive traffic that has already been qualified by a routing form, so anyone who lands on the booking page some other way gets pointed to the right place.
#### Useful when:
* You use routing forms to qualify leads and only want qualified traffic to reach a specific event type.
* You want to redirect direct visitors to a marketing page, a general contact form, or a support portal.
* You want to keep a shareable link tidy without exposing a booking page to unqualified traffic.
#### How to enable:
1. Open the event type you want to configure.
2. Go to the **Privacy & security** section under **Policies**.
3. Toggle **Redirect when accessed without routing form**.
4. Enter the URL you want visitors to be sent to.
5. Click **Save** in the top-right corner.
Anyone who opens the event type without a routing form response is now redirected to that URL. Visitors who arrive through a routing form still see the normal booking page.
## Domain restriction for organizations
If the event type belongs to an organization, the redirect URL must use the organization's verified domain. This prevents an event type from being used to send visitors to an unrelated or untrusted site.
The URL's hostname must either:
* Exactly match the verified domain (for example, `acme.com`).
* Be a subdomain of the verified domain (for example, `app.acme.com` or `help.acme.com`).
Any other hostname is rejected when you save, and you'll see a validation error. Personal event types that don't belong to an organization aren't subject to this check.
The verified domain comes from your organization's auto-accept email domain. If you're not sure which domain is verified for your organization, ask your organization admin or check your organization settings.
# Restriction Schedule
Source: https://cal.com/help/event-types/restriction-schedule
Team members with elevated permissions (Admins and Owners) can now add restriction schedules to team event types (Collective and Round Robin). This feature acts as a policy-based filter, ensuring that bookings can only occur within specific time windows—even if team members are available outside those times.
This feature is currently available for teams on request. To enable it for your organization, please contact the Cal.com support team.
## How It Works
A **Restriction Schedule** filters availability by clipping off any time slots that fall *outside* the defined restriction window.
For example:
If your team’s availability is from **7 AM to 6 PM**, and your restriction schedule is set from **8 AM to 5 PM**, then:
* Slots from **7 AM to 8 AM** and **5 PM to 6 PM** will be removed
* Bookings can only happen between **8 AM and 5 PM**
This ensures more control over when your team can be booked—even if they're technically available outside the restricted window.
### Use Booker’s Timezone with Restriction Schedule
By default, the restriction schedule is applied in the timezone of the schedule you selected.
However, you can enable the **“Use Booker Timezone”** option to apply the restriction based on the **invitee’s** local timezone.
Example:
If you want to prevent bookings **before 8 AM local time for the booker**, enable this option and define the restriction as starting from 8 AM.
Now, a booker in New York won’t see slots before 8 AM *New York time*, even if the team is available at that hour in a different timezone.
Restriction Schedules are an additional layer on top of your availability. If you're unavailable on a given day, Cal.com still won’t show any times—Restriction Schedules only further limit what's shown.
## How to Set It Up
1. Open the **Team Event Type**
2. Go to the **Availability** tab
3. Toggle **Add Restriction Schedule** to enable
4. Select the restriction schedule from the dropdown
5. Check the box to **Use Booker’s Timezone** (if desired)
6. Click **Save**
## Example: TCPA Compliance
If your legal team requires you to avoid contacting customers outside **8 AM to 9 PM** in their local time:
* Create a restriction schedule from **8:00 to 21:00**
* Enable **Use Booker Timezone**
This guarantees that Cal.com will only show time slots **within this window**, evaluated in the **booker’s** local timezone—ensuring TCPA compliance.
## Enforcing Company-Wide Booking Rules
Restriction Schedules also allow you to:
* Prevent early morning or late-night bookings (e.g., before 9 AM or after 5 PM)
* Block off **lunch hours globally** (e.g., 12–1 PM)
* Apply **blackout periods** for holidays or internal training sessions
* **Block entire days** using date overrides (the event type will be unbookable on these days for all members)
If you'd like help setting this up or enabling the feature, [reach out to us](https://cal.com/support).
# Round Robin Scheduling
Source: https://cal.com/help/event-types/round-robin
Round robin event types allow you to distribute meetings amongst team members. At the moment, the distribution is based on availability, optimizing all options regardless of individual load. The booking will be assigned to an available host based on weights, priorities or the person least recently booked.
## Underlying Mechanism
The round robin events when **not** using a common schedule offer slots which are formed using the union of all slots available for each round robin host. Once an available slot is chosen by the scheduler, the underlying mechanism of host assignment kicks in. The mechanism has a couple of options:
## Priority Ranking
Every round-robin host has a priority, by default 'medium'. The priority level assigned to a host directly influences their likelihood of being selected for bookings. A higher priority signals a stronger preference, positioning them as a more desirable option for hosting duties. This system ensures that hosts with higher designated priorities are given precedence in the booking process, optimizing the allocation of resources and streamlining event organization.
For instance, if John Doe & Jane Doe are both available in the same slot, but John has a priority **`High`** compared to Jane's priority of **`Medium`**, John will be booked. If several users have the same priority it will choose the least recently booked user.
You have the option to select priority for each host and based on their priority (and availability in the selected slot), the hosts will be booked.
## Weights
Weights are optional and must be enabled to use. They allow you to determine how meetings should be distributed among hosts. When enabled, every host has a default weight of 100%. This means each host should end up with the same number of bookings by default. However, hosts with fewer availabilities can still end up with fewer bookings. Only confirmed bookings count towards past bookings.
For instance, Jane Doe has a weight of 100% and already has 8 bookings while John Doe has a weight of 200% and already has 12 bookings. Assuming both of them are available, the next bookings would go to John Doe until a total of 16 bookings is reached.
**Weight Adjustment**: If new hosts are added to a round-robin event type that has weights enabled, their weights will be adjusted accordingly. New hosts will have their bookings adjusted proportionally to their weight, taking into account the bookings that existing hosts already have. This ensures a fair distribution of bookings when new hosts are added.
### Example:
Existing host 1: 100% weight, 5 bookings Existing host 2: 200% weight, 9 bookings New host: 50% weight
Weight Adjustment = (Bookings of existing hosts / Sum of weights of existing hosts) \* New host weight
Weight Adjustment = 14 / 300 \* 50 = 2.33 The new host will have a weight adjustment of 2 bookings.
## Least Recently Booked
This is the fallback method where the available round robin host who was booked least recently is chosen. If more than one host meets this criteria, one of them is chosen at random.
## Round-Robin Groups
With **Round-Robin Groups**, you can utilize round-robin scheduling even further by organizing hosts into separate groups and having one host from **each group** join the booking. This is useful for scenarios where you need multiple participants from different roles or departments to be part of the same event — for example, a sales representative and a solutions engineer, or a recruiter and a hiring manager.
### How It Works:
**Without Round-Robin Groups**: Only one host from the Round-Robin pool will be selected for the booking.
* **With Round-Robin Groups**:
* You can create multiple Round-Robin groups, each with its own assigned hosts.
* For each booking, **one host from every group** will be selected.
* Within each group, our regular Round-Robin algorithm determines which host is booked next.
* This ensures fair distribution of bookings for all hosts within their group.
You can set it up by clicking on `Add Group` button next to the Round-Robin hosts setup shown in the screenshot below. Make sure you save your changes once done.
## Fixed hosts
If you wish to bring in Collective behavior into round-robin events, it is possible with Cal.com. You can now select which hosts you wish to always attend the meeting whilst the other selected team members who are booked on a round-robin basis.

**Fixed Hosts** are individuals who are consistently present at every meeting.
**Round-Robin Hosts** are members of a group who take turns attending meetings. Rather than everyone in this group attending every meeting, only one person from the group will attend each time.
For tasks like scheduling sales calls or product demos, where you have a pool of people among whom you'd like to distribute meetings, round robin is the perfect choice.
## Reassigning round robin booking
Reassigning a round robin booking lets you transfer an existing meeting from the originally assigned host to a different team member. This is helpful when the assigned host becomes unavailable, needs to hand off the meeting to a colleague, or when you want to rebalance who attends a particular booking. The reassignment can be done directly from your bookings list without cancelling or recreating the meeting.
To reassign a booking, go to the Upcoming bookings page. Click on the three dots next to the event you want to reassign, and in the dropdown menu select Reassign.
### Hide host details in reassignment notifications
By default, when a round robin booking is reassigned, the cancellation email sent to the previous host includes the full booking details, including the new host's information and the meeting link. If you'd rather not share those details with the previous host, you can turn on **Hide host details in reassignment notifications**.
When this setting is enabled, the reassignment email sent to the previous host:
* Hides the **Who** section (team members and new host details).
* Hides the **Where** section (meeting location and video call link).
* Removes attendee and location information from the calendar invite (`.ics`) attachment.
* Still shows a **Reassigned to** line so the previous host knows the booking was handed off.
This setting is available only for round robin event types.
#### How to enable:
* Open the event type settings.
* Go to the **Reschedule** tab.
* Toggle **Hide host details in reassignment notifications**.
* Click **Save** in the top-right corner.
# Setting up location of team events on cal.com
Source: https://cal.com/help/event-types/setup-location
When scheduling a Team Event on [**Cal.com**](https://cal.com/), specifying the location is crucial for ensuring seamless coordination, especially when utilizing video conferencing apps like Zoom, Google Meet, or Microsoft Teams. Here's how it works:
* **Selecting the Location**: While creating a new Team Event, you'll notice a dropdown menu for selecting the event's location. If your event will be conducted using a video conferencing app, choosing "Organizer's default app" from the dropdown is essential.
* **Utilizing Default Video Conferencing Apps**: Video conferencing apps don’t appear in the Location dropdown menu for Team events. However, by selecting "Organizer's default app," you ensure that the appropriate video conferencing link will be generated for the event.
* **Configuring Default Apps**: To ensure smooth operation, all team members assigned to that event type must have the preferred video conferencing app set as their default in the Installed Apps section. This can be done by navigating to: [**https://app.cal.com/apps/installed/conferencing**](https://app.cal.com/apps/installed/conferencing).
* **Generating Meeting Links**: Once all team members have set their preferred app as the default, a meeting link will be automatically generated upon booking the Team Event. For instance, if Zoom is selected as the default app for all members, the event booking will generate a Zoom meeting link.
## Custom host locations for round robin team events
If your team needs to use different conferencing tools for different clients, you can enable **custom host locations** for **round robin team events**. This lets you set a location for each host instead of relying only on **Organizer’s default app**.
When **Enable custom host locations** is turned on, Cal.com shows all hosts assigned to the event type and lets you choose a location for each one individually. You can also use **Set location for all hosts** to apply the same location across the whole host list.
If a selected conferencing app is not installed for a host, Cal.com will show that in the event settings. Until that host connects the app, Cal.com will use the event type’s default location as the fallback.
This is useful when different clients require different meeting platforms, such as **Zoom** or **Microsoft Teams**, but hosts do not all have the same apps connected yet.
Custom host locations are available for **Organizations only**.
# How to split fullname into firstname and lastname in the public booking page
Source: https://cal.com/help/event-types/split-name
By default, Cal.com booking page has a fullname text input field for the scheduler to put their name in. This usually works just fine for most people. However, at times, it is preferable to take the firstname and lastname of the scheduler as separate inputs in the booking form.
Cal.com provides the option to split the fullname input field in the booking form into firstname and lastname. To do that, you can do the following:
Head to the event type settings where you wish to split the fullname into firstname and lastname.
Fill the label and optional placeholder values, and click on **save**.
Remember to click on the **save** button in the event type settings as well.
You're all set!
## How this affects the Booking API requests
Please note that in case of API requests, your usual **responses object**:
```json theme={null}
"responses": { "name": "John Doe", "email": "john.doe@example.com", "location": { "optionValue": "", "value": "Acme Industries" } }
```
will now be updated to allow **name** to be converted into object containing **firstName** and **lastName** as follows:
```json theme={null}
"responses": { "name": { "firstName": "John", "lastName": "Doe" }, "email": "john.doe@example.com", "location": { "optionValue": "", "value": "Acme Industries" } }
```
# Can Cal.com sponsor my open source project?
Source: https://cal.com/help/event-types/sponsor
Cal.com is a commercial open source company and thereby we fully support other open source projects, whether it's commercial or non-commercial. We're friends of many other COSS companies.
## Sponsorship Criteria
* The project should be non-commercial or a commercial open source company with less than \$2M in ARR
* The project should be open source
* Include our "Book us with Cal.com" banner in your footer and link to a Cal.com booking link of your choice
* Include our "Book us with Cal.com" banner in your open source repository's README.md file and link to a Cal.com booking link of your choice
* Add the UTM tag with the format for the banners: ?utm\_source=banner\&utm\_campaign=oss
## HTML Code:
```html theme={null}
```
or
```html theme={null}
```
## How to apply
Please note that we have a limited number of openings for OSS sponsorships each month. If you're interested in applying for a sponsorship for your open source software project, please follow these steps:
* Ensure that you meet all the sponsorship criteria mentioned above.
* Send an email to [peer@cal.com](https://cal.com/help/en/articles/) and explain what you are working on and confirm that you meet all the sponsorship criteria (watch out, Peer may invest a small angel check in your COSS company 👀)
* Explaining why Cal.com's free tier or open core is insufficient for your project
* Include your Cal.com team slug and provide a link to your open source repository in the email.
Please note that sponsorship requests are reviewed on a monthly basis, so allow some time before reaching out for updates. We reserve the right to reject any project at will without reason.
# How to troubleshoot symbolic link issues on Windows
Source: https://cal.com/help/event-types/symbolic-issues
If you're using Cal.com self hosting instance on windows, you might be struggling with Prisma Environment variables not working. One of the reasons why this happens is because by default, symbolic links are disabled on windows OS.
To test the state of symbolic links configuration in your local repo, please run the following command from your root
```bash theme={null}
git config --get core.symlinks
```
This should return **`false`**. If that is the case, you can follow one of the two following methods to enable symbolic links
### Enable symbolic links
Please make sure to open **gitbash** with elevated privileges (Admin) before running the following commands, or they may fail silently and just not work as expected.
### Create a new clone with symbolic links enabled (Recommended)
Please use the following steps to clone the repo with symbolic links:
```bash theme={null}
git clone -c core.symlinks=true https://github.com/calcom/cal.com.git
```
### Enable symbolic links in your existing cloned repo
This is quite tricky, and not the recommended way of troubleshooting this issue. Please use the following steps to troubleshoot:
```
git config core.symlinks true
```
```
git config --get core.symlinks
```
```
git restore packages/prisma/.env
```
# Lock timezone on booking page
Source: https://cal.com/help/event-types/timezone-lock
You can lock the timezone on the booking page to match the organizer's fixed timezone. This is especially useful for in-person events, ensuring that attendees see the event time exactly as scheduled, rather than converting it to their local timezone.
# User-level booking limits
Source: https://cal.com/help/event-types/user-booking-limits
Limit how many times you can be booked across all your event types using per-day, per-week, per-month, or per-year caps.
Booking frequency limits on individual event types let you cap how often a specific event can be booked. **User-level booking limits** go further — they apply a cap across every personal and team event type you host, so you can control your total meeting load in one place.
This setting is found in your **General** settings, not inside an individual event type. It applies to you as a host across all of your event types.
User-level booking limits are available to members of a Cal.com organization. If you do not see the setting in **General**, check with your organization admin or review your plan.
### When to use it
* You want an overall cap on how many meetings you take per day, week, month, or year.
* You host multiple event types and want a single limit that covers all of them.
* You need to protect focused time without adjusting limits on every event type individually.
### How it works
When you enable user-level booking limits, Cal.com checks your total confirmed bookings for the chosen time period before showing a slot as available. If you have already reached your limit, the slot is removed from your booking page so no one can book you.
You can set limits for any combination of these periods:
| Period | What it counts |
| --------- | ------------------------------------------------- |
| Per day | Total confirmed bookings on a single calendar day |
| Per week | Total confirmed bookings within a calendar week |
| Per month | Total confirmed bookings within a calendar month |
| Per year | Total confirmed bookings within a calendar year |
Limits stack — if you set both a daily and a weekly limit, both are enforced. For example, you could allow up to 4 bookings per day but no more than 15 per week.
Higher time-period limits must be greater than or equal to lower ones. For example, your weekly limit cannot be smaller than your daily limit.
### How to set it up
Go to **Settings > General** in your Cal.com dashboard.
Find **Limit booking frequency** and toggle it on.
Choose one or more time periods (per day, per week, per month, per year) and set the maximum number of bookings for each.
Click **Update** to apply your changes.
### How it differs from event-type booking limits
| | User-level booking limits | Event-type booking limits |
| ------------------- | ----------------------------- | ----------------------------------- |
| **Scope** | All your event types combined | One specific event type |
| **Where to set it** | Settings > General | Event type > Limits tab |
| **What it caps** | Your total bookings as a host | Bookings for that single event type |
Both limits are enforced simultaneously. If an event type allows 10 bookings per day but your user-level limit is 5 per day, you will not receive more than 5 bookings total.
# Import Numbers
Source: https://cal.com/help/importing/import-numbers
Learn how to import phone numbers from Twilio for your Cal.ai agent via SIP trunking
## Steps
### 1. Create Elastic SIP Trunking
1. Search "Elastic SIP trunks" on Twilio Console
2. Create the trunk, give it a name, and toggle these settings and click Save
3. Setup termination (this is for outbound)
* Click the **Termination** tab on the sidebar
* The termination SIP URI here is important, we would use it in later steps. You might want to use a localized termination uri that's near your region. You can expand and view your localized uris in your provider's console.
* You can pick the uri something like cal-ai-support-network-02
* For your elastic SIP trunk to accept our outbound request, you need to create a auth with username and password.
* Click on create new credentials list in Authentication section
* Give it a friendly name and enter any username and password and we would need this username and password in the later steps and click save on the Termination page.
4. Setup origination (this is for inbound)
* Click on Origination tab on the sidebar
* Click on Add new Origination URI's button
* Here you will specify SIP server address as the origination SIP URI: `sip:5t4n6j0wnrl.sip.livekit.cloud` and click 'Add'
### 2. Move numbers to Elastic SIP Trunking
You've created the elastic SIP trunk, now you would need to purchase numbers / move existing numbers to this trunk.
* Now go to **Numbers** tab on the sidebar and click on **Add a number** button to purchase / move existing numbers to this trunk.
### 3. Import modal on Cal.com
On Import modal on Cal.com workflow edit page, enter these values:
* Your complete phone number with country code
* Complete Termination URI from the previous steps
* SIP Username and password from the previous steps
* Click on **Create** button to import the number to Cal.com
# How Cal.com Handles Google Calendar Data Privacy
Source: https://cal.com/help/privacy-and-compliance/google-calendar-privacy
### Data We Access: Only Free/Busy Information
Cal.com uses the [Google Calendar Free/Busy API](https://developers.google.com/calendar/api/v3/reference/freebusy/query) to retrieve availability information. This means that we only access data on whether you are free or busy at a given time – no specific event details, titles, locations, or any other personal information is accessed or stored.
### Compliance and Security
We take compliance and security very seriously. For more information on our security practices, please visit [cal.com/security](https://cal.com/security).
### Code Reference
For those interested in seeing exactly how this works, you can view our code on GitHub, where we explicitly do not access any event details.
# Calendar
Source: https://cal.com/help/quick-start/calendar
Here you can find articles on how to connect various calendars to your Cal.com account.
## How to Connect Your Apple Calendar
Connecting your Apple Calendar helps Cal.com check when you're free or busy. This avoids double bookings and ensures new bookings are added to the right calendar.
Follow these steps:
1. **Log in to your Cal.com account**.
* Go to **Settings** and click the [**Calendars**](https://app.cal.com/settings/my-account/calendars) tab.
2. **Add a Calendar**:
* Click **Add Calendar**.
* You’ll be taken to our App Store.
3. **Install the Calendar**:
* Choose **Apple Calendar** and click **Install**.
4. **Log in with Your App-Specific Password**:
* Head over to [https://appleid.apple.com/account/manage](https://appleid.apple.com/account/manage) and generate your app-specific password.
* Paste the password in the password section.
5. **Set Up and Adjust Settings**:
* You’ll see your calendar in the **Installed Calendars** section.
* Select which calendar to check for conflicts.
* Add more calendars if needed.
You're all set! Cal.com will now manage your availability and prevent scheduling
# Complete your onboarding
Source: https://cal.com/help/quick-start/complete-onboarding
Once you create a Cal.com account, you are taken to the onboarding flow, where you'll need to go through the process of setting up some basics to get you up and running.
## Set up your name and timezone
Here all you need to do is enter your full name to be displayed on your booking page, and confirm the Timezone that you're in.

## Connect a calendar
You can connect your Cal.com account with any of your calendars to automatically check for busy times and create new events as they are scheduled. If you wish to connect a calendar at a later stage, you can always click on **I'll connect my calendar later** and it'll skip to the next step.

## Set up your availability
You can set your availability schedule in this step. You can always create or modify your availability at a later stage in the application as well. If you wish you can learn more about [Setting up your availability](https://cal.com/docs/how-to-guides/setting-up-your-availability) or check out the deep dive into the [Availability](https://cal.com/docs/core-features/availability) feature.

## Final profile details
Finally, you can personalize your Cal.com booking link by providing a brief description about yourself and uploading a photograph so the people know who they're booking with.

That's it. You're fully onboarded and all set to start your scheduling journey!
# Create your account
Source: https://cal.com/help/quick-start/create-account
The easiest way to get started with Cal.com is on our website. We offer a generous free tier where you get unlimited scheduling with no limits and all of our features built for individuals, with the option to upgrade to a teams plan for collaboration features.
[Sign up here](https://cal.com/signup) to create your free account.
Most people will do this, but for full data ownership and control over your scheduling, you can [self-host Cal.com](https://cal.com/docs/self-hosting) on your own infrastructure.
To get started, head to [cal.com/signup](https://cal.com/signup), where you'll be able to enter your desired username (the part that comes after cal.com, like cal.com/bailey), your email and a password. Alternatively, you can sign up using your Google account, or using SAML SSO by clicking on the respective buttons.
Please note that if you choose a **premium username**, which is a username that‘s either short or a common name, it costs a monthly fee. This prevents username squatting and ensures that people and brands are often able to get their username without it being taken by someone. You can always start with a non-premium username and then upgrade later on from within the application.
Once you've signed up, you'll go through the new user onboarding flow. Click below to skip to that section of the documentation.
# Customization
Source: https://cal.com/help/quick-start/customization
Cal.com offers customizable appearance baked into the product. You can select from a few options and dictate how your booking pages will look like:
### Theme
Select the theme of your booking pages. You can either force the booking page to be in Light mode or Dark mode, where visitors to your booking page would only ever see the selected mode. Alternatively, you could select the System default (selected by default by Cal.com) where visitors to your website would see the version as per their system default settings (Light or Dark).
### Brand Colors
Select your Brand Color for both light theme and dark theme, which overrides the default brand color of Cal.com in your public booking pages. This adds a custom feel to the booking experience.
You can easily use these in combination with [embed](https://cal.com/docs/core-features/embed) to make the Cal.com embed feel like a part of your website by simply updating these settings to match your website.
# Make a User an Organization Admin
Source: https://cal.com/help/roles/make-user-an-org-admin
A quick guide to making an existing organization member an admin in cal.com.
This guide outlines the process for an **organization admin** to elevate an existing member to an **admin** role.
First, go to your organization's members page. You can access this directly by navigating to `https://app.cal.com/settings/organizations/{org_slug}/members`, where `{org_slug}` is your organization's unique slug. You can do this by clicking on the Members tab in the sidebar.
Locate the user you wish to promote to admin. At the end of their row, click on the **three dots (...)** to open a dropdown menu.
From the dropdown menu, click on the **"Edit"** option. This will open a slide-over panel.
In the slide-over panel, click on **"Edit"** again. This will make the user's details editable. Click on the **"Role"** dropdown menu and select **"Admin"**.
After selecting **"Admin"**, save the changes to promote the user. They will now have administrator privileges within the organization.
# Connect Routing Form Data to Booking Questions
Source: https://cal.com/help/routing/connect-routing-form-to-booking-questions
# How to Connect Routing Form Data to Booking Questions
When using Cal.com's routing forms to direct leads to the appropriate calendar, you might want the information collected in the routing form to be available in the booking details and calendar events. This guide explains how to connect routing form fields with booking questions to ensure data flows seamlessly from initial lead capture to final booking confirmation.
***
## The Problem
Users often face this scenario:
* A routing form collects information from leads (company, department, specific needs, etc.)
* The routing form directs them to the appropriate team member's calendar
* The booking is created, but the original routing form data isn't associated with the booking
* You receive booking notifications without context about how the lead originally found you
This disconnect makes it difficult to:
* Track lead sources and routing effectiveness
* Understand attendee context before meetings
* Maintain complete records of the customer journey
***
## The Solution: Matching Identifiers
Cal.com allows you to connect routing form fields to booking questions using **matching identifiers**. When both the routing form field and booking question use the same identifier, the data automatically flows from the routing form to the booking.
### How It Works
1. **Routing Form Collection**: User fills out routing form with company information
2. **Automatic Transfer**: Data transfers to the booking form using matching identifiers
3. **Booking Association**: Information appears in booking details and can optionally show in calendar events
***
## Step-by-Step Implementation
### Step 1: Set Up Your Routing Form Field
When creating a field in your routing form, note the **identifier** you assign to it.
**Example:**
* **Field Label**: "What company are you with?"
* **Field Identifier**: `company-name`
### Step 2: Create a Matching Booking Question
In your event type's booking questions section:
1. Go to **Advanced** → **Booking Questions**
2. Create a new booking question
3. Use the **exact same identifier** as your routing form field
4. Set the field type to match your routing form field
**Example:**
* **Question**: "Company Name"
* **Identifier**: `company-name` *(must match routing form)*
* **Type**: Text input
* **Required**: Optional (depends on your needs)
### Step 3: Choose Visibility
You have two options for the booking question visibility:
#### Option 1: Hidden Question (Recommended)
* **Visibility**: Hidden
* **Result**: Data flows automatically but doesn't show in calendar event
* **Best for**: Internal tracking and booking details
* **User Experience**: Seamless - no additional form fields for the user
#### Option 2: Visible Question
* **Visibility**: Visible
* **Result**: Data appears in both booking details AND calendar event
* **Best for**: Information needed during the actual meeting
* **User Experience**: User sees pre-filled field they can modify if needed
***
## Complete Example Workflow
### Scenario Setup
You want to track which department a lead is interested in and route them accordingly.
### Routing Form Configuration
```
Field: "Which department do you need help with?"
Options: Sales, Support, Technical
Identifier: department-interest
```
### Booking Question Configuration
```
Question: "Department"
Identifier: department-interest
Type: Select
Options: Sales, Support, Technical
Visibility: Hidden
```
### User Experience
1. **Lead visits routing form** → Selects "Sales"
2. **Gets routed to sales team calendar** → Based on routing rules
3. **Books appointment** → "Sales" is automatically captured
4. **Booking details show** → Department: Sales
5. **You receive notification** → With full context about the lead's interest
***
## Best Practices
### Identifier Naming
* Use descriptive, lowercase identifiers
* Use hyphens for readability
* Keep them consistent across forms
* Examples: `company-name`, `budget-range`, `use-case-type`
### Hidden vs Visible Questions
**Use Hidden Questions When:**
* Information is for internal tracking only
* You want the smoothest user experience
* Data doesn't need to appear in calendar events
**Use Visible Questions When:**
* Information is relevant during the meeting
* You want attendees to be able to modify the data
* The information should appear in calendar event details
### Multiple Field Connections
You can connect multiple routing form fields to booking questions:
```
Routing Form Fields → Booking Questions
company-name → company-name
employee-count → employee-count
budget-range → budget-range
timeline → project-timeline
```
***
## Troubleshooting
### Data Not Transferring
**Check these common issues:**
* ✅ Identifiers match exactly (case-sensitive)
* ✅ Field types are compatible
* ✅ Booking question is properly saved
* ✅ Event type has the booking question configured
### Data Not Appearing in Calendar Event
* Hidden booking questions don't appear in calendar events
* Change question visibility to "Visible" if needed
### User Sees Duplicate Information
* If booking question is visible, user will see the pre-filled data
* This is expected behavior and allows them to modify if needed
By connecting your routing forms to booking questions, you create a seamless lead capture and booking process that maintains context throughout the entire customer journey. This ensures you're always prepared for meetings and can make data-driven improvements to your routing and booking processes.
# Headless Routing
Source: https://cal.com/help/routing/headless-routing
This guide explains how to integrate Cal.com Routing Forms with your existing forms and client applications, enabling seamless data forwarding and dynamic routing decisions.
***
## What is Headless Routing?
Headless Routing allows you to use your own custom forms (on your website, application, or landing pages) while leveraging Cal.com's powerful routing logic. Instead of requiring users to fill out a Cal.com Routing Form directly, you can:
1. Collect data through your own forms
2. Pass that data to Cal.com via URL parameters
3. Let Cal.com handle the routing decision-making
4. Direct users to the appropriate booking flow
This approach provides a **completely seamless user experience** while maintaining centralized routing control within Cal.com.
***
## How It Works
The headless routing flow follows these steps:
1. **User fills out your custom form** on your website or application
2. **Form data is collected** (e.g., name, email, company size, urgency)
3. **Data is forwarded to Cal.com** as URL parameters
4. **Cal.com Routing Form processes** the parameters
5. **User is directed** to the appropriate booking page or outcome(e.g. redirecting to an external webpage or showing a Custom Page with a message)
***
## Implementation Steps
### 1. Create Your Routing Form
First, create a Routing Form in Cal.com with fields that will receive data from your external form:
1. Navigate to [Routing Forms](https://app.cal.com/routing)
2. Create a new Routing Form
3. Add fields that match the data you'll collect:
* Use clear field identifiers (e.g., `firstName`, `lastName`, `email`, `companySize`)
* These identifiers will be used as URL parameter names
4. Configure routing logic based on these fields
### 2. Prepare Your External Form
Your external form should:
* Collect the necessary information
* Match field names to your Routing Form identifiers
* Construct the URL with parameters
### 3. Pass Data via URL Parameters
Construct the headless routing URL with your form data:
```
https://your-org.cal.com/router?form=YOUR_FORM_ID&firstName=John&lastName=Doe&email=john@example.com&companySize=10-100
```
**Important considerations:**
* URL encode special characters (e.g., `+` becomes `%2B`)
* All parameter names must match your Routing Form field identifiers
* The `form` parameter should be the your Routing Form ID that you see on in your Routing Form URL. e.g. for `https://app.cal.com/routing/route-builder/8cfd7889-9043-4e20-9a09-db8e2c9f747c`, the Routing Form ID is `8cfd7889-9043-4e20-9a09-db8e2c9f747c`
***
## Using Attributes for Team Member Routing
Headless routing works seamlessly with Cal.com's attribute-based routing system. This allows you to dynamically route bookings to specific team members based on attributes like:
* **Service type** (e.g., Sales, Support, Technical)
* **Language** preferences
* **Geographic region**
* **Product expertise**
* **Custom attributes** specific to your organization
### How Attribute Routing Works
1. **Set up attributes** in your organization settings
2. **Assign attributes** to team members
3. **Configure your Routing Form** to match fields with attributes
4. **Pass attribute values** via URL parameters from your custom form
For example, if you have a `service` attribute, you can pass it directly:
```
/router?form={FORM_ID}&service=Technical%20Support&email=user@example.com
```
Cal.com will automatically match this to team members who have the "Technical Support" attribute assigned.
**[Learn more about setting up attribute-based routing →](/help/routing/routing-with-attributes)**
## Troubleshooting
### Common Issues
**Parameters not being recognized:**
* Verify field identifiers match exactly
* Check for typos in parameter names
* Ensure proper URL encoding
**Routing not working as expected:**
* Test the Routing Form directly first
* Verify all required fields are included
* Check routing logic configuration
***
## Try It Out
You can experiment with a live example in this [CodeSandbox demo](https://codesandbox.io/p/devbox/headless-router-with-embed-kzjc9s).
***
## Related Resources
* [Routing Forms Overview](/help/routing/routing-overview)
* [Routing with Attributes](/help/routing/routing-with-attributes) - Set up attribute-based team member routing
* [Cal.com Embed Documentation](/help/embedding/adding-embed)
# Routing Overview
Source: https://cal.com/help/routing/routing-overview
# What is Routing in Cal.com?
Routing in Cal.com is a powerful feature that helps individuals, teams, and organizations efficiently distribute meetings to the right event or team members based on predefined rules. Whether you need to balance workload, match leads with the right representatives, or ensure specialized team members handle specific cases, Routing allows you to optimize scheduling with precision and flexibility.
***
## Key Features of Cal.com Routing
### 1. Attribute-Based Routing
One of Cal.com’s standout capabilities is **Attributes**—a feature that allows organizations to tag users with specific attributes and use them in routing logic.
**How It Works:**
* Admins can define attributes such as `Country`, `Language`, `Department`, `Seniority Level`, etc.
* When a booking request is made, routing logic filters the team members based on relevant attributes.
* For example, if a client is looking for a representative in the USA, only users with the `country: USA` attribute will be considered.
This reduces unnecessary scheduling conflicts and ensures meetings are routed to the most relevant team members.
***
### 2. Attribute Weights and Virtual Queues
Instead of relying on the host's weight set within an event type, you can use **attribute weights**. This allows a host to have different weights for each assigned attribute value, providing greater flexibility in distribution. Using attribute weights also enables **virtual queues**, which help balance assigned bookings more effectively.
**How It Works:**
* Admins can enable weights on attributes and assign specific weights to team members based on their attributes.
* If an attribute has weights set, it can be enabled and used on a routing form route.
> **Note:** The event type used in the route must have weights enabled.
#### What Are Virtual Queues?
Virtual queues play an important role in distributing bookings within our **Round Robin** algorithm. Virtual queues are defined by the selected route and the attribute used for weighting on that route.
**Example:**\
If the `Country` attribute is used for weights and a client requests a representative in the USA, the Round Robin algorithm will only consider bookings that match both the same route and the USA attribute. Without virtual queues, all bookings from the event type would be counted, leading to less precise distribution.
***
### 3. Smart Fallback Routing
Cal.com offers **fallback logic** to prevent scheduling failures when routing doesn’t return results. Instead of defaulting to a full team’s Round Robin, Cal.com allows fallback to a **subset of team members** that could be configured per route.
**Use Case Example:**
* If no team members match the requested attributes criteria, instead of loading the entire team’s calendar, fallback team members are used.
***
### 4. Routing via Salesforce
Cal.com allows you to route prospects based on **Salesforce ownership**. Ownership is found via the prospect’s email.
**How It Works:**
* Routing can be based on ownership of the lead, contact, or an account that the prospect belongs to.
* When routing to an account:
* Cal.com searches the account `Website` field against the prospect's email domain. Website values are normalized automatically, so accounts with URLs containing extra paths, ports, or protocols (e.g. `https://www.acme.com/about/`) are still matched correctly.
* If no account is found by website, Cal.com checks the email domains of existing contacts to find the most likely account.
* When multiple accounts match, a [tiebreaker waterfall](/help/apps-and-integrations/salesforce#tiebreaker-waterfall) selects the best candidate. You can enable a [geo tiebreaker](/help/apps-and-integrations/salesforce#geo-tiebreaker) on routing form routes to prefer the account geographically closest to the booker.
* Routing can be based on the account ownership or a [custom user lookup field](/help/apps-and-integrations/salesforce#route-to-custom-lookup-field) on the account (or on a connected object via dot-notation).
***
### 5. Routing trace
Every time Cal.com routes a booking, it records a **routing trace** — a log of the routing decisions that led to the final host assignment. You can view the routing trace from two places:
* **Bookings list** — open the actions menu (three-dot icon) on any booking and select **View routing trace**.
* **Booking detail page** — a **Routing trace** badge appears in the booking details section. Click it to open the full trace.
Routing traces are available for bookings created through routing forms and for bookings routed directly via CRM integrations such as Salesforce. This means you can inspect how Cal.com selected the host even when the booking did not go through a routing form.
Routing traces are visible to organization and team admins. They appear automatically — no additional configuration is required.
***
### 6. Headless Routing
Integrate Cal.com Routing Forms with your existing forms and applications. Headless routing allows you to collect data through your own forms and leverage Cal.com's powerful routing logic via URL parameters.
This method provides a seamless user experience while maintaining centralized routing control within Cal.com.
**[Learn more about Headless Routing →](/help/routing/headless-routing)**
***
## Route actions
Each route in a routing form ends in one of three actions:
* **Event Redirect** — Send the booker to a Cal.com event type (the most common option for team scheduling).
* **External Redirect** — Send the booker to a URL outside Cal.com (for example, a thank-you page or a `mailto:` link).
* **Custom Page Message** — Show a static message on the form instead of redirecting.
### Supported URLs for External Redirect
For security, only the following URL schemes are accepted in the **External Redirect** action:
* `http://`
* `https://`
* `mailto:`
Any other scheme (such as `javascript:`, `data:`, `file:`, or protocol-relative URLs like `//example.com`) is rejected when you save the form. If a previously saved form contains an unsupported redirect URL, that route automatically falls back to a custom page message so the form keeps working safely while you fix it.
If you need to send bookers to an internal tool that uses a custom URL scheme, host a small redirect page on `https://` that forwards to the destination instead of pointing the route directly at the custom scheme.
***
## Why Use Cal.com Routing?
* **Precision Matching:** Ensure meetings are scheduled with the most relevant team member based on attributes.
* **Fail-Safe Logic:** Prevent scheduling dead-ends by configuring fallbacks.
* **Seamless Integration:** Link external forms with Cal.com’s routing logic via URL parameters.
* **Scalable & Efficient:** Reduce calendar clutter and improve scheduling efficiency across teams.
***
## Getting Started with Routing
1. **Define Routing Rules:** Set up rules based on attributes like location, role, or language.
2. **Configure Fallbacks:** Ensure a smooth backup booking process.
3. **Integrate Routing Forms:** Connect client-side forms with URL parameter support.
***
By leveraging Cal.com Routing, organizations can optimize their scheduling workflows, enhance user experience, and ensure the right person is always available at the right time.
# Routing with Round Robin and Attribute Matching
Source: https://cal.com/help/routing/routing-with-attributes
This guide walks you through how to set up a Round Robin Team Event that routes bookings to team members based on attributes using Cal.com's Routing Forms.
Attributes are only available in Organizations Plan and Enterprise Plan
***
## Setting Up a Round Robin Team Event
1. **Ensure a Team exists**
If not already created, go to your organization and create a Team. For example, a team named `Sales` with the slug `sales`.
2. **Create a Round Robin Event Type**
* Create this event under the team you just set up.
* **Important**: Enable the setting `Add all team members, including future members`. This ensures team members are selected dynamically based on attributes.
***
## Creating an Attribute
Attributes let you define filters that team members can be matched against.
1. Go to [Organization Attributes](https://app.cal.com/settings/organizations/attributes)
2. Create one or more attributes.
* For matching use cases, **Multi Select** is a great option—especially when team members might belong to multiple attribute values.
* Example: Create an attribute with the name `Service (Attribute)` to clearly indicate it's used in attribute-based routing.
3. **Assign the attribute** to one or more team members. **This step is critical**.
***
## Setting Up a Routing Form
1. Navigate to [Routing Forms](https://app.cal.com/routing)
2. Create a new Routing Form **under the same team** as your event type.
3. Add fields that you want bookers to fill out.
* It's recommended to include an `Email` field with the identifier `email` to enable integrations with CRMs and contact lookup tools.
* Refer to [this guide](https://cal.com/help/apps-and-integrations/assign-people#option-2-based-on-emails) for more.
4. Create another field that matches the **options** from the attribute you set up.
* The **name and identifier don't have to match** the attribute name.
* Example: A `Service` field with identifier `service`, where the options are identical to those in `Service (Attribute)`.
***
## Connecting the RR Team Event, Attributes, and Routing Form
1. In your Routing Form, go to the **Routing** tab
2. Click `Add a new Route`
3. Link the Routing Form field to the corresponding Attribute
* For example, connect the `Service (Attribute)` to the `Service` field in your Routing Form
4. Click **Test Preview** on the left
* Input a value that exists in both the Routing Form field and the Attribute
* The system should now route the booking to a team member with that value assigned in their attributes
***
## Sending Leads or Visitors to the Router
There are two ways to use the Routing setup for collecting bookings:
### 1. Using the Cal.com Routing Form Public Page
* You can find the public link for your Routing Form in the UI
* The URL will look like:
```
app.cal.com/forms/{FORM_ID}
```
Share this link with your leads or embed it in your site.
### 2. Using Your Own Form with Headless Router (Embed Mode)
If you prefer to design your own form UI but still leverage Cal.com routing:
* Use the Headless Router endpoint:
```
/router?form={FORM_ID}&service=Service%20Type%201&email=jane@example.com
```
* The field identifiers become query params in the URL
* Cal.com will handle the routing and direct the user to the appropriate booking page
This gives you full control over your form UI while keeping Cal.com as the routing engine.
**[Learn more about implementing Headless Routing →](/help/routing/headless-routing)**
***
You’ve now set up a powerful attribute-based Round Robin routing system that integrates seamlessly with your team structure and forms.
# Account lockout
Source: https://cal.com/help/security/account-lockout
Protect user accounts from brute-force attacks with automatic lockout after repeated failed login attempts.
Account lockout automatically locks a user account after **10 consecutive failed login attempts**. This protects accounts from brute-force password attacks and unauthorized access.
This feature is controlled by a feature flag and may not yet be enabled on all instances.
***
## How it works
1. Each time someone enters the wrong password or an incorrect two-factor authentication code, the failed attempt counter increments.
2. After **10 failed attempts**, the account is locked and the user cannot log in.
3. A successful login resets the counter back to zero.
Rate limiting is also applied to failed login attempts so that attackers cannot rapidly trigger a lockout on someone else's account.
***
## What locked users see
When a locked user tries to log in, they see an error indicating their account has been locked. They cannot log in even with the correct password until an admin unlocks the account.
***
## Unlocking a user (admins)
Organization admins can unlock a user from the admin panel:
Navigate to your organization's admin area.
Look for the locked user in the users list or the locked users view.
Select the user and choose **Unlock**. This resets their failed login counter and restores access.
***
## What triggers the counter
The failed attempt counter increments when:
* An incorrect password is entered
* An incorrect two-factor authentication (2FA) code is provided
* An incorrect backup code is used
The counter **does not** increment when:
* The email address does not match any account
* The account is already locked
* Rate limiting has been exceeded for that email
***
## Best practices
* **Enable two-factor authentication** to add an extra layer of security beyond passwords.
* **Use strong, unique passwords** to reduce the risk of brute-force attacks succeeding before lockout kicks in.
* **Monitor locked accounts** regularly in the admin panel. Frequent lockouts for the same user may indicate a targeted attack.
* **Educate your team** so they know to contact an admin if they get locked out, rather than creating a new account.
# Blocklist
Source: https://cal.com/help/security/blocklist
The **Blocklist** helps Organization Admins stop unwanted bookings made with suspicious emails or domains. Organization members can **report** bookings they believe are spam. Reported bookings are **flagged** and **auto-cancelled** (including all future occurrences for recurring events).\
Admins then review these reports at [/admin/privacy](https://app.cal.com/settings/admin/privacy) and decide to **Ignore** or **Block** the email/domain. Admins can also **add blocklist entries directly** without a prior report.
***
## What happens when a booking is reported
1. The booking is marked **Reported**.
2. The booking (and any **future recurrences**) is **automatically cancelled**.
3. The report appears in **Privacy & Security → Blocklist** for System Admin review.
Past occurrences in a recurring series are not retroactively cancelled.
***
## Reviewing reports (Privacy & Security)
For each report the system admins see:
* **Booker email**
* **Who reported it** and **when**
* **Linked booking** (event, host, time)
* **Actions**: **Ignore** or **Block**
### Actions
* **Ignore**: Closes the report. The email/domain isn't added to the blocklist
* **Block** (Email or Domain):
* **Email**: Blocks *that exact* email.
* **Domain**: Blocks *all* addresses at that domain (e.g., `@example.com`).
When **blocked**, **any future booking attempts** are **silently rejected**. The booker is **not** told they’ve been blocked.
***
## Add to Organization Blocklist
From the **Blocklist**:
1. Click **Add to Blocklist**.
2. Choose **Email** or **Domain**.
3. Provide the value and (optionally) a description explaining **reason/notes**.
4. Save.
This immediately activates the block for all users in your organization.
***
## How blocking works (under the hood)
* **Checks run at booking time** against global blocklist and your org’s blocklist.
* **Silent failure**: We do **not** reveal the block to suspected spammers (prevents evasion and harassment).
* **PII safe:** We do \*\*not \*\*reveal the host's PII in such cases.
* **Scope**: Org-wide. A blocked email/domain cannot book **any** user in your org.
***
## Benefits
* **Reduces noise** and protects calendars from spam or harassment.
* **Prevents recurring spam** by shutting down future attempts automatically.
* **Protects host privacy & safety** by avoiding explicit “you’re blocked” notices.
* **Saves time** for admins and hosts; fewer manual cancellations and follow-ups.
* **Organization-wide coverage** ensures consistent enforcement for all members.
***
## Best practices
* **Prefer domain blocks** for obvious throwaway/spam domains; use **email blocks** for one-off bad actors on otherwise legitimate domains.
* **Add a note** when blocking (reason, source). It helps future reviewers.
* **Review regularly**: Clear out resolved reports to keep the queue tidy.
* **Start narrow, widen later**: If unsure, block the email first; escalate to a domain block if you see a pattern.
***
## Permissions & access
* **Who can report**: Any user who receives a suspicious booking.
* **Who can review/block**: **System Admins** (and Owners).
* **Where**: `/admin/privacy` → **Blocklist** .
***
## Unblocking / managing entries
* Navigate to **Blocklist**.
* Find the entry → **Remove**.
* Removing an entry **re-enables** booking attempts from that email/domain.
Removing a block does not restore previously cancelled bookings; those must be recreated if needed.
***
## FAQs
**Q: Will the booker know they were blocked?**\
**A:** No. We intentionally keep it silent to prevent abuse escalation and evasion.
**Q: Can I block subdomains only (e.g., \`@mail.bad.com but not @good.bad.com)?**\
**A:** Use a **domain** entry for the exact domain you want blocked. If you need finer control, prefer **email blocks** or add multiple domain entries.
**Q: Do past recurring instances get cancelled when reported?**\
**A:** We cancel the **reported instance and future occurrences**. Past instances are not retroactively altered.
**Q: Can I import a list of domains?**\
**A:** Add entries individually today. If you need bulk operations, contact support for recommended workflows.
# Report a user
Source: https://cal.com/help/security/report-user
Flag suspicious Cal.com profiles for admin review and manage submitted reports from the Abuse Control panel.
You can report a Cal.com user profile if you believe it violates Cal.com's policies, for example if the profile is used for spam, phishing, impersonation, harassment, or other inappropriate content. Reports go to system admins for review inside the **Abuse Control** panel.
***
## Reporting a profile
The **Report** button appears at the bottom-right of a public profile page (`cal.com/username`), just below the profile card.
Visit the profile you want to report, for example `cal.com/username`. You must be signed in to Cal.com to see the **Report** button.
Select **Report** at the bottom-right of the page.
Pick the reason that best matches the issue:
* **Spam**
* **Phishing**
* **Impersonation**
* **Harassment or abuse**
* **Inappropriate content**
* **Other**
Add a short description if the reason needs extra context (for example, a link to the impersonated account). The description is optional.
Select **Submit**. A toast confirms the report was received.
You can submit only one report against the same user every 24 hours. A second submission within that window returns a friendly error.
### When the Report button is hidden
The **Report** button is intentionally hidden in these cases:
* You are viewing your own profile.
* You are not signed in.
* The profile belongs to a member of an organization (organization admins handle abuse for their members internally).
***
## Reviewing reports (admins)
System admins review submitted reports in the **Reports** tab of the **Abuse Control** panel.
Go to [`/settings/admin/abuse-rules`](https://app.cal.com/settings/admin/abuse-rules).
Select the **Reports** tab, next to **Rules**, **Locked users**, and **Configuration**.
Filter by status (**Pending**, **Reviewed**, **Actioned**, **Dismissed**) or reason, or use the search box to find a specific reported user or reporter.
For any pending row, choose one of the row actions:
* **Mark reviewed** — you've looked at the report but aren't taking further action yet.
* **Dismiss** — the report doesn't warrant action and should be closed.
Once a report reaches a terminal state (**Actioned** or **Dismissed**), the row actions are hidden.
Each row shows the reported user, the reporter, the selected reason, the optional description, the current status, and when the report was created.
***
## Report statuses
| Status | Meaning |
| ------------- | ------------------------------------------------------------------------------------ |
| **Pending** | New report awaiting admin review. |
| **Reviewed** | An admin has looked at the report but hasn't taken further action yet. |
| **Actioned** | An admin acted on the report (for example, the reported user was locked or removed). |
| **Dismissed** | The report was closed without action. |
***
## FAQs
**Q: Does the reported user see who reported them?**\
**A:** No. Reports are only visible to system admins.
**Q: Can I report the same user multiple times?**\
**A:** You can submit one report per user every 24 hours. Additional reports within that window are blocked to prevent abuse of the reporting system.
**Q: Can I report an organization member?**\
**A:** No. Profiles belonging to organization members don't show the **Report** button. Contact the organization's admin or Cal.com support if you need to report abuse from an organization member.
**Q: Can I report a user without being signed in?**\
**A:** No. You must be signed in to submit a report.
# Webhooks
Source: https://cal.com/help/webhooks
Webhooks offer a great way to automate the flow with other apps when invitees schedule, cancel or reschedule events, or when the meeting ends.
The webhook subscription allows you to listen to specific trigger events, such as when a booking has been scheduled, for example. You can always listen to the webhook by providing a custom subscriber URL with your own development work. However, if you wish to trigger automations without any development work, you can use the integration with Zapier which connects Cal.com to your apps.
### Webhook scope levels
Webhooks can be created at multiple levels of scope, each determining which events they apply to:
* **User-level**:
Triggers for all event types owned by the user (excluding team-managed types).
* **Event-type level**:
Triggers only for a specific event type. Useful for fine-grained control.
* **Team-level**:
Applies to team event types (i.e., Collective and Round Robin) within the specified team.
In the case of Managed events, bookings are made on the child event types, not the parent team event. Because of this, team-level webhooks will **not** trigger for managed events unless one of the following is true:
* You create a webhook directly on the parent event type (recommended), or
* You create individual webhooks on the child event types (owned by users).
💡 **Note:**
Users can create webhooks that apply to their own event types, including child events under a managed event, even if a team-level webhook exists.
* **Organization-level**:
Applies to all team event types across all teams within the organization.
### Creating a webhook subscription
To create a new webhook subscription, visit `/settings/developer/webhooks` and proceed to enter the following details:
1. Subscriber URL: The listener URL where the payload will be sent to, when an event trigger is triggered.
The subscriber URL must meet the following requirements:
* **Cal.com SaaS**: Only HTTPS URLs are accepted. HTTP, private/internal IP addresses (e.g., `10.x.x.x`, `192.168.x.x`, `127.0.0.1`), and `localhost` are blocked.
* **Self-hosted**: Both HTTP and HTTPS URLs are accepted, and private IP addresses are allowed for internal webhooks.
* **All environments**: Cloud metadata endpoints (e.g., `169.254.169.254`) and non-HTTP protocols (e.g., `ftp://`, `file://`) are always blocked.
If your subscriber URL does not meet these requirements, the webhook creation request will be rejected with an error.
2. Event triggers: You can decide which triggers specifically to listen to. Currently, we offer listening to `Booking Cancelled`, `Booking Created`, `Booking Rescheduled`, `Booking Rejected`, `Booking Requested`, `Booking Paid`, `Booking Payment Initiated`, `Booking No-Show Updated`, `Meeting Started`, `Meeting Ended`, `Recording Ready`, `Recording Transcription Generated`, `Instant Meeting Created`, `Instant Meeting Accepted`, `Out of Office Created`, `After Hosts Cal Video No-Show`, `After Guests Cal Video No-Show`, `Form Submitted`, `Form Submitted (No Event)`, `Calendar Entry Rejected`, and `Delegation Credential Rotation Required`.
3. Secret: You can provide a secret key with this webhook and then [verify it](/help/docs/core-features/webhooks#verifying-the-authenticity-of-the-received-payload) on the subscriber URL when receiving a payload to confirm if the payload is authentic or adulterated. You can leave it blank, if you don't wish to secure the webhook with a secret key.
4. Custom Payload: You have the option to [customize the payload](/help/docs/core-features/webhooks#adding-a-custom-payload-template) you receive when a subscribed event is triggered.
### Expectations with the triggers
| **Event** | **Triggers When...** |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Booking Created | A new booking is successfully created. |
| Booking Cancelled | A booking is cancelled by the host, attendee, or via API. |
| Booking Rejected | A booking request is explicitly rejected by the host. |
| Booking Requested | A booking requiring confirmation from the host is submitted. |
| Booking Paid | Payment for a booking is completed. |
| Booking Payment Initiated | A payment attempt is initiated (before confirmation). |
| Booking No-Show Updated | A host or attendee is marked as a no-show after the meeting. |
| Meeting Started | At the scheduled start time of the meeting. Uses a [flat payload format](#meeting-started--meeting-ended-flat-format). Automatically cancelled if the booking is cancelled or rescheduled. |
| Meeting Ended | At the scheduled end time of the meeting. Uses a [flat payload format](#meeting-started--meeting-ended-flat-format). Automatically cancelled if the booking is cancelled or rescheduled. |
| Recording Ready | A meeting recording is available and ready to access. |
| Recording Transcription Generated | A transcription of the meeting recording is successfully generated. |
| Instant Meeting Created | An instant (ad-hoc) meeting is created. |
| Instant Meeting Accepted | A host accepts an instant meeting and becomes the organizer. Only fires for the first host to accept. |
| Out of Office Created | A user adds a new Out of Office entry to their availability. |
| After Hosts Cal Video No-Show | The host did not show up to a Cal Video meeting in the first `n` minutes, as set up in the configuration. |
| After Guests Cal Video No-Show | The attendee did not show up to a Cal Video meeting in the first `n` minutes, as set up in the configuration. |
| Form Submitted | A form is submitted as part of a routing form **with** a scheduled event. |
| Form Submitted (No Event) | A form is submitted **without** a scheduled event (form-only flow). |
| Calendar Entry Rejected | An external attendee declines a Cal.com event from their connected Google or Microsoft 365 calendar. |
| Delegation Credential Rotation Required | The client secret for a Microsoft 365 [Delegation Credential](/help/enterprise/delegation-credential-microsoft-365) that has opted out of automatic rotation is approaching expiry (\~14 days out). Organization-level only. |
### Seated event types
For event types with [seats enabled](/help/event-types/offer-seats), the `attendees` array in webhook payloads contains only the attendee associated with the specific seat that triggered the webhook. For example, when a new seat is booked, the webhook includes only that seat's attendee — not all attendees across the entire booking. This applies to all booking-related triggers (`BOOKING_CREATED`, `BOOKING_RESCHEDULED`, etc.).
### Example webhook payloads
Most webhook events use a nested payload format with booking details inside a `payload` object. The `MEETING_STARTED` and `MEETING_ENDED` events use a different flat format where booking fields are at the top level.
#### Booking events (nested format)
Events like `BOOKING_CREATED`, `BOOKING_CANCELLED`, `BOOKING_RESCHEDULED`, and most other triggers use this format:
```json theme={null}
{
"triggerEvent": "BOOKING_CREATED",
"createdAt": "2023-05-24T09:30:00.538Z",
"payload": {
"type": "60min",
"title": "60min between Pro Example and John Doe",
"description": "",
"additionalNotes": "",
"customInputs": {},
"startTime": "2023-05-25T09:30:00Z",
"endTime": "2023-05-25T10:30:00Z",
"organizer": {
"id": 5,
"name": "Pro Example",
"email": "owner@acme.com",
"username": "owner90",
"usernameInOrg": "owner",
"timeZone": "Asia/Kolkata",
"language": {
"locale": "en"
},
"timeFormat": "h:mma"
},
"responses": {
"name": {
"label": "your_name",
"value": "John Doe"
},
"email": {
"label": "email_address",
"value": "john.doe@example.com"
},
"location": {
"label": "location",
"value": {
"optionValue": "",
"value": "inPerson"
}
},
"notes": {
"label": "additional_notes"
},
"guests": {
"label": "additional_guests"
},
"rescheduleReason": {
"label": "reschedule_reason"
}
},
"userFieldsResponses": {},
"attendees": [
{
"email": "john.doe@example.com",
"name": "John Doe",
"timeZone": "Asia/Kolkata",
"language": {
"locale": "en"
}
}
],
"location": "Calcom HQ",
"destinationCalendar": {
"id": 10,
"integration": "apple_calendar",
"externalId": "https://caldav.icloud.com/1234567/calendars/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/",
"userId": 5,
"eventTypeId": null,
"credentialId": 1
},
"hideCalendarNotes": false,
"requiresConfirmation": null,
"eventTypeId": 7,
"seatsShowAttendees": true,
"seatsPerTimeSlot": null,
"uid": "bFJeNb2uX8ANpT3JL5EfXw",
"appsStatus": [
{
"appName": "Apple Calendar",
"type": "apple_calendar",
"success": 1,
"failures": 0,
"errors": [],
"warnings": []
}
],
"eventTitle": "60min",
"eventDescription": "",
"price": 0,
"currency": "usd",
"length": 60,
"bookingId": 91,
"metadata": {},
"status": "ACCEPTED"
}
}
```
#### Meeting started / meeting ended (flat format)
`MEETING_STARTED` and `MEETING_ENDED` webhooks use a flat payload format where booking fields are at the top level alongside `triggerEvent`, rather than nested inside a `payload` object. These webhooks are delivered at the scheduled start and end time of the meeting respectively.
```json theme={null}
{
"triggerEvent": "MEETING_STARTED",
"id": 91,
"uid": "bFJeNb2uX8ANpT3JL5EfXw",
"title": "60min between Pro Example and John Doe",
"description": "",
"startTime": "2023-05-25T09:30:00.000Z",
"endTime": "2023-05-25T10:30:00.000Z",
"location": "https://cal.app/video/abc123",
"status": "ACCEPTED",
"paid": false,
"createdAt": "2023-05-24T09:30:00.538Z",
"updatedAt": "2023-05-24T09:30:00.538Z",
"userId": 5,
"eventTypeId": 7,
"metadata": {},
"responses": {
"name": {
"label": "your_name",
"value": "John Doe"
},
"email": {
"label": "email_address",
"value": "john.doe@example.com"
}
},
"user": {
"email": "owner@acme.com",
"name": "Pro Example",
"username": "owner90",
"timeZone": "Asia/Kolkata",
"locale": "en"
},
"attendees": [
{
"id": 201,
"name": "John Doe",
"email": "john.doe@example.com",
"timeZone": "Asia/Kolkata",
"locale": "en",
"noShow": false
}
],
"payment": [],
"references": [
{
"id": 42,
"type": "daily_video",
"uid": "abc123",
"meetingId": "abc123",
"meetingUrl": "https://cal.app/video/abc123"
}
]
}
```
`MEETING_STARTED` and `MEETING_ENDED` webhooks do not support [custom payload templates](#adding-a-custom-payload-template). They always send the full booking data in the flat format shown above.
If a booking is cancelled or rescheduled before the meeting time, the scheduled `MEETING_STARTED` and `MEETING_ENDED` webhooks for that booking are automatically cancelled.
#### Instant meeting accepted
The `INSTANT_MEETING_ACCEPTED` webhook fires when a host accepts an instant meeting request through the connect-and-join flow. It only triggers for the first host to accept — if another host has already accepted the booking, the webhook is not sent again. This trigger is available for team event types only.
The payload includes the booking `status` (set to `ACCEPTED`), the accepting host as the `organizer` with their locale and time format preferences, the guest `attendees` list, booking `responses`, and a `metadata` object containing the `videoCallUrl` for the meeting.
```json theme={null}
{
"triggerEvent": "INSTANT_MEETING_ACCEPTED",
"createdAt": "2025-04-17T10:01:00.000Z",
"payload": {
"bookingId": 142,
"bookingUid": "aB3kL9mNpQ7rS1tU",
"eventTypeId": 15,
"status": "ACCEPTED",
"title": "Instant meeting between Team and Jane Smith",
"startTime": "2025-04-17T10:00:00.000Z",
"endTime": "2025-04-17T10:30:00.000Z",
"organizer": {
"id": 8,
"name": "Host Example",
"email": "host@example.com",
"username": "host-example",
"timeZone": "America/New_York",
"language": {
"locale": "en"
},
"timeFormat": "h:mma",
"utcOffset": -300
},
"attendees": [
{
"email": "jane.smith@example.com",
"name": "Jane Smith",
"timeZone": "Europe/London",
"language": {
"locale": "en"
},
"utcOffset": 60
}
],
"responses": {
"name": {
"label": "your_name",
"value": "Jane Smith"
},
"email": {
"label": "email_address",
"value": "jane.smith@example.com"
}
},
"location": "integrations:daily",
"metadata": {
"videoCallUrl": "https://cal.app/video/aB3kL9mNpQ7rS1tU"
}
}
}
```
#### Calendar entry rejected
The `CALENDAR_ENTRY_REJECTED` webhook fires when an external attendee declines a Cal.com event from their connected Google Calendar or Microsoft 365 calendar. Cal.com detects the decline during calendar sync and dispatches the webhook once per attendee per booking — duplicate syncs do not re-fire the trigger, so you can rely on it as an at-most-once signal.
Use this trigger when you want to react to attendee declines that happen outside Cal.com, for example to notify the host, update a CRM, or offer the attendee a reschedule link. The webhook resolves subscribers at the user, event type, team, and organization levels, so any matching subscription receives the payload.
The payload uses a flat format with `booking`, `calendarEvent`, and `declinedAttendee` objects at the top level:
```json theme={null}
{
"triggerEvent": "CALENDAR_ENTRY_REJECTED",
"createdAt": "2026-06-18T14:22:00.000Z",
"booking": {
"uid": "aB3kL9mNpQ7rS1tU",
"title": "60min between Pro Example and Jane Smith",
"startTime": "2026-06-20T09:30:00.000Z",
"endTime": "2026-06-20T10:30:00.000Z"
},
"calendarEvent": {
"id": "abc123xyz",
"iCalUID": "abc123xyz@google.com",
"provider": "google_calendar"
},
"declinedAttendee": {
"email": "jane.smith@example.com"
}
}
```
The `provider` field is `google_calendar` or `office365_calendar` depending on where the decline originated.
### Subscriber URL requirements
Cal.com validates webhook subscriber URLs to protect against server-side request forgery (SSRF). The validation rules depend on whether you are using Cal.com Cloud or a self-hosted instance.
**Cal.com Cloud:**
* The subscriber URL must use HTTPS.
* URLs pointing to private or internal IP addresses (such as `10.x.x.x`, `172.16.x.x`, `192.168.x.x`, or `127.0.0.1`) are blocked.
* Cloud metadata endpoints (such as `169.254.169.254`) are blocked.
* Hostnames that resolve to private IP addresses via DNS are also blocked.
**Self-hosted:**
* Both HTTP and HTTPS URLs are accepted, so you can use internal services as webhook targets.
* Private IP addresses are allowed for internal webhooks.
* Cloud metadata endpoints are still blocked for security, since self-hosted instances may run on cloud infrastructure.
If your subscriber URL does not meet these requirements, the webhook creation or update request will fail with a `400` error indicating the URL is not allowed.
### Verifying the authenticity of the received payload
1. Simply add a new **secret key** to your webhook and save.
2. Wait for the webhook to be triggered (event created, cancelled, rescheduled, or meeting ended)
3. Use the **secret key** to create an `hmac`, and update that with the webhook payload received to create an SHA256.
4. Compare the hash received in the header of the webhook `(X-Cal-Signature-256)` with the one created using the **secret key** and the body of the payload. If they don't match, the received payload was adulterated and cannot be trusted.
### Adding a custom payload template
Customizable webhooks are a great way reduce the development effort and in many cases remove the need for a developer to build an additional integration service.
An example of a custom payload template is provided here:
```json theme={null}
{
"content": "A new event has been scheduled",
"type": "{{type}}",
"name": "{{title}}",
"organizer": "{{organizer.name}}",
"booker": "{{attendees.0.name}}"
}
```
where `{{type}}` represents the event type slug and `{{title}}` represents the title of the event type. Note that the variables should be added with a double parenthesis as shown above. Here’s a breakdown of the payload that you would receive via an incoming webhook, with an exhaustive list of all the supported variables provided below:
#### Webhook variable list
| Variable | Type | Description |
| ------------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| triggerEvent | String | The name of the trigger event \[BOOKING\_CREATED, BOOKING\_RESCHEDULED, BOOKING\_CANCELLED, MEETING\_ENDED, BOOKING\_REJECTED, BOOKING\_REQUESTED, BOOKING\_PAYMENT\_INITIATED, BOOKING\_PAID, MEETING\_STARTED, RECORDING\_READY, INSTANT\_MEETING, INSTANT\_MEETING\_ACCEPTED, FORM\_SUBMITTED, CALENDAR\_ENTRY\_REJECTED] |
| createdAt | Datetime | The Time of the webhook |
| type | String | The event type slug |
| title | String | The event type name |
| startTime | Datetime | The event's start time |
| endTime | Datetime | The event's end time |
| description | String | The event's description as described in the event type settings |
| location | String | Location of the event |
| organizer | Organizer | The organizer of the event |
| attendees | Attendee\[] | The event booker & any guests. For [seated event types](/help/event-types/offer-seats), this contains only the attendee for the specific seat that triggered the webhook. |
| uid | String | The UID of the booking |
| rescheduleUid | String | The UID for rescheduling |
| cancellationReason | String | Reason for cancellation |
| rejectionReason | String | Reason for rejection |
| team.name | String | Name of the team booked |
| team.members | String\[] | Members of the team booked |
| metadata | JSON | Contains a metadata of the booking, including the meeting URL (videoCallUrl) in case of Google Meet and Cal Video |
#### Organizer Structure
| Variable | Type | Description |
| ---------------- | ------ | --------------------------------------------------------------------- |
| name | String | Name of the organizer |
| email | Email | Email of the organizer |
| username | String | Global username of the organizer |
| usernameInOrg | String | Username of the organizer within their organization (if applicable) |
| timeZone | String | Timezone of the organizer ("America/New\_York", "Asia/Kolkata", etc.) |
| language?.locale | String | Locale of the organizer ("en", "fr", etc.) |
#### Attendee Structure
| Variable | Type | Description |
| ---------------- | ------ | -------------------------------------------------------------------- |
| name | String | Name of the attendee |
| email | Email | Email of the attendee |
| timeZone | String | Timezone of the attendee ("America/New\_York", "Asia/Kolkata", etc.) |
| language?.locale | String | Locale of the attendee ("en", "fr", etc.) |
# Help Desk
Source: https://cal.com/help/welcome
Welcome to the official Cal.com Help Desk. To help get you started, we've put together a few resources to help you learn about how to use Cal.com.
This resource is for users of Cal.com and not for developers. For any self-hosted installation tutorials, developer docs and API references, please head over to [cal.com/docs](https://cal.com/docs).
We strongly recommend to read the Help Desk when facing an issue or having a question before reaching out to support, but if you feel like your issue cannot be solved with the information provided, please visit [go.cal.com/support](https://go.cal.com/support) or contact [support@cal.com](mailto:support@cal.com) with your issue.
These guides will go into depth on how you can best use the hosted Cal.com for your needs.
## Just getting started?
Head to the Quick Start section to get set up as quickly as possible. We'll breeze through the basics and give you enough to get started on your own.
When starting from scratch without a Cal.com Account
## You can also follow us on Social Media
You can find a lot more information on our social media platforms and contact our team as well.
Watch some getting started videos
Follow for fun, releases, announcements and more
Get access to the full cal.com source code
# Credit System for SMS/Whatsapp workflows
Source: https://cal.com/help/workflows/credits
### What Are Credits Used For?
* Sending SMS messages
* Sending WhatsApp messages
### How Many Credits Do You Get?
* **Enterprise plans**: Unlimited credits. Enterprise organizations are not charged for SMS, WhatsApp, or Cal.ai credit usage.
* **Platform organizations**: Unlimited credits, same as Enterprise.
* **Organizations (non-Enterprise)**: 1000 credits per team member renewed monthly. Additional credits can be purchased in the Organization billing settings.
* **Team Plan**: 750 credits per team member, renewed monthly. Additional credits can be purchased in the team billing settings.
* **Free Users**: No free credits. You can purchase credits in your [Billing Settings](https://app.cal.com/settings/billing).
### How Much Does It Cost to Send Messages?
* **US & Canada**: Free
* **Other Countries**: One credit = \$0.01 and we charge you based on Twilio’s costs per SMS plus an 80% processing fee ([Twilio SMS Pricing](https://www.twilio.com/en-us/sms/pricing/de))
### What Happens If You Run Out of Credits?
* We’ll send warning emails when you're low on credits. For teams, all admins will be notified.
* Once your account or team runs out of credits, SMS and WhatsApp messages will stop immediately. Messages will be sent via email instead.
* Enterprise and Platform organizations are not subject to these limits — their credits are unlimited.
# Cal.com Workflows
Source: https://cal.com/help/workflows/workflowsoverview
Automate messages, actions, and follow-ups for your bookings
## What Are Workflows?
Workflows in Cal.com allow you to automate actions when a specific event happens, such as when a booking is created, canceled, or about to start. This makes it easy to stay on top of communication, send reminders, and reduce manual work.
Each workflow follows a simple logic:\
**Trigger → Action**
* **Trigger**: When something happens (e.g., a new booking)
* **Action**: What should be done (e.g., send an email)
## Example Use Cases
* Send a reminder email and SMS to the attendee 1 hour before the meeting
* Send a post-event follow-up email with a feedback link
* Notify your internal teammate of the meeting details
* Email the organizer if the attendee cancels
## How to Set Up a Workflow
[https://app.cal.com/workflows](https://app.cal.com/workflows)
## Available Triggers
These are the currently available trigger options:
* Before the event starts
* When the event is canceled
* When a new event is booked
* After the event ends
* When event is rescheduled
* When the routing form is submitted
* When the routing form is submitted and no booking is created
* When a booking is rejected (events that require confirmation)
* When booking is requested (events that require confirmatoin)
* When booking payment is initiated
* When booking payment is successful
* When booking no-show is updated
## Available Actions
You can automate actions such as:
* Sending an email to host
* Sending an email to attendees
* Sending an email to a specific email address
* Sending SMS to attendee
* Sending SMS to a specific number
* Send WhatsApp message to attendee
* Send WhatsApp message to a specific number
* Cal.ai - Call attendee using cal.ai voice agent (requires credits)
## Dynamic Text Variables
You can insert dynamic text into your messages using variables. These variables will be replaced with real booking data when the message is sent.
| Variable | Description |
| :------------------------------------------------- | :----------------------------------------------- |
| `{EVENT_NAME}` | The event type name |
| `{EVENT_DATE}` | The event date |
| `{EVENT_TIME}` | The event start time |
| `{EVENT_END_TIME}` | The event end time |
| `{TIMEZONE_VARIABLE}` | The timezone of the person receiving the message |
| `{LOCATION_VARIABLE}` | The location of the event |
| `{ORGANIZER_NAME}` | The organizer’s (host’s) name |
| `{ATTENDEE}` | Full name of the attendee/person booking |
| `{ATTENDEE_FIRST_NAME}` | First name of the attendee |
| `{ATTENDEE_LAST_NAME}` | Last name of the attendee |
| `{ATTENDEE_EMAIL}` | Email address of the attendee |
| `{ADDITIONAL_NOTES_VARIABLE}` | Additional notes submitted during booking |
| `{MEETING_URL}` | The video conference/meeting URL |
| `{CANCEL_URL}` | Link to cancel the booking |
| `{CANCELLATION_REASON}` | Reason provided for cancellation |
| `{RESCHEDULE_URL}` | Link to reschedule the booking |
| `{RESCHEDULE_REASON}` | Reason provided for rescheduling |
| `{RATING_URL_VARIABLE}` | URL to the post-event rating/feedback form |
| `{NO_SHOW_URL_VARIABLE}` | URL to mark/report a no-show |
| `{ATTENDEE_TIMEZONE}` | Attendee's timezone information |
| `{EVENT_START_TIME_IN_ATTENDEE_TIMEZONE_VARIABLE}` | Event start time in attendee’s local timezone |
| `{EVENT_END_TIME_IN_ATTENDEE_TIMEZONE_VARIABLE}` | Event end time in attendee’s local timezone |
***
## Auto-translate for attendees
If you're on an **Organization plan**, you can enable auto-translation for workflow steps that send messages to attendees. When enabled, Cal.com automatically translates your workflow message into the attendee's preferred language before sending.
This works with:
* **Email to attendee** actions
* **SMS to attendee** actions
### How to enable auto-translate
1. Open a workflow and add or edit a step that sends a message to an attendee.
2. Below the message editor, check the **Auto-translate for attendees** checkbox.
3. Once enabled, a note confirms which language your message is written in (your account's default language). This is the source language used for translation.
4. Save the workflow.
When a booking is made, Cal.com detects the attendee's language preference and translates the message content automatically. If the attendee's language matches your source language, no translation is applied.
Auto-translate is only available on **Organization** plans. If you're on a different plan, you'll see an upgrade prompt instead of the checkbox.
***
## Plan Limitations
* **Free Plan**: Can only use the default reminder email (no customization)
* **Team, Organization, and Enterprise Plans**: Full access to create custom workflows with multiple actions and dynamic content
* **Self-hosted Instances**: No restrictions on workflow usage
**Note:** WhatsApp workflows **cannot be customized** on any plan at the moment. They are currently limited to sending a **predetermined default message** only.