# Creates a new attendee
Source: https://cal.com/docs/api-reference/v1/attendees/creates-a-new-attendee
api-reference/v1/openapi-v1.json post /attendees
# Edit an existing attendee
Source: https://cal.com/docs/api-reference/v1/attendees/edit-an-existing-attendee
api-reference/v1/openapi-v1.json patch /attendees/{id}
# Find all attendees
Source: https://cal.com/docs/api-reference/v1/attendees/find-all-attendees
api-reference/v1/openapi-v1.json get /attendees
# Find an attendee
Source: https://cal.com/docs/api-reference/v1/attendees/find-an-attendee
api-reference/v1/openapi-v1.json get /attendees/{id}
# Remove an existing attendee
Source: https://cal.com/docs/api-reference/v1/attendees/remove-an-existing-attendee
api-reference/v1/openapi-v1.json delete /attendees/{id}
# Authentication
Source: https://cal.com/docs/api-reference/v1/authentication
The Cal.com API uses API keys to authenticate requests. You can view and manage your API keys in your settings page under the security tab in Cal.com.
API Keys are under Settings > Security
Test mode secret keys have the prefix `cal_` and live mode secret keys have the prefix `cal_live_`.
Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.
Authentication to the API is performed via URL Query Params. Provide your API key as a query param like: `https://api.cal.com/v1/?apiKey=cal_live_xxxxxx`
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
# Creates a new availability
Source: https://cal.com/docs/api-reference/v1/availabilities/creates-a-new-availability
api-reference/v1/openapi-v1.json post /availabilities
# Edit an existing availability
Source: https://cal.com/docs/api-reference/v1/availabilities/edit-an-existing-availability
api-reference/v1/openapi-v1.json patch /availabilities/{id}
# Find an availability
Source: https://cal.com/docs/api-reference/v1/availabilities/find-an-availability
api-reference/v1/openapi-v1.json get /availabilities/{id}
# Remove an existing availability
Source: https://cal.com/docs/api-reference/v1/availabilities/remove-an-existing-availability
api-reference/v1/openapi-v1.json delete /availabilities/{id}
# Creates a new booking reference
Source: https://cal.com/docs/api-reference/v1/booking-references/creates-a-new-booking-reference
api-reference/v1/openapi-v1.json post /booking-references
# Edit an existing booking reference
Source: https://cal.com/docs/api-reference/v1/booking-references/edit-an-existing-booking-reference
api-reference/v1/openapi-v1.json patch /booking-references/{id}
# Find a booking reference
Source: https://cal.com/docs/api-reference/v1/booking-references/find-a-booking-reference
api-reference/v1/openapi-v1.json get /booking-references/{id}
# Find all booking references
Source: https://cal.com/docs/api-reference/v1/booking-references/find-all-booking-references
api-reference/v1/openapi-v1.json get /booking-references
# Remove an existing booking reference
Source: https://cal.com/docs/api-reference/v1/booking-references/remove-an-existing-booking-reference
api-reference/v1/openapi-v1.json delete /booking-references/{id}
# Booking cancellation
Source: https://cal.com/docs/api-reference/v1/bookings/booking-cancellation
api-reference/v1/openapi-v1.json delete /bookings/{id}/cancel
# Creates a new booking
Source: https://cal.com/docs/api-reference/v1/bookings/creates-a-new-booking
api-reference/v1/openapi-v1.json post /bookings
# Edit an existing booking
Source: https://cal.com/docs/api-reference/v1/bookings/edit-an-existing-booking
api-reference/v1/openapi-v1.json patch /bookings/{id}
# Find a booking
Source: https://cal.com/docs/api-reference/v1/bookings/find-a-booking
api-reference/v1/openapi-v1.json get /bookings/{id}
# Find all Cal video recordings of that booking
Source: https://cal.com/docs/api-reference/v1/bookings/find-all-cal-video-recordings-of-that-booking
api-reference/v1/openapi-v1.json get /bookings/{id}/recordings
# Find all Cal video transcripts of that booking
Source: https://cal.com/docs/api-reference/v1/bookings/find-all-cal-video-transcripts-of-that-booking
api-reference/v1/openapi-v1.json get /bookings/{id}/transcripts
# Find all Cal video transcripts of that recording
Source: https://cal.com/docs/api-reference/v1/bookings/find-all-cal-video-transcripts-of-that-recording
api-reference/v1/openapi-v1.json get /bookings/{id}/transcripts/{recordingId}
# Create a credential record for a user
Source: https://cal.com/docs/api-reference/v1/credentials/create-a-credential-record-for-a-user
api-reference/v1/openapi-v1.json post /credential-sync
# Delete a credential record for a user
Source: https://cal.com/docs/api-reference/v1/credentials/delete-a-credential-record-for-a-user
api-reference/v1/openapi-v1.json delete /credential-sync
# Get all app credentials for a user
Source: https://cal.com/docs/api-reference/v1/credentials/get-all-app-credentials-for-a-user
api-reference/v1/openapi-v1.json get /credential-sync
# Update a credential record for a user
Source: https://cal.com/docs/api-reference/v1/credentials/update-a-credential-record-for-a-user
api-reference/v1/openapi-v1.json patch /credential-sync
# Creates a new destination calendar
Source: https://cal.com/docs/api-reference/v1/destination-calendars/creates-a-new-destination-calendar
api-reference/v1/openapi-v1.json post /destination-calendars
# Edit an existing destination calendar
Source: https://cal.com/docs/api-reference/v1/destination-calendars/edit-an-existing-destination-calendar
api-reference/v1/openapi-v1.json patch /destination-calendars/{id}
# Find a destination calendar
Source: https://cal.com/docs/api-reference/v1/destination-calendars/find-a-destination-calendar
api-reference/v1/openapi-v1.json get /destination-calendars/{id}
# Find all destination calendars
Source: https://cal.com/docs/api-reference/v1/destination-calendars/find-all-destination-calendars
api-reference/v1/openapi-v1.json get /destination-calendars
# Remove an existing destination calendar
Source: https://cal.com/docs/api-reference/v1/destination-calendars/remove-an-existing-destination-calendar
api-reference/v1/openapi-v1.json delete /destination-calendars/{id}
# Errors
Source: https://cal.com/docs/api-reference/v1/errors
Cal.com uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, or something else failed, etc.). Codes in the 5xx range indicate an error with Cal.com's servers (these are rare).
HTTP
Status Code
Summary
200
OK
Everything worked as expected
400
Bad Request
The request was unacceptable, often due to missing a required parameter
401
Unauthorized
No valid API key provided.
402
Request Failed
The parameters were valid but the request failed.
403
Forbidden
The API key doesn't have permissions to perform the request.
404
Not Found
The requested resource doesn't exist.
429
Too Many Requests
Too many requests hit the API too quickly. We recommend an exponential backoff of your requests.
500, 502, 503, 504
erver Errors
Something went wrong on our servers end. (These are rare.)
# Creates a new event type
Source: https://cal.com/docs/api-reference/v1/event-types/creates-a-new-event-type
api-reference/v1/openapi-v1.json post /event-types
# Edit an existing eventType
Source: https://cal.com/docs/api-reference/v1/event-types/edit-an-existing-eventtype
api-reference/v1/openapi-v1.json patch /event-types/{id}
# Find a eventType
Source: https://cal.com/docs/api-reference/v1/event-types/find-a-eventtype
api-reference/v1/openapi-v1.json get /event-types/{id}
# Find all event types
Source: https://cal.com/docs/api-reference/v1/event-types/find-all-event-types
api-reference/v1/openapi-v1.json get /event-types
# Find all event types that belong to teamId
Source: https://cal.com/docs/api-reference/v1/event-types/find-all-event-types-that-belong-to-teamid
api-reference/v1/openapi-v1.json get /teams/{teamId}/event-types
# Remove an existing eventType
Source: https://cal.com/docs/api-reference/v1/event-types/remove-an-existing-eventtype
api-reference/v1/openapi-v1.json delete /event-types/{id}
# Quick start
Source: https://cal.com/docs/api-reference/v1/introduction
## Get your API keys
Your API requests are authenticated using API keys. Any request that doesn't include an API key will return an error.
You can generate an API key from **Settings >** [**Security**](https://app.cal.com/settings/security) within the application. There you will find the API keys section which allows you to generate a key for use.
More information on this can be found in the [Authentication](authentication) page.
## Install the library
The best way to interact with our API is using a good HTTP client like **axios**:
```
# Install via NPM
npm install --save axios
# Install via Yarn
yarn add axios
```
```
# Install via pip
pip install --upgrade requests
```
## Make your first request
To make your first request, send an authenticated request to the event-types endpoint. This will list all of your event types.
Example using `curl`:
```
curl https://api.cal.com/v1/event-types?apiKey=cal_test_xxxxxx
```
## Try our Postman Collection
We've created a small collection of frequently made API calls that you can try in our [Postman Collection](https://www.postman.com/calcom/workspace/cd670dd8-b36d-4aee-8ab2-9044122e30d1/collection/20666831-b92a1d73-bfcc-4a5f-9ef5-cb117d49c904)
# Creates a new membership
Source: https://cal.com/docs/api-reference/v1/memberships/creates-a-new-membership
api-reference/v1/openapi-v1.json post /memberships
# Edit an existing membership
Source: https://cal.com/docs/api-reference/v1/memberships/edit-an-existing-membership
api-reference/v1/openapi-v1.json patch /memberships/{userId}_{teamId}
# Find a membership by userID and teamID
Source: https://cal.com/docs/api-reference/v1/memberships/find-a-membership-by-userid-and-teamid
api-reference/v1/openapi-v1.json get /memberships/{userId}_{teamId}
# Find all memberships
Source: https://cal.com/docs/api-reference/v1/memberships/find-all-memberships
api-reference/v1/openapi-v1.json get /memberships
# Remove an existing membership
Source: https://cal.com/docs/api-reference/v1/memberships/remove-an-existing-membership
api-reference/v1/openapi-v1.json delete /memberships/{userId}_{teamId}
# Find a payment
Source: https://cal.com/docs/api-reference/v1/payments/find-a-payment
api-reference/v1/openapi-v1.json get /payments/{id}
# Find all payments
Source: https://cal.com/docs/api-reference/v1/payments/find-all-payments
api-reference/v1/openapi-v1.json get /payments
# Rate limits
Source: https://cal.com/docs/api-reference/v1/rate-limit
We limit the number of calls you can make over a certain period of time. Rate limits vary and are specified by the following header in all responses:
Header
Description
X-RateLimit-Limit
The maximum number of requests that the consumer is permitted to make.
X-RateLimit-Remaining
The number of requests remaining in the current rate limit window.
X-RateLimit-Reset
The time at which the current rate limit window resets in UTC epoch seconds.
When the rate limit is **exceeded**, an error is returned with the status **"429 Too Many Requests"**:
```json
{
"error": {
"code": "too_many_requests",
"message": "Rate limit exceeded",
}
}
```
# Creates a new schedule
Source: https://cal.com/docs/api-reference/v1/schedules/creates-a-new-schedule
api-reference/v1/openapi-v1.json post /schedules
# Edit an existing schedule
Source: https://cal.com/docs/api-reference/v1/schedules/edit-an-existing-schedule
api-reference/v1/openapi-v1.json patch /schedules/{id}
# Find a schedule
Source: https://cal.com/docs/api-reference/v1/schedules/find-a-schedule
api-reference/v1/openapi-v1.json get /schedules/{id}
# Find all schedules
Source: https://cal.com/docs/api-reference/v1/schedules/find-all-schedules
api-reference/v1/openapi-v1.json get /schedules
# Remove an existing schedule
Source: https://cal.com/docs/api-reference/v1/schedules/remove-an-existing-schedule
api-reference/v1/openapi-v1.json delete /schedules/{id}
# Creates a new selected calendar
Source: https://cal.com/docs/api-reference/v1/selected-calendars/creates-a-new-selected-calendar
api-reference/v1/openapi-v1.json post /selected-calendars
# Edit a selected calendar
Source: https://cal.com/docs/api-reference/v1/selected-calendars/edit-a-selected-calendar
api-reference/v1/openapi-v1.json patch /selected-calendars/{userId}_{integration}_{externalId}
# Find a selected calendar by providing the compoundId(userId_integration_externalId) separated by `_`
Source: https://cal.com/docs/api-reference/v1/selected-calendars/find-a-selected-calendar-by-providing-the-compoundiduserid_integration_externalid-separated-by-`_`
api-reference/v1/openapi-v1.json get /selected-calendars/{userId}_{integration}_{externalId}
# Find all selected calendars
Source: https://cal.com/docs/api-reference/v1/selected-calendars/find-all-selected-calendars
api-reference/v1/openapi-v1.json get /selected-calendars
# Remove a selected calendar
Source: https://cal.com/docs/api-reference/v1/selected-calendars/remove-a-selected-calendar
api-reference/v1/openapi-v1.json delete /selected-calendars/{userId}_{integration}_{externalId}
# Get all bookable slots between a datetime range
Source: https://cal.com/docs/api-reference/v1/slots/get-all-bookable-slots-between-a-datetime-range
api-reference/v1/openapi-v1.json get /slots
# Creates a new team
Source: https://cal.com/docs/api-reference/v1/teams/creates-a-new-team
api-reference/v1/openapi-v1.json post /teams
# Edit an existing team
Source: https://cal.com/docs/api-reference/v1/teams/edit-an-existing-team
api-reference/v1/openapi-v1.json patch /teams/{teamId}
# Find a team
Source: https://cal.com/docs/api-reference/v1/teams/find-a-team
api-reference/v1/openapi-v1.json get /teams/{teamId}
# Find all teams
Source: https://cal.com/docs/api-reference/v1/teams/find-all-teams
api-reference/v1/openapi-v1.json get /teams
# Remove an existing team
Source: https://cal.com/docs/api-reference/v1/teams/remove-an-existing-team
api-reference/v1/openapi-v1.json delete /teams/{teamId}
# Creates a new user
Source: https://cal.com/docs/api-reference/v1/users/creates-a-new-user
api-reference/v1/openapi-v1.json post /users
# Edit an existing user
Source: https://cal.com/docs/api-reference/v1/users/edit-an-existing-user
api-reference/v1/openapi-v1.json patch /users/{userId}
# Find a user, returns your user if regular user.
Source: https://cal.com/docs/api-reference/v1/users/find-a-user-returns-your-user-if-regular-user
api-reference/v1/openapi-v1.json get /users/{userId}
# Find all users
Source: https://cal.com/docs/api-reference/v1/users/find-all-users
api-reference/v1/openapi-v1.json get /users
# Remove an existing user
Source: https://cal.com/docs/api-reference/v1/users/remove-an-existing-user
api-reference/v1/openapi-v1.json delete /users/{userId}
# Creates a new webhook
Source: https://cal.com/docs/api-reference/v1/webhooks/creates-a-new-webhook
api-reference/v1/openapi-v1.json post /webhooks
# Edit an existing webhook
Source: https://cal.com/docs/api-reference/v1/webhooks/edit-an-existing-webhook
api-reference/v1/openapi-v1.json patch /webhooks/{id}
# Find a webhook
Source: https://cal.com/docs/api-reference/v1/webhooks/find-a-webhook
api-reference/v1/openapi-v1.json get /webhooks/{id}
# Find all webhooks
Source: https://cal.com/docs/api-reference/v1/webhooks/find-all-webhooks
api-reference/v1/openapi-v1.json get /webhooks
# Remove an existing hook
Source: https://cal.com/docs/api-reference/v1/webhooks/remove-an-existing-hook
api-reference/v1/openapi-v1.json delete /webhooks/{id}
# Refresh API Key
Source: https://cal.com/docs/api-reference/v2/api-keys/refresh-api-key
api-reference/v2/openapi.json post /v2/api-keys/refresh
Generate a new API key and delete the current one. Provide API key to refresh as a Bearer token in the Authorization header (e.g. "Authorization: Bearer ").
# Cancel a booking
Source: https://cal.com/docs/api-reference/v2/bookings/cancel-a-booking
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/cancel
:bookingUid can be :bookingUid of an usual booking, individual recurrence or recurring booking to cancel all recurrences.
Cancelling seated bookings:
It is possible to cancel specific seat within a booking as an attendee or all of the seats as the host.
1. As an attendee - provide :bookingUid in the request URL `/bookings/:bookingUid/cancel` and seatUid in the request body `{"seatUid": "123-123-123"}` . This will remove this particular attendance from the booking.
2. As the host - host can cancel booking for all attendees aka for every seat. Provide :bookingUid in the request URL `/bookings/:bookingUid/cancel` and cancellationReason in the request body `{"cancellationReason": "Will travel"}` and `Authorization: Bearer token` request header where token is event type owner (host) credential. This will cancel the booking for all attendees.
Cancelling recurring seated bookings:
For recurring seated bookings it is not possible to cancel all of them with 1 call
like with non-seated recurring bookings by providing recurring bookind uid - you have to cancel each recurrence booking by its bookingUid + seatUid.
# Confirm a booking
Source: https://cal.com/docs/api-reference/v2/bookings/confirm-a-booking
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/confirm
The provided authorization header refers to the owner of the booking.
# Create a booking
Source: https://cal.com/docs/api-reference/v2/bookings/create-a-booking
api-reference/v2/openapi.json post /v2/bookings
POST /v2/bookings is used to create regular bookings, recurring bookings and instant bookings. The request bodies for all 3 are almost the same except:
If eventTypeId in the request body is id of a regular event, then regular booking is created.
If it is an id of a recurring event type, then recurring booking is created.
Meaning that the request bodies are equal but the outcome depends on what kind of event type it is with the goal of making it as seamless for developers as possible.
For team event types it is possible to create instant meeting. To do that just pass `"instant": true` to the request body.
The start needs to be in UTC aka if the timezone is GMT+2 in Rome and meeting should start at 11, then UTC time should have hours 09:00 aka without time zone.
Finally, there are 2 ways to book an event type belonging to an individual user:
1. Provide `eventTypeId` in the request body.
2. Provide `eventTypeSlug` and `username` and optionally `organizationSlug` if the user with the username is within an organization.
And 2 ways to book and event type belonging to a team:
1. Provide `eventTypeId` in the request body.
2. Provide `eventTypeSlug` and `teamSlug` and optionally `organizationSlug` if the team with the teamSlug is within an organization.
# Decline a booking
Source: https://cal.com/docs/api-reference/v2/bookings/decline-a-booking
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/decline
The provided authorization header refers to the owner of the booking.
# Get a booking
Source: https://cal.com/docs/api-reference/v2/bookings/get-a-booking
api-reference/v2/openapi.json get /v2/bookings/{bookingUid}
`:bookingUid` can be
1. uid of a normal booking
2. uid of one of the recurring booking recurrences
3. uid of recurring booking which will return an array of all recurring booking recurrences (stored as recurringBookingUid on one of the individual recurrences).
# Get 'Add to Calendar' links for a booking
Source: https://cal.com/docs/api-reference/v2/bookings/get-add-to-calendar-links-for-a-booking
api-reference/v2/openapi.json get /v2/bookings/{bookingUid}/calendar-links
Retrieve calendar links for a booking that can be used to add the event to various calendar services. Returns links for Google Calendar, Microsoft Office, Microsoft Outlook, and a downloadable ICS file.
# Get all bookings
Source: https://cal.com/docs/api-reference/v2/bookings/get-all-bookings
api-reference/v2/openapi.json get /v2/bookings
# Get all the recordings for the booking
Source: https://cal.com/docs/api-reference/v2/bookings/get-all-the-recordings-for-the-booking
api-reference/v2/openapi.json get /v2/bookings/{bookingUid}/recordings
Fetches all the recordings for the booking `:bookingUid`
# Get all the transcripts download links for the booking
Source: https://cal.com/docs/api-reference/v2/bookings/get-all-the-transcripts-download-links-for-the-booking
api-reference/v2/openapi.json get /v2/bookings/{bookingUid}/transcripts
Fetches all the transcripts download links for the booking `:bookingUid`
# Get booking references
Source: https://cal.com/docs/api-reference/v2/bookings/get-booking-references
api-reference/v2/openapi.json get /v2/bookings/{bookingUid}/references
# Mark a booking absence
Source: https://cal.com/docs/api-reference/v2/bookings/mark-a-booking-absence
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/mark-absent
The provided authorization header refers to the owner of the booking.
# Reassign a booking to a specific host
Source: https://cal.com/docs/api-reference/v2/bookings/reassign-a-booking-to-a-specific-host
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/reassign/{userId}
Currently only supports reassigning host for round robin bookings. The provided authorization header refers to the owner of the booking.
# Reassign a booking to auto-selected host
Source: https://cal.com/docs/api-reference/v2/bookings/reassign-a-booking-to-auto-selected-host
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/reassign
Currently only supports reassigning host for round robin bookings. The provided authorization header refers to the owner of the booking.
# Reschedule a booking
Source: https://cal.com/docs/api-reference/v2/bookings/reschedule-a-booking
api-reference/v2/openapi.json post /v2/bookings/{bookingUid}/reschedule
Reschedule a booking or seated booking
# Get meeting details from calendar
Source: https://cal.com/docs/api-reference/v2/cal-unified-calendars/get-meeting-details-from-calendar
api-reference/v2/openapi.json get /v2/calendars/{calendar}/event/{eventUid}
Returns detailed information about a meeting including attendance metrics
# Update meeting details in calendar
Source: https://cal.com/docs/api-reference/v2/cal-unified-calendars/update-meeting-details-in-calendar
api-reference/v2/openapi.json patch /v2/calendars/{calendar}/events/{eventUid}
Updates event information in the specified calendar provider
# Check a calendar connection
Source: https://cal.com/docs/api-reference/v2/calendars/check-a-calendar-connection
api-reference/v2/openapi.json get /v2/calendars/{calendar}/check
# Check an ICS feed
Source: https://cal.com/docs/api-reference/v2/calendars/check-an-ics-feed
api-reference/v2/openapi.json get /v2/calendars/ics-feed/check
# Disconnect a calendar
Source: https://cal.com/docs/api-reference/v2/calendars/disconnect-a-calendar
api-reference/v2/openapi.json post /v2/calendars/{calendar}/disconnect
# Get all calendars
Source: https://cal.com/docs/api-reference/v2/calendars/get-all-calendars
api-reference/v2/openapi.json get /v2/calendars
# Get busy times
Source: https://cal.com/docs/api-reference/v2/calendars/get-busy-times
api-reference/v2/openapi.json get /v2/calendars/busy-times
Get busy times from a calendar. Example request URL is `https://api.cal.com/v2/calendars/busy-times?loggedInUsersTz=Europe%2FMadrid&dateFrom=2024-12-18&dateTo=2024-12-18&calendarsToLoad[0][credentialId]=135&calendarsToLoad[0][externalId]=skrauciz%40gmail.com`
# Get OAuth connect URL
Source: https://cal.com/docs/api-reference/v2/calendars/get-oauth-connect-url
api-reference/v2/openapi.json get /v2/calendars/{calendar}/connect
# Save an ICS feed
Source: https://cal.com/docs/api-reference/v2/calendars/save-an-ics-feed
api-reference/v2/openapi.json post /v2/calendars/ics-feed/save
# Save Apple calendar credentials
Source: https://cal.com/docs/api-reference/v2/calendars/save-apple-calendar-credentials
api-reference/v2/openapi.json post /v2/calendars/{calendar}/credentials
# Save Google or Outlook calendar credentials
Source: https://cal.com/docs/api-reference/v2/calendars/save-google-or-outlook-calendar-credentials
api-reference/v2/openapi.json get /v2/calendars/{calendar}/save
# Conferencing app OAuth callback
Source: https://cal.com/docs/api-reference/v2/conferencing/conferencing-app-oauth-callback
api-reference/v2/openapi.json get /v2/conferencing/{app}/oauth/callback
# Connect your conferencing application
Source: https://cal.com/docs/api-reference/v2/conferencing/connect-your-conferencing-application
api-reference/v2/openapi.json post /v2/conferencing/{app}/connect
# Disconnect your conferencing application
Source: https://cal.com/docs/api-reference/v2/conferencing/disconnect-your-conferencing-application
api-reference/v2/openapi.json delete /v2/conferencing/{app}/disconnect
# Get OAuth conferencing app auth URL
Source: https://cal.com/docs/api-reference/v2/conferencing/get-oauth-conferencing-app-auth-url
api-reference/v2/openapi.json get /v2/conferencing/{app}/oauth/auth-url
# Get your default conferencing application
Source: https://cal.com/docs/api-reference/v2/conferencing/get-your-default-conferencing-application
api-reference/v2/openapi.json get /v2/conferencing/default
# List your conferencing applications
Source: https://cal.com/docs/api-reference/v2/conferencing/list-your-conferencing-applications
api-reference/v2/openapi.json get /v2/conferencing
# Set your default conferencing application
Source: https://cal.com/docs/api-reference/v2/conferencing/set-your-default-conferencing-application
api-reference/v2/openapi.json post /v2/conferencing/{app}/default
# Update destination calendars
Source: https://cal.com/docs/api-reference/v2/destination-calendars/update-destination-calendars
api-reference/v2/openapi.json put /v2/destination-calendars
# Create a private link for an event type
Source: https://cal.com/docs/api-reference/v2/event-types-private-links/create-a-private-link-for-an-event-type
api-reference/v2/openapi.json post /v2/event-types/{eventTypeId}/private-links
# Delete a private link for an event type
Source: https://cal.com/docs/api-reference/v2/event-types-private-links/delete-a-private-link-for-an-event-type
api-reference/v2/openapi.json delete /v2/event-types/{eventTypeId}/private-links/{linkId}
# Get all private links for an event type
Source: https://cal.com/docs/api-reference/v2/event-types-private-links/get-all-private-links-for-an-event-type
api-reference/v2/openapi.json get /v2/event-types/{eventTypeId}/private-links
# Update a private link for an event type
Source: https://cal.com/docs/api-reference/v2/event-types-private-links/update-a-private-link-for-an-event-type
api-reference/v2/openapi.json patch /v2/event-types/{eventTypeId}/private-links/{linkId}
# Create a webhook
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/create-a-webhook
api-reference/v2/openapi.json post /v2/event-types/{eventTypeId}/webhooks
# Delete a webhook
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/delete-a-webhook
api-reference/v2/openapi.json delete /v2/event-types/{eventTypeId}/webhooks/{webhookId}
# Delete all webhooks
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/delete-all-webhooks
api-reference/v2/openapi.json delete /v2/event-types/{eventTypeId}/webhooks
# Get a webhook
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/get-a-webhook
api-reference/v2/openapi.json get /v2/event-types/{eventTypeId}/webhooks/{webhookId}
# Get all webhooks
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/get-all-webhooks
api-reference/v2/openapi.json get /v2/event-types/{eventTypeId}/webhooks
# Update a webhook
Source: https://cal.com/docs/api-reference/v2/event-types-webhooks/update-a-webhook
api-reference/v2/openapi.json patch /v2/event-types/{eventTypeId}/webhooks/{webhookId}
# Create an event type
Source: https://cal.com/docs/api-reference/v2/event-types/create-an-event-type
api-reference/v2/openapi.json post /v2/event-types
# Delete an event type
Source: https://cal.com/docs/api-reference/v2/event-types/delete-an-event-type
api-reference/v2/openapi.json delete /v2/event-types/{eventTypeId}
# Get all event types
Source: https://cal.com/docs/api-reference/v2/event-types/get-all-event-types
api-reference/v2/openapi.json get /v2/event-types
# Get an event type
Source: https://cal.com/docs/api-reference/v2/event-types/get-an-event-type
api-reference/v2/openapi.json get /v2/event-types/{eventTypeId}
# Update an event type
Source: https://cal.com/docs/api-reference/v2/event-types/update-an-event-type
api-reference/v2/openapi.json patch /v2/event-types/{eventTypeId}
# Introduction to API v2
Source: https://cal.com/docs/api-reference/v2/introduction
Introduction to Cal.com API v2 endpoints
## Platform endpoints
Platform customers have the following endpoints available:
1. Endpoints prefixed with "Platform".
2. Endpoints with no prefix e.g "Bookings", "Event Types".
3. If you are at least on the ESSENTIALS plan, then all endpoints prefixed with "Orgs" except "Orgs / Attributes", "Orgs / Attributes / Options" and "Orgs / Teams / Routing forms / Responses".
## Organizations endpoints
Organizations customers have all the endpoints except the ones prefixed with "Platform" and "Teams" and "Orgs / Orgs" because
children organizations are only allowed in the platform plan right now.
## Teams endpoints
Teams customers have all the endpoints except the ones prefixed with "Platform" and "Orgs".
## Authentication
The Cal.com API has 3 authentication methods:
1. API key
2. Platform OAuth client credentials
3. Managed user access token
If you are a platform customer you don't need an API key and must instead use OAuth credentials or a managed user access token. We cover when to use which below.
### 1. API key
You can view and manage your API keys in your settings page under the security tab in Cal.com.
API Keys are under Settings > Security
Test mode secret keys have the prefix `cal_` and live mode secret keys have the prefix `cal_live_`.
Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.
Authentication to the API is performed via the Authorization header. For example, the request would go something like:
```
'Authorization': 'Bearer YOUR_API_KEY'
```
in your request header.
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
### 2. OAuth client credentials
You need to use OAuth credentials when:
1. Managing managed users [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user)
2. Creating OAuth client webhooks [API reference](https://cal.com/docs/api-reference/v2/platform-webhooks/create-a-webhook)
3. Refreshing tokens of a managed user [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens)
4. Teams related endpoints: Managing organization teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team), adding managed users as members to teams [API reference](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership), creating team event types [API reference](https://cal.com/docs/api-reference/v2/orgs-event-types/create-an-event-type).
OAuth credentials can be accessed in the platform dashboard [https://app.cal.com/settings/platform](https://app.cal.com/settings/platform) after you have created an OAuth client. Each one has an ID and secret. You then need to pass them as request headers:
1. `x-cal-client-id` - ID of the OAuth client.
2. `x-cal-secret-key` - secret of the OAuth client.
### 3. Managed user access token
After you create a managed user you will receive its access and refresh tokens. The response also includes managed user's id, so we recommend you to add new properties to your users table calAccessToken, calRefreshToken and calManagedUserId to store this information.
You need to use access token when managing managed user's:
1. Schedules [API reference](https://cal.com/docs/api-reference/v2/schedules/create-a-schedule)
2. Event types [API reference](https://cal.com/docs/api-reference/v2/event-types/create-an-event-type)
3. Bookings - some endpoints like creating a booking is public, but some like getting all managed user's bookings require managed user's access token [API reference](https://cal.com/docs/api-reference/v2/bookings/get-all-bookings)
It is passed as an authorization bearer request header Authorization: Bearer \.
Validity period: access tokens are valid for 60 minutes and refresh tokens for 1 year, and tokens can be refreshed using the refresh endpoint [API reference](https://cal.com/docs/api-reference/v2/oauth/post-v2oauth-refresh). After refreshing you will receive the new access and refresh tokens that you have to store in your database.
Recovering tokens: if you ever lose managed user's access or refresh tokens, you can force refresh them using the OAuth client credentials and store them in your database [API reference](https://cal.com/docs/api-reference/v2/platform-managed-users/force-refresh-tokens).
# Create an organization within an organization
Source: https://cal.com/docs/api-reference/v2/managed-orgs/create-an-organization-within-an-organization
api-reference/v2/openapi.json post /v2/organizations/{orgId}/organizations
Requires the user to have at least the 'ORG_ADMIN' role within the organization. Additionally, for platform, the plan must be 'SCALE' or higher to access this endpoint.
# Delete an organization within an organization
Source: https://cal.com/docs/api-reference/v2/managed-orgs/delete-an-organization-within-an-organization
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/organizations/{managedOrganizationId}
Requires the user to have at least the 'ORG_ADMIN' role within the organization. Additionally, for platform, the plan must be 'SCALE' or higher to access this endpoint.
# Get all organizations within an organization
Source: https://cal.com/docs/api-reference/v2/managed-orgs/get-all-organizations-within-an-organization
api-reference/v2/openapi.json get /v2/organizations/{orgId}/organizations
Requires the user to have at least the 'ORG_ADMIN' role within the organization. Additionally, for platform, the plan must be 'SCALE' or higher to access this endpoint.
# Get an organization within an organization
Source: https://cal.com/docs/api-reference/v2/managed-orgs/get-an-organization-within-an-organization
api-reference/v2/openapi.json get /v2/organizations/{orgId}/organizations/{managedOrganizationId}
Requires the user to have at least the 'ORG_ADMIN' role within the organization. Additionally, for platform, the plan must be 'SCALE' or higher to access this endpoint.
# Update an organization within an organization
Source: https://cal.com/docs/api-reference/v2/managed-orgs/update-an-organization-within-an-organization
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/organizations/{managedOrganizationId}
Requires the user to have at least the 'ORG_ADMIN' role within the organization. Additionally, for platform, the plan must be 'SCALE' or higher to access this endpoint.
# Get my profile
Source: https://cal.com/docs/api-reference/v2/me/get-my-profile
api-reference/v2/openapi.json get /v2/me
# Update my profile
Source: https://cal.com/docs/api-reference/v2/me/update-my-profile
api-reference/v2/openapi.json patch /v2/me
# Create an OAuth client
Source: https://cal.com/docs/api-reference/v2/oauth-clients/create-an-oauth-client
api-reference/v2/openapi.json post /v2/oauth-clients
# Delete an OAuth client
Source: https://cal.com/docs/api-reference/v2/oauth-clients/delete-an-oauth-client
api-reference/v2/openapi.json delete /v2/oauth-clients/{clientId}
# Get all OAuth clients
Source: https://cal.com/docs/api-reference/v2/oauth-clients/get-all-oauth-clients
api-reference/v2/openapi.json get /v2/oauth-clients
# Get an OAuth client
Source: https://cal.com/docs/api-reference/v2/oauth-clients/get-an-oauth-client
api-reference/v2/openapi.json get /v2/oauth-clients/{clientId}
# Update an OAuth client
Source: https://cal.com/docs/api-reference/v2/oauth-clients/update-an-oauth-client
api-reference/v2/openapi.json patch /v2/oauth-clients/{clientId}
# Get list of verified emails of an org team
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/get-list-of-verified-emails-of-an-org-team
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/verified-resources/emails
# Get list of verified phone numbers of an org team
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/get-list-of-verified-phone-numbers-of-an-org-team
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/verified-resources/phones
# Get verified email of an org team by id
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/get-verified-email-of-an-org-team-by-id
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/verified-resources/emails/{id}
# Get verified phone number of an org team by id
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/get-verified-phone-number-of-an-org-team-by-id
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/verified-resources/phones/{id}
# Request email verification code
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/request-email-verification-code
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/verified-resources/emails/verification-code/request
Sends a verification code to the email
# Request phone number verification code
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/request-phone-number-verification-code
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/verified-resources/phones/verification-code/request
Sends a verification code to the phone number
# Verify a phone number for an org team
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/verify-a-phone-number-for-an-org-team
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/verified-resources/phones/verification-code/verify
Use code to verify a phone number
# Verify an email for an org team
Source: https://cal.com/docs/api-reference/v2/organization-team-verified-resources/verify-an-email-for-an-org-team
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/verified-resources/emails/verification-code/verify
Use code to verify an email
# Assign an attribute to a user
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/assign-an-attribute-to-a-user
api-reference/v2/openapi.json post /v2/organizations/{orgId}/attributes/options/{userId}
# Create an attribute option
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/create-an-attribute-option
api-reference/v2/openapi.json post /v2/organizations/{orgId}/attributes/{attributeId}/options
# Delete an attribute option
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/delete-an-attribute-option
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/attributes/{attributeId}/options/{optionId}
# Get all assigned attribute options by attribute ID
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/get-all-assigned-attribute-options-by-attribute-id
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes/{attributeId}/options/assigned
# Get all assigned attribute options by attribute slug
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/get-all-assigned-attribute-options-by-attribute-slug
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes/slugs/{attributeSlug}/options/assigned
# Get all attribute options
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/get-all-attribute-options
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes/{attributeId}/options
# Get all attribute options for a user
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/get-all-attribute-options-for-a-user
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes/options/{userId}
# Unassign an attribute from a user
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/unassign-an-attribute-from-a-user
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/attributes/options/{userId}/{attributeOptionId}
# Update an attribute option
Source: https://cal.com/docs/api-reference/v2/orgs-attributes-options/update-an-attribute-option
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/attributes/{attributeId}/options/{optionId}
# Create an attribute
Source: https://cal.com/docs/api-reference/v2/orgs-attributes/create-an-attribute
api-reference/v2/openapi.json post /v2/organizations/{orgId}/attributes
# Delete an attribute
Source: https://cal.com/docs/api-reference/v2/orgs-attributes/delete-an-attribute
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/attributes/{attributeId}
# Get all attributes
Source: https://cal.com/docs/api-reference/v2/orgs-attributes/get-all-attributes
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes
# Get an attribute
Source: https://cal.com/docs/api-reference/v2/orgs-attributes/get-an-attribute
api-reference/v2/openapi.json get /v2/organizations/{orgId}/attributes/{attributeId}
# Update an attribute
Source: https://cal.com/docs/api-reference/v2/orgs-attributes/update-an-attribute
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/attributes/{attributeId}
# Get organization bookings
Source: https://cal.com/docs/api-reference/v2/orgs-bookings/get-organization-bookings
api-reference/v2/openapi.json get /v2/organizations/{orgId}/bookings
# Save delegation credentials for your organization
Source: https://cal.com/docs/api-reference/v2/orgs-delegation-credentials/save-delegation-credentials-for-your-organization
api-reference/v2/openapi.json post /v2/organizations/{orgId}/delegation-credentials
# Update delegation credentials of your organization
Source: https://cal.com/docs/api-reference/v2/orgs-delegation-credentials/update-delegation-credentials-of-your-organization
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/delegation-credentials/{credentialId}
# Create a membership
Source: https://cal.com/docs/api-reference/v2/orgs-memberships/create-a-membership
api-reference/v2/openapi.json post /v2/organizations/{orgId}/memberships
# Delete a membership
Source: https://cal.com/docs/api-reference/v2/orgs-memberships/delete-a-membership
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/memberships/{membershipId}
# Get a membership
Source: https://cal.com/docs/api-reference/v2/orgs-memberships/get-a-membership
api-reference/v2/openapi.json get /v2/organizations/{orgId}/memberships/{membershipId}
# Get all memberships
Source: https://cal.com/docs/api-reference/v2/orgs-memberships/get-all-memberships
api-reference/v2/openapi.json get /v2/organizations/{orgId}/memberships
# Update a membership
Source: https://cal.com/docs/api-reference/v2/orgs-memberships/update-a-membership
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/memberships/{membershipId}
# Create routing form response and get available slots
Source: https://cal.com/docs/api-reference/v2/orgs-routing-forms/create-routing-form-response-and-get-available-slots
api-reference/v2/openapi.json post /v2/organizations/{orgId}/routing-forms/{routingFormId}/responses
# Get organization routing forms
Source: https://cal.com/docs/api-reference/v2/orgs-routing-forms/get-organization-routing-forms
api-reference/v2/openapi.json get /v2/organizations/{orgId}/routing-forms
# Get routing form responses
Source: https://cal.com/docs/api-reference/v2/orgs-routing-forms/get-routing-form-responses
api-reference/v2/openapi.json get /v2/organizations/{orgId}/routing-forms/{routingFormId}/responses
# Update routing form response
Source: https://cal.com/docs/api-reference/v2/orgs-routing-forms/update-routing-form-response
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/routing-forms/{routingFormId}/responses/{responseId}
# Get all schedules
Source: https://cal.com/docs/api-reference/v2/orgs-schedules/get-all-schedules
api-reference/v2/openapi.json get /v2/organizations/{orgId}/schedules
# Get booking references
Source: https://cal.com/docs/api-reference/v2/orgs-teams-bookings/get-booking-references
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/bookings/{bookingUid}/references
# Get organization team bookings
Source: https://cal.com/docs/api-reference/v2/orgs-teams-bookings/get-organization-team-bookings
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/bookings
# Connect your conferencing application to a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/connect-your-conferencing-application-to-a-team
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/connect
# Disconnect team conferencing application
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/disconnect-team-conferencing-application
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/disconnect
# Get OAuth conferencing app's auth URL for a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/get-oauth-conferencing-apps-auth-url-for-a-team
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/oauth/auth-url
# Get team default conferencing application
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/get-team-default-conferencing-application
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/conferencing/default
# List team conferencing applications
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/list-team-conferencing-applications
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/conferencing
# Save conferencing app OAuth credentials
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/save-conferencing-app-oauth-credentials
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/oauth/callback
# Set team default conferencing application
Source: https://cal.com/docs/api-reference/v2/orgs-teams-conferencing/set-team-default-conferencing-application
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/default
# Create a private link for a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types-private-links/create-a-private-link-for-a-team-event-type
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}/private-links
# Delete a private link for a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types-private-links/delete-a-private-link-for-a-team-event-type
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}/private-links/{linkId}
# Get all private links for a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types-private-links/get-all-private-links-for-a-team-event-type
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}/private-links
# Update a private link for a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types-private-links/update-a-private-link-for-a-team-event-type
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}/private-links/{linkId}
# Create a phone call
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/create-a-phone-call
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}/create-phone-call
# Create an event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/create-an-event-type
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/event-types
# Delete a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/delete-a-team-event-type
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}
# Get all team event types
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/get-all-team-event-types
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/event-types
# Get an event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/get-an-event-type
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}
# Get team event types
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/get-team-event-types
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/event-types
# Update a team event type
Source: https://cal.com/docs/api-reference/v2/orgs-teams-event-types/update-a-team-event-type
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}/event-types/{eventTypeId}
# Create a membership
Source: https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/memberships
# Delete a membership
Source: https://cal.com/docs/api-reference/v2/orgs-teams-memberships/delete-a-membership
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}/memberships/{membershipId}
# Get a membership
Source: https://cal.com/docs/api-reference/v2/orgs-teams-memberships/get-a-membership
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/memberships/{membershipId}
# Get all memberships
Source: https://cal.com/docs/api-reference/v2/orgs-teams-memberships/get-all-memberships
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/memberships
# Update a membership
Source: https://cal.com/docs/api-reference/v2/orgs-teams-memberships/update-a-membership
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}/memberships/{membershipId}
# Create routing form response and get available slots
Source: https://cal.com/docs/api-reference/v2/orgs-teams-routing-forms-responses/create-routing-form-response-and-get-available-slots
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/routing-forms/{routingFormId}/responses
# Get organization team routing form responses
Source: https://cal.com/docs/api-reference/v2/orgs-teams-routing-forms-responses/get-organization-team-routing-form-responses
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/routing-forms/{routingFormId}/responses
# Update routing form response
Source: https://cal.com/docs/api-reference/v2/orgs-teams-routing-forms-responses/update-routing-form-response
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}/routing-forms/{routingFormId}/responses/{responseId}
# Get team routing forms
Source: https://cal.com/docs/api-reference/v2/orgs-teams-routing-forms/get-team-routing-forms
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/routing-forms
# Get all team member schedules
Source: https://cal.com/docs/api-reference/v2/orgs-teams-schedules/get-all-team-member-schedules
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/schedules
# Check team Stripe connection
Source: https://cal.com/docs/api-reference/v2/orgs-teams-stripe/check-team-stripe-connection
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/stripe/check
# Get Stripe connect URL for a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams-stripe/get-stripe-connect-url-for-a-team
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/stripe/connect
# Save Stripe credentials
Source: https://cal.com/docs/api-reference/v2/orgs-teams-stripe/save-stripe-credentials
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/stripe/save
# Get schedules of a team member
Source: https://cal.com/docs/api-reference/v2/orgs-teams-users-schedules/get-schedules-of-a-team-member
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/users/{userId}/schedules
# Create organization team workflow
Source: https://cal.com/docs/api-reference/v2/orgs-teams-workflows/create-organization-team-workflow
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams/{teamId}/workflows
# Delete organization team workflow
Source: https://cal.com/docs/api-reference/v2/orgs-teams-workflows/delete-organization-team-workflow
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}/workflows/{workflowId}
# Get organization team workflow
Source: https://cal.com/docs/api-reference/v2/orgs-teams-workflows/get-organization-team-workflow
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/workflows/{workflowId}
# Get organization team workflows
Source: https://cal.com/docs/api-reference/v2/orgs-teams-workflows/get-organization-team-workflows
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}/workflows
# Update organization team workflow
Source: https://cal.com/docs/api-reference/v2/orgs-teams-workflows/update-organization-team-workflow
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}/workflows/{workflowId}
# Create a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team
api-reference/v2/openapi.json post /v2/organizations/{orgId}/teams
# Delete a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams/delete-a-team
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/teams/{teamId}
# Get a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams/get-a-team
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/{teamId}
# Get all teams
Source: https://cal.com/docs/api-reference/v2/orgs-teams/get-all-teams
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams
# Get teams membership for user
Source: https://cal.com/docs/api-reference/v2/orgs-teams/get-teams-membership-for-user
api-reference/v2/openapi.json get /v2/organizations/{orgId}/teams/me
# Update a team
Source: https://cal.com/docs/api-reference/v2/orgs-teams/update-a-team
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/teams/{teamId}
# Get all bookings for an organization user
Source: https://cal.com/docs/api-reference/v2/orgs-users-bookings/get-all-bookings-for-an-organization-user
api-reference/v2/openapi.json get /v2/organizations/{orgId}/users/{userId}/bookings
# Create an out-of-office entry for a user
Source: https://cal.com/docs/api-reference/v2/orgs-users-ooo/create-an-out-of-office-entry-for-a-user
api-reference/v2/openapi.json post /v2/organizations/{orgId}/users/{userId}/ooo
# Delete an out-of-office entry for a user
Source: https://cal.com/docs/api-reference/v2/orgs-users-ooo/delete-an-out-of-office-entry-for-a-user
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/users/{userId}/ooo/{oooId}
# Get all out-of-office entries for a user
Source: https://cal.com/docs/api-reference/v2/orgs-users-ooo/get-all-out-of-office-entries-for-a-user
api-reference/v2/openapi.json get /v2/organizations/{orgId}/users/{userId}/ooo
# Get all out-of-office entries for organization users
Source: https://cal.com/docs/api-reference/v2/orgs-users-ooo/get-all-out-of-office-entries-for-organization-users
api-reference/v2/openapi.json get /v2/organizations/{orgId}/ooo
# Update an out-of-office entry for a user
Source: https://cal.com/docs/api-reference/v2/orgs-users-ooo/update-an-out-of-office-entry-for-a-user
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/users/{userId}/ooo/{oooId}
# Create a schedule
Source: https://cal.com/docs/api-reference/v2/orgs-users-schedules/create-a-schedule
api-reference/v2/openapi.json post /v2/organizations/{orgId}/users/{userId}/schedules
# Delete a schedule
Source: https://cal.com/docs/api-reference/v2/orgs-users-schedules/delete-a-schedule
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/users/{userId}/schedules/{scheduleId}
# Get a schedule
Source: https://cal.com/docs/api-reference/v2/orgs-users-schedules/get-a-schedule
api-reference/v2/openapi.json get /v2/organizations/{orgId}/users/{userId}/schedules/{scheduleId}
# Get all schedules
Source: https://cal.com/docs/api-reference/v2/orgs-users-schedules/get-all-schedules
api-reference/v2/openapi.json get /v2/organizations/{orgId}/users/{userId}/schedules
# Update a schedule
Source: https://cal.com/docs/api-reference/v2/orgs-users-schedules/update-a-schedule
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/users/{userId}/schedules/{scheduleId}
# Create a user
Source: https://cal.com/docs/api-reference/v2/orgs-users/create-a-user
api-reference/v2/openapi.json post /v2/organizations/{orgId}/users
# Delete a user
Source: https://cal.com/docs/api-reference/v2/orgs-users/delete-a-user
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/users/{userId}
# Get all users
Source: https://cal.com/docs/api-reference/v2/orgs-users/get-all-users
api-reference/v2/openapi.json get /v2/organizations/{orgId}/users
# Update a user
Source: https://cal.com/docs/api-reference/v2/orgs-users/update-a-user
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/users/{userId}
# Create a webhook
Source: https://cal.com/docs/api-reference/v2/orgs-webhooks/create-a-webhook
api-reference/v2/openapi.json post /v2/organizations/{orgId}/webhooks
# Delete a webhook
Source: https://cal.com/docs/api-reference/v2/orgs-webhooks/delete-a-webhook
api-reference/v2/openapi.json delete /v2/organizations/{orgId}/webhooks/{webhookId}
# Get a webhook
Source: https://cal.com/docs/api-reference/v2/orgs-webhooks/get-a-webhook
api-reference/v2/openapi.json get /v2/organizations/{orgId}/webhooks/{webhookId}
# Get all webhooks
Source: https://cal.com/docs/api-reference/v2/orgs-webhooks/get-all-webhooks
api-reference/v2/openapi.json get /v2/organizations/{orgId}/webhooks
# Update a webhook
Source: https://cal.com/docs/api-reference/v2/orgs-webhooks/update-a-webhook
api-reference/v2/openapi.json patch /v2/organizations/{orgId}/webhooks/{webhookId}
# Create a managed user
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user
api-reference/v2/openapi.json post /v2/oauth-clients/{clientId}/users
# Delete a managed user
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/delete-a-managed-user
api-reference/v2/openapi.json delete /v2/oauth-clients/{clientId}/users/{userId}
# Force refresh tokens
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/force-refresh-tokens
api-reference/v2/openapi.json post /v2/oauth-clients/{clientId}/users/{userId}/force-refresh
If you have lost managed user access or refresh token, then you can get new ones by using OAuth credentials. Access token is valid for 60 minutes and refresh token for 1 year. Make sure to store them in your database, for example, in your User database model `calAccessToken` and `calRefreshToken` fields.
Response also contains `accessTokenExpiresAt` and `refreshTokenExpiresAt` fields, but if you decode the jwt token the payload will contain `clientId` (OAuth client ID), `ownerId` (user to whom token belongs ID), `iat` (issued at time) and `expiresAt` (when does the token expire) fields.
# Get a managed user
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/get-a-managed-user
api-reference/v2/openapi.json get /v2/oauth-clients/{clientId}/users/{userId}
# Get all managed users
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/get-all-managed-users
api-reference/v2/openapi.json get /v2/oauth-clients/{clientId}/users
# Refresh managed user tokens
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens
api-reference/v2/openapi.json post /v2/oauth/{clientId}/refresh
If managed user access token is expired then get a new one using this endpoint - it will also refresh the refresh token, because we use
"refresh token rotation" mechanism. Access token is valid for 60 minutes and refresh token for 1 year. Make sure to store them in your database, for example, in your User database model `calAccessToken` and `calRefreshToken` fields.
Response also contains `accessTokenExpiresAt` and `refreshTokenExpiresAt` fields, but if you decode the jwt token the payload will contain `clientId` (OAuth client ID), `ownerId` (user to whom token belongs ID), `iat` (issued at time) and `expiresAt` (when does the token expire) fields.
# Update a managed user
Source: https://cal.com/docs/api-reference/v2/platform-managed-users/update-a-managed-user
api-reference/v2/openapi.json patch /v2/oauth-clients/{clientId}/users/{userId}
# Create a webhook
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/create-a-webhook
api-reference/v2/openapi.json post /v2/oauth-clients/{clientId}/webhooks
# Delete a webhook
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/delete-a-webhook
api-reference/v2/openapi.json delete /v2/oauth-clients/{clientId}/webhooks/{webhookId}
# Delete all webhooks
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/delete-all-webhooks
api-reference/v2/openapi.json delete /v2/oauth-clients/{clientId}/webhooks
# Get a webhook
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/get-a-webhook
api-reference/v2/openapi.json get /v2/oauth-clients/{clientId}/webhooks/{webhookId}
# Get all webhooks
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/get-all-webhooks
api-reference/v2/openapi.json get /v2/oauth-clients/{clientId}/webhooks
# Update a webhook
Source: https://cal.com/docs/api-reference/v2/platform-webhooks/update-a-webhook
api-reference/v2/openapi.json patch /v2/oauth-clients/{clientId}/webhooks/{webhookId}
# Calculate slots based on routing form response
Source: https://cal.com/docs/api-reference/v2/routing-forms/calculate-slots-based-on-routing-form-response
api-reference/v2/openapi.json post /v2/routing-forms/{routingFormId}/calculate-slots
It will not actually save the response just return the routed event type and slots when it can be booked.
# Create a schedule
Source: https://cal.com/docs/api-reference/v2/schedules/create-a-schedule
api-reference/v2/openapi.json post /v2/schedules
Create a schedule for the authenticated user.
The point of creating schedules is for event types to be available at specific times.
The first goal of schedules is to have a default schedule. If you are platform customer and created managed users, then it is important to note that each managed user should have a default schedule.
1. If you passed `timeZone` when creating managed user, then the default schedule from Monday to Friday from 9AM to 5PM will be created with that timezone. The managed user can then change the default schedule via the `AvailabilitySettings` atom.
2. If you did not, then we assume you want the user to have this specific schedule right away. You should create a default schedule by specifying
`"isDefault": true` in the request body. Until the user has a default schedule the user can't be booked nor manage their schedule via the AvailabilitySettings atom.
The second goal of schedules is to create another schedule that event types can point to. This is useful for when an event is booked because availability is not checked against the default schedule but instead against that specific schedule.
After creating a non-default schedule, you can update an event type to point to that schedule via the PATCH `event-types/{eventTypeId}` endpoint.
When specifying start time and end time for each day use the 24 hour format e.g. 08:00, 15:00 etc.
# Delete a schedule
Source: https://cal.com/docs/api-reference/v2/schedules/delete-a-schedule
api-reference/v2/openapi.json delete /v2/schedules/{scheduleId}
# Get a schedule
Source: https://cal.com/docs/api-reference/v2/schedules/get-a-schedule
api-reference/v2/openapi.json get /v2/schedules/{scheduleId}
# Get all schedules
Source: https://cal.com/docs/api-reference/v2/schedules/get-all-schedules
api-reference/v2/openapi.json get /v2/schedules
Get all schedules of the authenticated user.
# Get default schedule
Source: https://cal.com/docs/api-reference/v2/schedules/get-default-schedule
api-reference/v2/openapi.json get /v2/schedules/default
Get the default schedule of the authenticated user.
# Update a schedule
Source: https://cal.com/docs/api-reference/v2/schedules/update-a-schedule
api-reference/v2/openapi.json patch /v2/schedules/{scheduleId}
# Add a selected calendar
Source: https://cal.com/docs/api-reference/v2/selected-calendars/add-a-selected-calendar
api-reference/v2/openapi.json post /v2/selected-calendars
# Delete a selected calendar
Source: https://cal.com/docs/api-reference/v2/selected-calendars/delete-a-selected-calendar
api-reference/v2/openapi.json delete /v2/selected-calendars
# Delete a reserved slot
Source: https://cal.com/docs/api-reference/v2/slots/delete-a-reserved-slot
api-reference/v2/openapi.json delete /v2/slots/reservations/{uid}
# Get available time slots for an event type
Source: https://cal.com/docs/api-reference/v2/slots/get-available-time-slots-for-an-event-type
api-reference/v2/openapi.json get /v2/slots
There are 4 ways to get available slots for event type of an individual user:
1. By event type id. Event type id can be of user and team event types. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'
2. By event type slug + username. Example '/v2/slots?eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'
3. By event type slug + username + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'
4. By usernames only (used for dynamic event type - there is no specific event but you want to know when 2 or more people are available). Example '/v2/slots?usernames=alice,bob&username=bob&organizationSlug=org-slug&start=2050-09-05&end=2050-09-06'. As you see you also need to provide the slug of the organization to which each user in the 'usernames' array belongs.
And 3 ways to get available slots for team event type:
1. By team event type id. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'
2. By team event type slug + team slug. Example '/v2/slots?eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'
3. By team event type slug + team slug + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'
All of them require "start" and "end" query parameters which define the time range for which available slots should be checked.
Optional parameters are:
- timeZone: Time zone in which the available slots should be returned. Defaults to UTC.
- duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.
- format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use "range" as value.
- bookingUidToReschedule: When rescheduling an existing booking, provide the booking's unique identifier to exclude its time slot from busy time calculations. This ensures the original booking time appears as available for rescheduling.
# Get reserved slot
Source: https://cal.com/docs/api-reference/v2/slots/get-reserved-slot
api-reference/v2/openapi.json get /v2/slots/reservations/{uid}
# Reserve a slot
Source: https://cal.com/docs/api-reference/v2/slots/reserve-a-slot
api-reference/v2/openapi.json post /v2/slots/reservations
Make a slot not available for others to book for a certain period of time. If you authenticate using oAuth credentials, api key or access token
then you can also specify custom duration for how long the slot should be reserved for (defaults to 5 minutes).
# Update a reserved slot
Source: https://cal.com/docs/api-reference/v2/slots/update-a-reserved-slot
api-reference/v2/openapi.json patch /v2/slots/reservations/{uid}
# Check Stripe connection
Source: https://cal.com/docs/api-reference/v2/stripe/check-stripe-connection
api-reference/v2/openapi.json get /v2/stripe/check
# Get Stripe connect URL
Source: https://cal.com/docs/api-reference/v2/stripe/get-stripe-connect-url
api-reference/v2/openapi.json get /v2/stripe/connect
# Save Stripe credentials
Source: https://cal.com/docs/api-reference/v2/stripe/save-stripe-credentials
api-reference/v2/openapi.json get /v2/stripe/save
# Create a phone call
Source: https://cal.com/docs/api-reference/v2/teams-event-types/create-a-phone-call
api-reference/v2/openapi.json post /v2/teams/{teamId}/event-types/{eventTypeId}/create-phone-call
# Create an event type
Source: https://cal.com/docs/api-reference/v2/teams-event-types/create-an-event-type
api-reference/v2/openapi.json post /v2/teams/{teamId}/event-types
# Delete a team event type
Source: https://cal.com/docs/api-reference/v2/teams-event-types/delete-a-team-event-type
api-reference/v2/openapi.json delete /v2/teams/{teamId}/event-types/{eventTypeId}
# Get a team event type
Source: https://cal.com/docs/api-reference/v2/teams-event-types/get-a-team-event-type
api-reference/v2/openapi.json get /v2/teams/{teamId}/event-types
# Get an event type
Source: https://cal.com/docs/api-reference/v2/teams-event-types/get-an-event-type
api-reference/v2/openapi.json get /v2/teams/{teamId}/event-types/{eventTypeId}
# Update a team event type
Source: https://cal.com/docs/api-reference/v2/teams-event-types/update-a-team-event-type
api-reference/v2/openapi.json patch /v2/teams/{teamId}/event-types/{eventTypeId}
# Create a membership
Source: https://cal.com/docs/api-reference/v2/teams-memberships/create-a-membership
api-reference/v2/openapi.json post /v2/teams/{teamId}/memberships
# Delete a membership
Source: https://cal.com/docs/api-reference/v2/teams-memberships/delete-a-membership
api-reference/v2/openapi.json delete /v2/teams/{teamId}/memberships/{membershipId}
# Get a membership
Source: https://cal.com/docs/api-reference/v2/teams-memberships/get-a-membership
api-reference/v2/openapi.json get /v2/teams/{teamId}/memberships/{membershipId}
# Get all memberships
Source: https://cal.com/docs/api-reference/v2/teams-memberships/get-all-memberships
api-reference/v2/openapi.json get /v2/teams/{teamId}/memberships
# Update membership
Source: https://cal.com/docs/api-reference/v2/teams-memberships/update-membership
api-reference/v2/openapi.json patch /v2/teams/{teamId}/memberships/{membershipId}
# Get all team member schedules
Source: https://cal.com/docs/api-reference/v2/teams-schedules/get-all-team-member-schedules
api-reference/v2/openapi.json get /v2/teams/{teamId}/schedules
# Get list of verified emails of a team
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/get-list-of-verified-emails-of-a-team
api-reference/v2/openapi.json get /v2/teams/{teamId}/verified-resources/emails
# Get list of verified phone numbers of a team
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/get-list-of-verified-phone-numbers-of-a-team
api-reference/v2/openapi.json get /v2/teams/{teamId}/verified-resources/phones
# Get verified email of a team by id
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/get-verified-email-of-a-team-by-id
api-reference/v2/openapi.json get /v2/teams/{teamId}/verified-resources/emails/{id}
# Get verified phone number of a team by id
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/get-verified-phone-number-of-a-team-by-id
api-reference/v2/openapi.json get /v2/teams/{teamId}/verified-resources/phones/{id}
# Request email verification code
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/request-email-verification-code
api-reference/v2/openapi.json post /v2/teams/{teamId}/verified-resources/emails/verification-code/request
Sends a verification code to the Email
# Request phone number verification code
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/request-phone-number-verification-code
api-reference/v2/openapi.json post /v2/teams/{teamId}/verified-resources/phones/verification-code/request
Sends a verification code to the phone number
# Verify a phone number for an org team
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/verify-a-phone-number-for-an-org-team
api-reference/v2/openapi.json post /v2/teams/{teamId}/verified-resources/phones/verification-code/verify
Use code to verify a phone number
# Verify an email for a team
Source: https://cal.com/docs/api-reference/v2/teams-verified-resources/verify-an-email-for-a-team
api-reference/v2/openapi.json post /v2/teams/{teamId}/verified-resources/emails/verification-code/verify
Use code to verify an email
# Create a team
Source: https://cal.com/docs/api-reference/v2/teams/create-a-team
api-reference/v2/openapi.json post /v2/teams
# Delete a team
Source: https://cal.com/docs/api-reference/v2/teams/delete-a-team
api-reference/v2/openapi.json delete /v2/teams/{teamId}
# Get a team
Source: https://cal.com/docs/api-reference/v2/teams/get-a-team
api-reference/v2/openapi.json get /v2/teams/{teamId}
# Get teams
Source: https://cal.com/docs/api-reference/v2/teams/get-teams
api-reference/v2/openapi.json get /v2/teams
# Update a team
Source: https://cal.com/docs/api-reference/v2/teams/update-a-team
api-reference/v2/openapi.json patch /v2/teams/{teamId}
# Differences between v1 and v2
Source: https://cal.com/docs/api-reference/v2/v1-v2-differences
## API Versions
We offer two versions of our API: the legacy version (v1) and the latest v2 version. While both versions are currently available, we highly recommend using the v2 API in all your integrations and applications.
### Why Use v2?
The v2 API includes numerous enhancements and new features that are not available in v1. It has been designed to be more efficient, secure, and easier to use. v2 reflects our commitment to providing the best possible developer experience and ensuring that your applications can take advantage of the latest advancements in our platform.
### Key Differences
* **Performance Improvements**: v2 has been optimized for better performance and scalability.
* **User friendly response objects**: In v2 we have focused heavily on improving the response object for a better User Experience.
* **Enhanced Security**: v2 includes improved security measures to protect your data.
* **Platform product**: Our new Platform product was built entirely on v2.
We are committed to supporting our community during this transition. If you have any questions or need assistance with migrating to the v2 API, please contact our support team.
Thank you for your understanding and cooperation.
# Get list of verified emails
Source: https://cal.com/docs/api-reference/v2/verified-resources/get-list-of-verified-emails
api-reference/v2/openapi.json get /v2/verified-resources/emails
# Get list of verified phone numbers
Source: https://cal.com/docs/api-reference/v2/verified-resources/get-list-of-verified-phone-numbers
api-reference/v2/openapi.json get /v2/verified-resources/phones
# Get verified email by id
Source: https://cal.com/docs/api-reference/v2/verified-resources/get-verified-email-by-id
api-reference/v2/openapi.json get /v2/verified-resources/emails/{id}
# Get verified phone number by id
Source: https://cal.com/docs/api-reference/v2/verified-resources/get-verified-phone-number-by-id
api-reference/v2/openapi.json get /v2/verified-resources/phones/{id}
# Request email verification code
Source: https://cal.com/docs/api-reference/v2/verified-resources/request-email-verification-code
api-reference/v2/openapi.json post /v2/verified-resources/emails/verification-code/request
Sends a verification code to the email
# Request phone number verification code
Source: https://cal.com/docs/api-reference/v2/verified-resources/request-phone-number-verification-code
api-reference/v2/openapi.json post /v2/verified-resources/phones/verification-code/request
Sends a verification code to the phone number
# Verify a phone number
Source: https://cal.com/docs/api-reference/v2/verified-resources/verify-a-phone-number
api-reference/v2/openapi.json post /v2/verified-resources/phones/verification-code/verify
Use code to verify a phone number
# Verify an email
Source: https://cal.com/docs/api-reference/v2/verified-resources/verify-an-email
api-reference/v2/openapi.json post /v2/verified-resources/emails/verification-code/verify
Use code to verify an email
# Create a webhook
Source: https://cal.com/docs/api-reference/v2/webhooks/create-a-webhook
api-reference/v2/openapi.json post /v2/webhooks
# Delete a webhook
Source: https://cal.com/docs/api-reference/v2/webhooks/delete-a-webhook
api-reference/v2/openapi.json delete /v2/webhooks/{webhookId}
# Get a webhook
Source: https://cal.com/docs/api-reference/v2/webhooks/get-a-webhook
api-reference/v2/openapi.json get /v2/webhooks/{webhookId}
# Get all webhooks
Source: https://cal.com/docs/api-reference/v2/webhooks/get-all-webhooks
api-reference/v2/openapi.json get /v2/webhooks
Gets a paginated list of webhooks for the authenticated user.
# Update a webhook
Source: https://cal.com/docs/api-reference/v2/webhooks/update-a-webhook
api-reference/v2/openapi.json patch /v2/webhooks/{webhookId}
# How to Set Up the API in a Local Instance
Source: https://cal.com/docs/developing/guides/api/how-to-setup-api-in-a-local-instance
To test the API in your local instance, you have the following pre-requisites:
Please clone the cal.com repository. You can do it by following the instructions provided in [Installation](/developing/local-development)
Add a staging license key that goes in as value for `CALCOM_LICENSE_KEY` in your root `.env` file.
You can use the following as staging license key
```
1a1f8138-0bfc-4f37-b4af-1e24fd145839
```
Start the cal.com server using `yarn dev` on localhost and create the test API keys by visiting `/settings/developer/api-keys`
Start the API server by running `yarn workspace @calcom/api dev` and start testing your API locally
By default, the app server runs on port 3000 and the API server runs on port 3003
# Build a greeter app
Source: https://cal.com/docs/developing/guides/appstore-and-integration/build-a-greeter-app
## Building a **Greeter** app
Create an app with the title "**Greeter".** Run the following command and provide the information it is looking for.
```bash
yarn app-store create
```
The app is created in Step 1 and we should install it now.
The app is installed but it doesn't do anything because we haven't written added any functionality to it. 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
/**
* 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/button/Button";
import useMeQuery from "@calcom/trpc/react/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 (
);
}
```
```;
/**
* 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/docs/developing/guides/appstore-and-integration/build-an-app
Since Cal.com is open source we encourage developers to create new apps for others to use. This guide is to help you get started.
You can create an app by simply running the following command. It creates a new directory under [`packages/app-store/`](https://github.com/calcom/cal.com/tree/main/packages/app-store)\`\`
```bash
yarn create-app
```
You just need to provide a few inputs and then you will have your app created within a few seconds. [See, how you can build a very simple app that greets your users.](/developing/guides/appstore-and-integration/build-a-greeter-app)
### Steps in creating an app
Create the app using the `create-app` command. The app can be installed now, but at this moment it isn't doing anything. It is just installed and ready to do what you want it to do.
There is pretty much no restriction on what an App can do. For example:
* Hooking into existing functionalities to enhance them - *In all these cases you need to first check if the app is installed or not. There is* `_useApp(appSlug)_` *react hook to do that. It gives you the app details if the app is installed.*
* Apps that need to connect with third parties like Google Calendar, Apple Calendar, Google Meet.
* A very powerful app that has its own data and pages - [Routing Forms App](https://github.com/calcom/cal.com/tree/main/packages/app-store/ee/routing_forms) is a great example of this.
* There are other powerful apps already in the [App Store](https://app.cal.com/apps) that you can get an idea of the capabilities of apps.
### Structure
All apps can be found under [`packages/app-store`](https://github.com/calcom/cal.com/tree/main/packages/app-store). In this folder is `_baseApp` which shows the general structure of an app.
```bash
├──_example
| ├──config.json -> Autogenerated by cli. You are free to edit it.
| ├──api
| | ├──add.ts -> Autogenerated by cli. You would want to edit it if your app needs to connect with a third party
|
| ├──components
|
| ├──static -> Add all static assets here
| | ├──icon.svg -> This is used as the logo for your App.
| ├──index.ts
| ├──package.json
| ├──.env.example -> Specify the environmental variables (ex. auth token, API secrets) that your app will need if it's applicable
| ├──README.mdx -> Customize your app description. You can add an image slider as well.
```
### Other Commands
**Deleting an app:**
```bash
yarn app-store delete --slug APP_NAME
```
**Editing an app:**
```bash
yarn app-store edit --slug APP_NAME
```
### Important Points
* Make sure to have `yarn app-store:watch` command running when developing an app so that autogenerated files are always up to date.
* If app-store cli fails at this step, try to run this command manually first. Solve that problem and then re-run cli. The command can fail because there are Prisma migrations that can't be applied automatically.
A sample failure in create command
* When you edit an app following things aren't updated.
* README.mdx - It would still have the old description. Feel free to edit it manually.
### Publishing Your App to the Cal.com App Store
Once your app is working in your environment, you can publish it to Cal.com App Store by opening a PR [here](https://github.com/calcom/cal.com).
If you need any help feel free to join us in our [GitHub Discussions](https://github.com/calcom/cal.com/discussions).
# Assign people to a call from a CRM or database
Source: https://cal.com/docs/developing/guides/appstore-and-integration/how-to-show-assigned-people-from-a-crm
## 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](mailto:name@acme.com) our integration will look up who has spoken to [name@acme.com](mailto:name@acme.com) before and skip all round-robin logic.
Here is an example URL: i.cal.com/sales/exploration?email=[name@acme.com](mailto:name@acme.com)
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](mailto:jane@acme.com) → acme.cal.com/jane (or schedule.acme.com/jane)
This means if you have a table
| User | AccountExecutive |
| :---------------------------------- | :------------------------------------ |
| [peer@cal.com](mailto:peer@cal.com) | [jane@acme.com](mailto:jane@acme.com) |
You could show [peer@cal.com](mailto:peer@cal.com) an embed inside your application simply by using the value from AccountExecutive to build the link:
[jane@acme.com](mailto:jane@acme.com) → acme.cal.com/jane either with a string replace function or a simple regex.
# Setting up OIDC with okta
Source: https://cal.com/docs/developing/guides/auth-and-provision/how-to-setup-oidc-with-okta
For example, in Okta, once you create an account, you can click on Applications on the sidebar menu:
Enter the Sign in redirect URL (or auth URL) as:
```
https://app.cal.com/api/auth/oidc
```
And the sign out URL as:
```
https://app.cal.com/auth/login
```
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
```
Log in with the Organization Admin user.
Visit `https://app.cal.com/settings/organizations/sso` and you should see something like this:
Click on Configure SSO with OIDC, and then enter the Client Secret, Client ID, and Well Known URL from Step 5, and click save.
That's it. Now when you try to login with SSO, your application on Okta will handle the authentication.
# null
Source: https://cal.com/docs/developing/guides/auth-and-provision/how-to-setup-scim-with-okta
For example, in Okta, once you create an account, you can click on Applications on the sidebar menu:
Note you will have to fill in the appropriate fields for the SAML or OIDC setup to continue.
* [SAML Setup](/developing/guides/auth-and-provision/sso-setup#setting-up-saml-login)
* [OIDC Setup](/developing/guides/auth-and-provision/sso-setup#setting-up-oidc-login)
Once the application is created, under General -> App Settings, click "Edit" and then the checkbox "Enable SCIM provisioning".
Next, go to your instance of Cal.com and navigate to `https://app.cal.com/settings/organization/dsync` and click configure.
In the "Configure Directory Sync" form, choose a directory sync name and select "Okta SCIM v2.0" as the "Directory Provider".
In 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"
After saving, navigate to the "To App" settings, still under the "Provisioning" tab.
Under "Provisioning to App", click "Edit" and enable:
* "Create User"
* "Update User Attributes"
* "Deactivate User"
Under "\{Your application name} Attribute Mapping," remove all fields except for:
* "username"
* "givenName"
* "familyName"
* "email"
* "displayName"
Set each of these properties to "Map from Okta Profile" and the related field. Under "Apply On" select "Create and Update".
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 `https://app.cal.com/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.
The group name must be spelled exactly as it is shown on Okta.
When you push the group to your organization, those users will automatically be added to the team.
# SSO setup
Source: https://cal.com/docs/developing/guides/auth-and-provision/sso-setup
Cal.com supports both Security Assertion Markup Language (SAML) and OpenID Connect (OIDC), two of the industry's leading authentication protocols. We prioritize your ease of access and security by providing robust Single Sign-On (SSO) capabilities. Whether you're looking for the XML-based standard of SAML or the lightweight OIDC, our platform is equipped to integrate smoothly with your preferred identity provider, ensuring both convenience and security for your users.
### Setting up SAML login
Follow the instructions here - [SAML Setup](/developing/guides/auth-and-provision/sso-setup#saml-registration-with-identity-providers)
Ensure that all users who need access to Cal.com have access to the IdP SAML app.
Keep the XML metadata from your IdP accessible, as you will need it later.
Visit `settings/organizations/sso`.
Click on the `Configure` button for `SSO with SAML`.
In the SAML configuration section, copy and paste the XML metadata from step 3 and click on Save.
Once setup is complete, provisioned users can log into Cal.com using SAML.
### SAML Registration with Identity Providers
This guide explains the settings you need to use to configure SAML with your Identity Provider. Once configured, obtain an XML metadata file and upload it on your Cal.com instance.
> **Note:** Please do not add a trailing slash at the end of the URLs. Create them exactly as shown below.
**Assertion consumer service URL / Single Sign-On URL / Destination URL:** [https://app.cal.com/api/auth/saml/callback](https://app.cal.com/api/auth/saml/callback)
**Entity ID / Identifier / Audience URI / Audience Restriction:** [https://saml.cal.com](https://saml.cal.com)
**Response:** Signed
**Assertion Signature:** Signed
**Signature Algorithm:** RSA-SHA256
**Assertion Encryption:** Unencrypted
**Name ID Format:** EmailAddress
**Application username:** email
**Mapping Attributes / Attribute Statements:**
| Name | Name Format | Value |
| :-------- | :---------- | :------------- |
| firstName | Basic | user.firstName |
| lastName | Basic | user.lastName |
### Setting up OIDC login
Keep handy the Client Secret, Client ID, and Well Known URL for the next steps.
Visit `/settings/organizations/sso` and you should see something like this:
Click on Configure SSO with OIDC, enter the Client Secret, Client ID, and Well Known URL from Step 1, and click save.
Now, when you try to login with SSO, your OIDC provider will handle the authentication.
# Webhooks
Source: https://cal.com/docs/developing/guides/automation/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.
Please note that the webhooks can be associated with user as well as individual event types, including team event types.
### Creating a webhook subscription
To create a new webhook subscription, visit `/settings/developer/webhooks` and proceed to enter the following details:
This is the listener URL where the payload will be sent when an event trigger is activated.
You can choose which specific triggers to listen to. Currently available triggers include:
* `Booking Cancelled`
* `Booking Created`
* `Booking Rescheduled`
* `Booking Rejected`
* `Booking Requested`
* `Booking Payment Initiated`
* `Booking Paid`
* `Meeting Started`
* `Recording Ready`
* `Form Submitted`
* `Meeting Ended`
* `Instant Meeting Created`
You can provide a secret key with this webhook to [verify it](/docs/core-features/webhooks#verifying-the-authenticity-of-the-received-payload) on the subscriber URL when receiving a payload. This helps confirm whether the payload is authentic or has been tampered with. You can leave it blank if you don't wish to secure the webhook with a secret key.
You have the option to [customize the payload](/docs/core-features/webhooks#adding-a-custom-payload-template) that you receive when a subscribed event is triggered.
### An example webhook payload
```json
{
"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": "pro@example.com",
"username": "pro",
"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"
}
}
```
### Verifying the authenticity of the received payload
Simply add a new **secret key** to your webhook configuration and save it.
The webhook will trigger when an event is created, cancelled, rescheduled, or when a meeting ends.
Use the **secret key** to create an HMAC, and update it with the webhook payload received to generate an SHA256 hash.
Compare the hash received in the header of the webhook `(x-cal-signature-256)` with the one you created using the **secret key** and the body of the payload. If they don't match, the received payload has been 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
{
"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, FORM\_SUBMITTED] |
| 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 | Person | The organizer of the event |
| attendees | Person\[] | The event booker & any guests |
| 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 metadata of the booking, including the meeting URL (videoCallUrl) in case of Google Meet and Cal Video |
#### Person Structure
| Variable | Type | Description |
| ---------------- | ------ | ---------------------------------------------------------------------- |
| name | String | Name of the individual |
| email | Email | Email of the individual |
| timezone | String | Timezone of the individual (e.g., "America/New\_York", "Asia/Kolkata") |
| language?.locale | String | Locale of the individual (e.g., "en", "fr") |
# Setting up mailtrap for email testing
Source: https://cal.com/docs/developing/guides/email/setup-mailtrap-for-email-testing
Mailtrap is a versatile tool for testing email notifications without sending them to the real users of your application. It's especially useful for testing and ensuring that the system sends out accurate emails in a secure and efficient manner.
To set up Mailtrap for email testing on Cal.com, follow these steps:
The first step is to register an account with Mailtrap. It offers a free plan for small testing needs, and also paid plans for larger organizations.
After registering, create an inbox for your application. Each inbox comes with its SMTP and POP3 credentials, which can be used to send and retrieve emails.
Change the tab to nodemailer and copy the information to `.env`:
```
EMAIL_SERVER_HOST='sandbox.smtp.mailtrap.io'
EMAIL_SERVER_PORT=2525
EMAIL_SERVER_USER='XXX'
EMAIL_SERVER_PASSWORD='XXX'
```
Please remember to change the user and password and replace 'XXX' above with their respective values.
Set the `EMAIL_FROM` environment variable in the `.env` file. For example:
```
EMAIL_FROM='notifications@yourselfhostedcal.com'
```
Once your instance is configured, you can start sending test emails. These emails are "trapped" in the Mailtrap inbox, enabling you to verify email content, headers, and attachments.
Mailtrap provides features to analyze and debug your emails. You can check whether the HTML displays correctly, ensure the email is not treated as spam, and also see if it contains any broken links, invalid format, or incorrect images.
Happy testing!
# Embed Events
Source: https://cal.com/docs/developing/guides/embeds/embed-events
## Actions
You can listen to an action that occurs in embedded cal link as follows. You can think of them as DOM events. We are avoiding the term "events" to not confuse it with Cal Events.
```js
```
## Following are the list of supported actions.
| Action | Description | Properties |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| eventTypeSelected | When user chooses an event-type from the listing. | `eventType: object` // Event Type that has been selected |
| bookingSuccessful | When the booking is successfully done. It might not be confirmed. | `confirmed: boolean` // Whether confirmation from organizer is pending or not `eventType: object` // Event Type that has been booked `date: string` // Date of Event `duration: number` // Duration of booked Event `organizer: object` // Organizer details like name, timezone, email |
| linkReady | Tells that the link is ready to be shown now. | None |
| linkFailed | Fired if link fails to load. | `code: number` // Error Code `msg: string` // Human Readable message `data: object` // More details to debug the error |
| \_\_iframeReady | It is fired when the embedded iframe is ready to communicate with parent snippet. This is mostly for internal use by Embed Snippet. | None |
| \_\_windowLoadComplete | Tells that window load for iframe is complete. | None |
| \_\_dimensionChanged | Tells that dimensions of the content inside the iframe changed. | `iframeWidth: number` `iframeHeight: number` |
Actions that start with \_\_ are internal.
To get more details on how Embed actually works, you can refer to this [Embed Flowchart](https://www.figma.com/file/zZ5oaUpg12Fuu5mGZrPlP5/Embed-Flowchart).
# How to Add a New Booking Chart to Cal.com Insights Page
Source: https://cal.com/docs/developing/guides/insights/add-new-booking-charts
This guide walks you through creating a new booking chart component for the insights page, covering the entire stack from UI component to backend service.
## Overview
The insights booking system follows this architecture:
```
UI Component → tRPC Handler → Insights Service → Database Query → Response
```
Create your chart component in `packages/features/insights/components/booking/`:
```typescript
// packages/features/insights/components/booking/MyNewChart.tsx
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Line, ResponsiveContainer } from "recharts";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsBookingParameters } from "../../hooks/useInsightsBookingParameters";
import { ChartCard } from "../ChartCard";
import { LoadingInsight } from "../LoadingInsights";
export const MyNewChart = () => {
const { t } = useLocale();
const insightsBookingParams = useInsightsBookingParameters();
const { data, isSuccess, isPending } = trpc.viewer.insights.myNewChartData.useQuery(insightsBookingParams, {
staleTime: 180000, // 3 minutes
refetchOnWindowFocus: false,
trpc: { context: { skipBatch: true } },
});
if (isPending) return ;
return (
{isSuccess && data?.length > 0 ? (
) : (
{t("no_data_yet")}
)}
);
};
```
Update the booking components index file:
```typescript
// packages/features/insights/components/booking/index.ts
export { AverageEventDurationChart } from "./AverageEventDurationChart";
export { BookingKPICards } from "./BookingKPICards";
// ... existing exports
export { MyNewChart } from "./MyNewChart"; // Add this line
```
Add your component to the main insights page:
```typescript
// apps/web/modules/insights/insights-view.tsx
import {
AverageEventDurationChart,
BookingKPICards, // ... existing imports
MyNewChart, // Add this import
} from "@calcom/features/insights/components/booking";
export default function InsightsPage() {
// ... existing code
return (
{/* Existing components */}
{/* Add your new chart */}
{/* Other existing components */}
);
}
```
Add the tRPC endpoint in the insights router using the `getInsightsBookingService()` DI container function:
```typescript
// packages/features/insights/server/trpc-router.ts
import { bookingRepositoryBaseInputSchema } from "@calcom/features/insights/server/raw-data.schema";
import { userBelongsToTeamProcedure } from "@calcom/trpc/server/procedures/authedProcedure";
import { TRPCError } from "@trpc/server";
export const insightsRouter = router({
// ... existing procedures
myNewChartData: userBelongsToTeamProcedure
.input(bookingRepositoryBaseInputSchema)
.query(async ({ ctx, input }) => {
// `createInsightsBookingService` is defined at the root level in this file
const insightsBookingService = createInsightsBookingService(ctx, input);
try {
return await insightsBookingService.getMyNewChartData();
} catch (e) {
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" });
}
}),
});
```
Add your new method to the `InsightsBookingBaseService` class:
```typescript
// packages/lib/server/service/InsightsBookingBaseService.ts
export class InsightsBookingBaseService {
// ... existing methods
async getMyNewChartData() {
const baseConditions = await this.getBaseConditions();
// Example: Get booking counts by day using raw SQL for performance
const data = await this.prisma.$queryRaw<
Array<{
date: Date;
bookingsCount: number;
}>
>`
SELECT
DATE("createdAt") as date,
COUNT(*)::int as "bookingsCount"
FROM "BookingTimeStatusDenormalized"
WHERE ${baseConditions}
GROUP BY DATE("createdAt")
ORDER BY date ASC
`;
// Transform the data for the chart
return data.map((item) => ({
date: item.date.toISOString().split("T")[0], // Format as YYYY-MM-DD
value: item.bookingsCount,
}));
}
}
```
## Best Practices
1. **Use `getInsightsBookingService()`**: Always use the DI container function for consistent service creation
2. **Raw SQL for Performance**: Use `$queryRaw` for complex aggregations and better performance
3. **Base Conditions**: Always use `await this.getBaseConditions()` for proper filtering and permissions
4. **Error Handling**: Wrap service calls in try-catch blocks with `TRPCError`
5. **Loading States**: Always show loading indicators with `LoadingInsight`
6. **Consistent Styling**: Use `recharts` for new charts.
7. **Date Handling**: Use `getDateRanges()` and `getTimeView()` for time-based charts
# Introduction
Source: https://cal.com/docs/developing/introduction
Follow our quickstart guide to start developing with Cal.com
Learn how to self-host Cal.com for controlled instance
Learn how to use Cal.com's API to CRUD various Cal resources programmatically
## Welcome to the Cal.com Documentation!
This is the documentation for Cal.com, an open source scheduling platform that enables you to take bookings on your own terms. Set your availability, connect your favourite calendar and video conferencing platforms, and share your link. It's that simple.
It covers everything from setup to usage and development. Here you can explore advice and explanations for all of our features, as well as discover new tips and tricks to get the most out of the Cal.com software. This also includes the more advanced documentation covering how to build on top of Cal.com both in the codebase, by API and more. These guides will go into depth on how you can best integrate and extend Cal.com for your needs.
# Local Development
Source: https://cal.com/docs/developing/local-development
Cal.com runs with pretty minimal hardware requirements by itself. The most intensive part for the software is when you actually build the software, but once it's running it's relatively lightweight.
Cal.com works with a very large range of operating systems, as it only requires JavaScript execution to run. **Cal.com is known to work well with Windows, Mac, Linux and BSD.** Although they do work well on all of them, for production deployments we would suggest Linux as the ideal platform. Any operating system that runs Node.js should be able to work too, but these are some of the common operating systems that we know work well.
To run Cal.com, you need to install a few things. **Node.js, yarn, Git and PostgreSQL**. We use **Prisma** for database maintenance, and is one of the dependencies. We won’t publish installation guides for these as they have their own resources available on the internet. If you're on Linux/BSD, all of these things should be readily available on your package manager. Your best bet is searching for something like **Debian 12 PostgreSQL**, which will give you a guide to installing and configuring PostgreSQL on Debian Linux 12.
To ensure optimal performance and compatibility, we highly recommend using Node.js version 18 for your development environment. This version provides the best balance of stability, features, and security for this project. Please make sure to update your Node.js installation if necessary.
## Development Setup & Production Build
1. **First, you git clone the repository** with the following command, so you have a copy of the code.
```git
git clone https://github.com/calcom/cal.com.git
```
If you are on windows, you would need to use the following command when cloning, with **admin privileges**:
```git
git clone -c core.symlinks=true https://github.com/calcom/cal.com.git
```
2. Then, go into the directory you just cloned with
```bash
cd cal.com
```
and run
```bash
yarn
```
to install all of the dependencies. Essentially, dependencies are just things that Cal.com needs to install to be able to work.
3. Then, you just need to set up a couple of things. For that, we use a `.env` file. We just need to copy and paste the `.env.example` file and rename the copy to `.env`. Here you'll have a template with comments showing you the settings you need/might want to set.
4. Next, use the command
```bash
openssl rand -base64 32
```
(or another secret generator tool if you prefer) to generate a key and add it under `NEXTAUTH_SECRET` in the .env file.
5. You'll also want to fill out the `.env.appStore` file similar to the `.env` file as this includes keys to enable apps.
**Development tips**
> Add `NEXT_PUBLIC_DEBUG=1` anywhere in your `.env` to get logging information for all the queries and mutations driven by **trpc**.
```bash
echo 'NEXT_PUBLIC_DEBUG=1' >> .env
```
> For email testing, set it to "1" if you need to email checks in E2E tests locally. Make sure to run mailhog container manually or with `yarn dx`.
```bash
echo 'E2E_TEST_MAILHOG_ENABLED=1' >> .env
```
### E2E Testing
Be sure to set the environment variable `NEXTAUTH_URL` to the correct value. If you are running locally, as the documentation within `.env.example` mentions, the value should be `http://localhost:3000`.
In a terminal just run:
```bash
yarn test-e2e
```
To open last HTML report run:
```bash
yarn playwright show-report test-results/reports/playwright-html-report
```
### Manual setup
1. Configure environment variables in the .env file. Replace ``, ``, ``, `` with their applicable values
```bash
DATABASE_URL='postgresql://:@:'
```
2. Set a 24 character random string in your .env file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like
```bash
openssl rand -base64 24
```
to generate one).
3. Set up the database using the Prisma schema (found in `packages/prisma/schema.prisma`)
```bash
yarn workspace @calcom/prisma db-deploy
```
4. Run (in development mode)
```bash
yarn dev
```
When you're testing out the enterprise features locally, you should see a warning shown in the image below, clarifying the need to purchase a license for such features in production.
## **Development quick start with** **`yarn dx`**
> * **Requires Docker and Docker Compose to be installed**
>
> * Will start a local Postgres instance with a few test users - the credentials will be logged in the console
```bash
yarn dx
```
## **Cron Jobs**
There are a few features which require cron job setup. At cal.com, the cron jobs are found in the following directory:
```bash
/apps/web/app/api/cron
```
## App store seeder
We recommend using the admin UI/wizard instead of the seeder to enable app store apps
## API
#### Step 1
Copy the .env files from their respective example files depending on the version of the API (v1 or v2):
```bash
cp apps/api/.env.example apps/api/{version}/.env
cp .env.example .env
```
#### Step 2
Install packages with yarn:
```bash
yarn
```
### Running API server
Run the API V1 with yarn:
```bash
yarn workspace @calcom/api dev
```
Run the API V2 with yarn:
Please note API V2 requires the database running in docker
```bash
yarn workspace @calcom/api-v2 dev
```
On windows, you would need to update the script to explicitly set port to 3003 and run yarn dev under `apps/api/package.json` So, it should look something like this after the changes:
`"dev": "set PORT=3003 && next dev"` Now, running `yarn workspace @calcom/api dev` should start the server.
Open [http://localhost:3003](http://localhost:3003/) with your browser to see the result.
If you wish to test how API works locally, please [check out our guide here](/developing/guides/api/how-to-setup-api-in-a-local-instance).
# Code styling
Source: https://cal.com/docs/developing/open-source-contribution/code-styling
Keeping our code styles consistent is key to making the repository easy to read and work with.
We use a number of style guides written by other amazing companies, simply because they are widely used and because we like working with them.
We don't expect you to study every single rule of each style guide, but these are great reference points as to how your code should be styled. We may reject a pull request if your code style significantly differs from these style guides however.
### ESLint & Prettier
Cal.com uses the ESLint and Prettier formatting tools, and the repository comes with defined rules for each tool. We recommend setting up both tools and using these to help automatically style your code to our guidelines.
### JavaScript/TypeScript
We use the
for all JavaScript and Typescript code.
### HTML & CSS
We use the [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html) for any HTML and CSS markup. However, exceptions to the HTML guide apply where JSX differentiates from standard HTML.
# Contributor's Guide
Source: https://cal.com/docs/developing/open-source-contribution/contributors-guide
## Introduction
Cal.com is structured as a monorepo using [Turborepo](https://github.com/vercel/turbo). Cal.com is built on [NextJS]("https://github.com/vercel/next.js") with [Typescript]("https://www.typescriptlang.org/"), [PostgreSQL]("https://www.postgresql.org/") database and the interactions with the database are carried out using [Prisma]("https://www.prisma.io/"). We use [TRPC]("https://trpc.io/") for end-to-end typesafe procedure calls to Prisma and utilize [Zod]("https://zod.dev/") for validation and type-safe parsing of API calls.
## Setting Up the Development Environment
### Prerequisites
Here is what you need to be able to run Cal.com.
* Node.js (Version: >=18.x)
* PostgreSQL
* Yarn (recommended)
Cal.com can be set up and run on your machine locally. Please take a look at [this quick guide](https://cal.com/docs/developing/local-development) for instructions on setting it up.
## Understanding the Project Structure
Cal.com makes use of Turborepo for a monorepo structure. This allows us to manage multiple code projects (like libraries, apps, services) and share code and resources effectively.
You can look at [turbo.json](https://github.com/calcom/cal.com/blob/main/turbo.json) to see how we use it. In simple terms,
* Each entry in the `pipeline` section corresponds to a different part of the project. Understanding these will help in navigating the codebase.
* Knowing which tasks depend on others is crucial for understanding the build process.
* The `env` entries under each task highlight the need for specific configuration settings, which you will need to set up in your development environment.
* You should focus on the tasks related to the area you are contributing to. For example, if working on the Prisma schema, look at tasks prefixed with `@calcom/prisma`
* The various packages can be found in the [/packages](https://github.com/calcom/cal.com/tree/main/packages) folder from the root.
* The various pages and components for the web can be found in the [/apps/web](https://github.com/calcom/cal.com/tree/main/apps/web) folder from the root.
* The public API related codebase can be found in the [/apps/api](https://github.com/calcom/cal.com/tree/main/apps/api) folder from the root.
* The Cal.ai related codebase can be found in the [/apps/ai](https://github.com/calcom/cal.com/tree/main/apps/ai) folder from the root
## File Naming Conventions
To ensure consistency and make files easy to fuzzy-find, we follow the naming conventions below for **services**, **repositories**, and other class-based files.
### Repository Files
* Repository class files must include the `Repository` suffix.
* If the repository is backed by a specific technology (e.g. Prisma), prefix the filename and class name with it.
* File name must match the exported class exactly (PascalCase).
**Pattern:**
Prisma``Repository.ts
**Examples:**
```js
// File: PrismaAppRepository.ts
export class PrismaAppRepository { ... }
// File: PrismaMembershipRepository.ts
export class PrismaMembershipRepository { ... }
```
This avoids ambiguous filenames like app.ts and improves discoverability in editors.
### Service Files
Service class files must include the Service suffix.
File name should be in PascalCase, matching the exported class.
Keep naming specific — avoid generic names like AppService.ts.
**Pattern:**
``Service.ts
**Examples:**
```js
// File: MembershipService.ts
export class MembershipService { ... }
// File: HashedLinkService.ts
export class HashedLinkService { ... }
```
New files must avoid dot-suffixes like .service.ts or .repository.ts; these will be migrated from the existing codebase progressively.\
We still reserve suffixes such as .test.ts, .spec.ts, and .types.ts for their respective use cases.
## How we use TRPC at cal.com
Cal.com makes use of the TRPC calls for CRUD operations on the database by utilizing the [useQuery()](https://trpc.io/docs/client/react/useQuery) & [useMutation()](https://trpc.io/docs/client/react/useMutation) hooks. These are essentially wrappers around @tanstack/react-query and you can learn more about them here, respectively: [queries](https://tanstack.com/query/v4/docs/react/guides/queries), [mutations](https://tanstack.com/query/v4/docs/react/guides/mutations).
Here’s an example usage of useQuery at cal.com:
```JS
const { data: webhooks } = trpc.viewer.webhook.list.useQuery(undefined, {
suspense: true,
enabled: session.status === "authenticated",
});
```
Here’s an example usage of useMutation at cal.com:
```JS
const createWebhookMutation = trpc.viewer.webhook.create.useMutation({
async onSuccess() {
showToast(t("webhook_created_successfully"), "success");
await utils.viewer.webhook.list.invalidate();
router.back();
},
onError(error) {
showToast(`${error.message}`, "error");
},
});
```
Both the examples are taken from [packages/features/webhooks/pages/webhook-new-view.tsx](https://github.com/calcom/cal.com/blob/main/packages/features/webhooks/pages/webhook-new-view.tsx) file. We use the useQuery hook for fetching data from the database. On the contrary, the useMutation hook is used for Creating/Updating/Deleting data from the database.
The path prior to the useQuery or useMutation hook represents the actual path of the procedure: in this case, [packages/trpc/server/routers/viewer/webhook](https://github.com/calcom/cal.com/tree/main/packages/trpc/server/routers/viewer/webhook). You will find `create.handler.ts` in case of
```js
trpc.viewer.webhook.create.useMutation()
```
& `list.handler.ts` in case of
```js
trpc.viewer.webhook.list.useQuery()
```
in the path mentioned above. There is usually a schema file in the same directory for each handler as well (*name*.schema.ts). This is generally how we make use of the TRPC calls in the cal.com repo.
## The Cal.com API V1
Our [API V1](https://github.com/calcom/cal.com/tree/main/apps/api) uses [zod validations](https://zod.dev/) to keep us typesafe and give us extensive parsing control and error handling. These validations reside in [/apps/api/lib/validations](https://github.com/calcom/cal.com/tree/main/apps/api/lib/validations). We also have [helper](https://github.com/calcom/cal.com/tree/main/apps/api/lib/helpers) and [utility](https://github.com/calcom/cal.com/tree/main/apps/api/lib/utils) functions which are used primarily within our API endpoints.
Here’s an example usage of our [zod validation in action with the respective API endpoint](https://github.com/calcom/cal.com/blob/main/apps/api/lib/validations/destination-calendar.ts):
```js
export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.pick({
integration: true,
externalId: true,
eventTypeId: true,
bookingId: true,
userId: true,
}).partial();
const schemaDestinationCalendarCreateParams = z
.object({
integration: z.string(),
externalId: z.string(),
eventTypeId: z.number().optional(),
bookingId: z.number().optional(),
userId: z.number().optional(),
})
.strict();
export const schemaDestinationCalendarCreateBodyParams = schemaDestinationCalendarBaseBodyParams.merge(
schemaDestinationCalendarCreateParams
);
```
And here’s the usage of this validation for parsing the request at the [respective endpoint](https://github.com/calcom/cal.com/blob/main/apps/api/pages/api/destination-calendars/_post.ts):
```js
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma, body } = req;
const parsedBody = schemaDestinationCalendarCreateBodyParams.parse(body);
```
This is the general approach of validation and parsing in our API submodule.
## Building Apps for Cal.com
We’ve got an app store containing apps which complement the scheduling platform. From video conferencing apps such as Zoom, Google Meet, etc. to Calendar Apps such as Google Calendar, Apple Calendar, CalDAV, etc. and even payment, automation, analytics and other miscellaneous apps, it is an amazing space to improve the scheduling experience.
We have a CLI script in place that makes building apps a breeze. [You can learn more about it here](https://cal.com/docs/how-to-guides/how-to-build-an-app).
## Running Tests
### E2E-Testing
Be sure to set the environment variable `NEXTAUTH_URL` to the correct value. If you are running locally, as the documentation within `.env.example` mentions, the value should be `http://localhost:3000`.
In a terminal just run:
```bash
yarn test-e2e
```
To open the last HTML report run:
```bash
`yarn playwright show-report test-results/reports/playwright-html-report`
```
#### Resolving issues
**E2E test browsers not installed**
If you face the following error when running `yarn test-e2e`:
Executable doesn't exist at /Users/alice/Library/Caches/ms-playwright/chromium-1048/chrome-mac/Chromium.app
You can resolve it by running:
```bash
npx playwright install
```
to download test browsers.
## Contribution and Collaboration Guides
* [Code Styling Guide](/developing/open-source-contribution/code-styling)
* [Pull Requests Guide](/developing/open-source-contribution/pull-requests)
# Introduction
Source: https://cal.com/docs/developing/open-source-contribution/introduction
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
* Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission.
### Priorities
| Type of issue | Priority |
| :--------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Minor improvements, non-core feature requests | |
| Confusing UX (... but working) | |
| Core Features (Booking page, availability, timezone calculation) | |
| Core Bugs (Login, Booking page, Emails are not working) | |
### Developing
The development branch is `main`. This is the branch that all pull
requests should be made against. The changes on the `main`
branch are tagged into a release monthly.
To develop locally:
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your
own GitHub account and then
[clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
2. Create a new branch:
```bash
git checkout -b MY_BRANCH_NAME
```
3. Install yarn:
```bash
npm install -g yarn
```
4. Install the dependencies with:
```bash
yarn
```
5. Start developing and watch for code changes:
```bash
yarn dev
```
### Building
You can build the project with:
```bash
yarn build
```
Please be sure that you can make a full production build before pushing code.
### Testing
More info on how to add new tests coming soon.
### Running tests
This will run and test all flows in multiple Chromium windows to verify that no critical flow breaks:
```bash
yarn test-e2e
```
### Linting
To check the formatting of your code:
```bash
yarn lint
```
If you get errors, be sure to fix them before committing.
### Making a Pull Request
* Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) while creating you PR.
* If your PR refers to or fixes an issue, be sure to add `refs #XXX` or `fixes #XXX` to the PR description. Replacing `XXX` with the respective issue number. See more about [Linking a pull request to an issue
](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
* Be sure to fill the PR Template accordingly.
### Guidelines for committing yarn lockfile
Do not commit your `yarn.lock` unless you've made changes to the `package.json`. If you've already committed `yarn.lock` unintentionally, follow these steps to undo:
If your last commit has the `yarn.lock` file alongside other files and you only wish to uncommit the `yarn.lock`:
```git
git checkout HEAD~1 yarn.lock
git commit -m "Revert yarn.lock changes"
```
If you've pushed the commit with the `yarn.lock`:
1. Correct the commit locally using the above method.
2. Carefully force push:
```git
git push origin --force
```
If `yarn.lock` was committed a while ago and there have been several commits since, you can use the following steps to revert just the `yarn.lock` changes without impacting the subsequent changes:
1. **Checkout a Previous Version**:
* Find the commit hash before the `yarn.lock` was unintentionally committed. You can do this by viewing the Git log:
```git
git log yarn.lock
```
* Once you have identified the commit hash, use it to checkout the previous version of `yarn.lock`:
```git
git checkout yarn.lock
```
2. **Commit the Reverted Version**:
* After checking out the previous version of the `yarn.lock`, commit this change:
```git
git commit -m "Revert yarn.lock to its state before unintended changes"
```
3. **Proceed with Caution**:
* If you need to push this change, first pull the latest changes from your remote branch to ensure you're not overwriting other recent changes:
```git
git pull origin
```
* Then push the updated branch:
```git
git push origin
```
# Pull requests
Source: https://cal.com/docs/developing/open-source-contribution/pull-requests
### Requirements
We have a number of requirements for PRs to ensure they are as easy to review as possible and to ensure that they are up to standard with the code.
### Title & Content
Start by providing a short and concise title. Don’t put something generic (e.g. bug fixes), and instead mention more specifically what your PR achieves, for instance “Fixes dropdown not expanding on settings page”.
For the PR description, you should go into much greater detail about what your PR adds or fixes. Firstly, the description should include a link to any relevant issues or discussions surrounding the feature or bug that your PR addresses.
### Feature PRs
Give a functional overview of how your feature works, including how the user can use the feature. Then, share any technical details in an overview of how the PR works (e.g. “Once the user enters their password, the password is hashed using BCrypt and stored in the Users database field”).
### Bug Fix PRs
Give an overview of how your PR fixes the bug both as a high-level overview and a technical explanation of what caused the issue and how your PR resolves this.
Feel free to add a short video or screenshots of what your PR achieves. Loom is a great way of sharing short videos.
### Code Quality & Styling
All submitted code must match our [code styling](./code-styling) standards. We will reject pull requests that differ significantly from our standardised code styles.
All code is automatically checked by Codacy and our linting process, and will notify you if there are any issues with the code that you submit. We require that code passes these quality checks before merging.
### PR review process
At least two members of the Cal.com team should review and approve any PR before it is merged.
Once two members of the team have approved this, someone from the team will merge the PR. If you are part of the Cal.com team, you should merge your own PRs once you have received both approvals.
# Apple calendar connect
Source: https://cal.com/docs/platform/atoms/apple-calendar-connect
The Apple calendar connect button is used to effortlessly syncs a user's apple calendar. This allows users to create, view and edit events, with options available for type and time all from the platform.
Below code snippet can be used to render the Apple calendar connect button
```js
import { Connect } from "@calcom/atoms";
export default function ConnectCalendar() {
return (
<>
>
);
}
```
For a demonstration of the Apple calendar connect integration, please refer to the video below.
The apple calendar atom works a bit differently than outlook and google calendar. We don’t get redirected to an OAuth consent page, instead a modal appears which prompts us to create an app specific password to use with Cal.com
Similar to Outlook and Google calendar, the Apple calendar connect supports integration for both single and multiple users. The above video demonstration showcases the integration for a single user. To enable integration for multiple users, simply pass the prop `isMultiCalendar` as `true`.
Below code snippet can be used to render the Apple calendar connect button for multiple users
```js
import { Connect } from "@calcom/atoms";
export default function ConnectCalendar() {
return (
<>
>
);
}
```
For a demonstration of the Apple calendar connect integration for multiple users, please refer to the video below.
We offer all kinds of customizations to the Outlook calendar connect via props. Below is a list of props that can be passed to the Google calendar connect.
| Name | Required | Description |
| :-------------------- | :------- | :------------------------------------------------------------------------ |
| className | No | To pass in custom classnames from outside for styling the atom |
| label | No | The label for the connect button |
| alreadyConnectedLabel | No | Label to display when atom is in already connected state |
| loadingLabel | No | Label to display when atom is in loading state |
| onCheckError | No | A callback function to handle errors when checking the connection status |
| initialData | No | Initial data to be passed |
| isMultiCalendar | No | Specifies if the button supports integration for multiple users |
| tooltip | No | In case user wants to pass external tooltip component |
| tooltipSide | No | Specifies what direction the tooltip appears |
| isClickable | No | Boolean to disable button or not |
| onSuccess | No | A callback function to handle success when checking the connection status |
If you try to put your Apple Id password in the password field, it will throw an error. It only accepts an
app specific password generated from [https://appleid.apple.com/account/manage](https://appleid.apple.com/account/manage).
# Availability settings
Source: https://cal.com/docs/platform/atoms/availability-settings
The availability settings atom enables a user to set their available time slots. This atom allows users to define specific time slots when they are available for meetings or events, helping them manage their schedules effectively and avoid double bookings.
First, for the AvailabilitySettings toggle animation to work set the reading direction on the `` element:
```html
...
```
Below code snippet can be used to render the availability settings atom
```js
import { AvailabilitySettings } from "@calcom/atoms";
export default function Availability() {
return (
<>
{
console.log("Updated schedule successfully");
}}
onDeleteSuccess={() => {
console.log("Deleted schedule successfully");
}}
onFormStateChange={(formState) => {
console.log("Form state updated");
// Access form data: formState.name, formState.schedule, formState.timeZone, etc.
}}
/>
>
)
}
```
For a demonstration of the availability settings atom, please refer to the video below.
If a user wishes to add further adjustments to their availability for special occasions or events, they can use the date overrides feature. Date overrides enables users to pick any date that they're currently available and set specific hours for availability on that day or mark themselves entirely unavailable. Once that day is passed, the date override is automatically deleted.
Below code snippet can be used to render date overrides into the availability settings atom
```js
import { AvailabilitySettings } from "@calcom/atoms";
export default function Availability() {
return (
<>
{
console.log("Updated schedule successfully");
}}
onDeleteSuccess={() => {
console.log("Deleted schedule successfully");
}}
onFormStateChange={(formState) => {
console.log("Form state changed:", formState);
// Access form data including dateOverrides: formState.dateOverrides
}}
/>
>
)
}
```
For a demonstration of the availability settings atom with date overrides, please refer to the video below.
We offer all kinds of customizations to the availability settings atom via props and customClassNames.
Below is a list of props that can be passed to the availability settings atom.
| Name | Required | Description |
| :--------------------- | :------- | :--------------------------------------------------------------------------------------------------------------- |
| id | No | The ID of the schedule which fetches a user's availability |
| labels | No | Helpful if you want to pass in custom labels for i18n |
| customClassNames | No | To pass in custom classnames from outside for styling the atom |
| onUpdateSuccess | No | A callback function to handle updating user availability successfully |
| onBeforeUpdate | No | Validates schedule before it is sent to the server; if true, the schedule is sent, else it is not |
| onUpdateError | No | A callback function that gets triggered when the user availability fails to update |
| onDeleteSuccess | No | A callback function that gets triggered when the user availability is deleted successfully |
| onDeleteError | No | A callback function that gets triggered when the user availability fails to delete |
| onFormStateChange | No | A callback function that gets triggered whenever the form state changes, providing real-time access to form data |
| enableOverrides | No | Allows user to enable or disable date overrides display in the atom; defaults to disabled |
| disableEditableHeading | No | Prevents users from editing the heading |
| allowDelete | No | When set to false, this prop hides the delete button |
| allowSetToDefault | No | When set to false, this prop hides the set to default toggle |
| disableToasts | No | Allows users to enable or disable toast notifications, with the default setting being disabled. |
Along with the props, Availability settings atom accepts custom styles via the **customClassNames** prop. Below is a list of props that fall under this **customClassNames** prop.
| Name | Description |
| :----------------------- | :------------------------------------------------------------------------------------ |
| containerClassName | Adds styling to the whole availability settings component |
| ctaClassName | Adds stylings only to certain call-to-action buttons |
| editableHeadingClassName | Editable heading or title can be styled |
| formClassName | Form which contains the days and toggles |
| timezoneSelectClassName | Adds styling to the timezone select component |
| subtitlesClassName | Styles the subtitle |
| scheduleClassNames | An object for granular styling of schedule components (see detailed table below) |
| dateOverrideClassNames | An object for granular styling of date override components (see detailed table below) |
### scheduleClassNames Object Structure
The `scheduleClassNames` prop accepts an object with the following structure for granular styling of schedule components:
| Property Path | Description |
| :------------------------ | :----------------------------------------------------------------------------------------- |
| `schedule` | Styles the entire schedule component |
| `scheduleContainer` | Styles the schedule container |
| `scheduleDay` | Adds styling to just the day of a particular schedule |
| `dayRanges` | Adds styling to day ranges |
| `timeRangeField` | Styles the time range input fields |
| `labelAndSwitchContainer` | Adds styling to label and switches |
| `timePicker` | An object for granular styling of time picker dropdown components (see nested table below) |
#### timePicker Object Structure (nested within scheduleClassNames)
The `timePicker` prop accepts an object with the following structure for granular styling of time picker dropdown components. This applies to the time selection dropdowns (e.g., \[ 9:00 ]) that users can click to open a dropdown with available times or click to manually enter a time:
| Property Path | Description |
| :--------------- | :------------------------------------------------- |
| `container` | Styles the main time picker container |
| `valueContainer` | Styles the container that holds the selected value |
| `value` | Styles the displayed selected time value |
| `input` | Styles the input field for manual time entry |
| `dropdown` | Styles the dropdown menu with time options |
### dateOverrideClassNames Object Structure
The `dateOverrideClassNames` prop accepts an object with the following structure for granular styling of date override components:
| Property Path | Description |
| :------------ | :------------------------------------- |
| `container` | Styles the main container |
| `title` | Styles the title |
| `description` | Styles the description |
| `button` | Styles the button to add date override |
Please ensure all custom classnames are valid [Tailwind CSS](https://tailwindcss.com/) classnames.
## Programmatic Form Validation and Submission
The AvailabilitySettings component supports programmatic form validation and submission through a ref-based API. This allows you to validate availability data and submit forms programmatically without user interaction.
```js
import { useRef } from 'react';
import { AvailabilitySettings } from "@calcom/atoms";
import type { AvailabilitySettingsFormRef } from "@calcom/atoms";
export function AvailabilityWithValidation() {
const availabilityRef = useRef(null);
const handleValidate = async () => {
const result = await availabilityRef.current?.validateForm();
if (result?.isValid) {
console.log("Availability form is valid");
} else {
console.log("Validation errors:", result?.errors);
}
};
const handleSubmit = () => {
availabilityRef.current?.handleFormSubmit({
onSuccess: () => {
// Additional success handling logic here
console.log('Availability updated successfully');
},
onError: (error) => {
// Additional error handling logic here
console.error('Error updating availability:', error);
}
});
};
return (
<>
{
console.log("Updated schedule successfully");
}}
onFormStateChange={(formState) => {
console.log("Form state changed:", formState);
}}
/>
>
);
}
```
### Ref Methods
| Method | Description |
| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| validateForm | Validates the current availability form state and returns a promise with validation results. |
| handleFormSubmit | Programmatically submits the availability form, triggering the same validation and submission flow as clicking the save button. Unlike `validateForm`, this method will check required fields and prevent submission unless all required fields are set |
### Callbacks
The `handleFormSubmit` method accepts an optional callbacks object with the following properties:
```typescript
type AvailabilitySettingsFormCallbacks = {
onSuccess?: () => void;
onError?: (error: Error) => void;
};
```
* **onSuccess**: Called when the form submission is successful. This allows you to execute additional logic after a successful update.
* **onError**: Called when an error occurs during form submission. The error parameter contains details about what went wrong, allowing you to handle specific error cases or display custom error messages.
The `validateForm` method returns an `AvailabilityFormValidationResult` object with:
* `isValid`: Boolean indicating if the form passed validation
* `errors`: Object containing any validation errors found
**Note:** If a required field is not filled in, the `validateForm` method will not return any error. The validation focuses on the format and consistency of provided data rather than enforcing required field completion.
# Booker
Source: https://cal.com/docs/platform/atoms/booker
The booker atom is a dynamic component that facilitates the booking process for users. It allows individuals to easily select available time slots and confirm their participation in various events, streamlining the scheduling experience. It is one of the most important atoms and a critical piece of our scheduling system.
Below code snippet can be used to render the booker atom
```js
import { Booker } from "@calcom/atoms";
export default function Booker( props : BookerProps ) {
return (
<>
{
console.log("booking created successfully");
}}
/>
>
)
}
```
For a demonstration of the booker atom, please refer to the video below.
It is also possible to change the booker layout into a week or column view, you just need to pass in the view prop the layout you want to use. The layouts are as follows: **MONTH\_VIEW,** **WEEK\_VIEW** and **COLUMN\_VIEW**. Both the week and column layouts come with an Overlay Calendar feature, which allows users to overlay multiple calendars on top of their primary calendar.
Below code snippet can be used to render the booker atom with week view
```js
import { Booker } from "@calcom/atoms";
export default function Booker( props : BookerProps ) {
return (
<>
{
console.log("booking created successfully");
}}
/>
>
)
}
```
For a demonstration of the booker atom along with calendar overlay, please refer to the video below.
We offer all kinds of customizations to the booker atom via props and customClassNames.
Below is a list of props that can be passed to the booker atom.
| Name | Required | Description |
| :------------------------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| username | Yes | Username of the person whose schedule is to be displayed |
| eventSlug | Yes | Unique slug created for a particular event |
| orgBannerUrl | No | URL of the user's current organization |
| customClassNames | No | To pass in custom classnames from outside for styling the atom |
| month | No | The exact month for displaying a user's availability; defaults to the current month |
| selectedDate | No | Default selected date for which the slot picker opens |
| startTime | No | Custom start time for the Booker that allows users to decide the first available date. Accepts JavaScript Date object or date string in format `YYYY-MM-DD` (e.g., `"2025-08-20"` or `new Date("2025-08-20")`) |
| hideBranding | No | For hiding any branding on the booker |
| isAway | No | Sets the booker component to the away state |
| allowsDynamicBooking | No | Boolean indicating if the booking is a dynamic booking |
| bookingData | No | Data for rescheduling a booking passed in via this prop |
| defaultFormValues | No | Prefilled values for booking form fields like name, email, guests, notes, reschedule reason, etc. |
| isTeamEvent | No | Boolean indicating if it is a team event |
| duration | No | Refers to a multiple-duration event type; selects default if not passed |
| durationConfig | No | Configures selectable options for a multi-duration event type |
| hashedLink | No | Refers to the private link from event types page |
| isInstantMeeting | No | Boolean indicating if the booking is an instant meeting |
| rescheduleUid | No | Unique ID generated during rescheduling |
| bookingUid | No | Unique ID generated during booking |
| locationUrl | No | Custom meeting link URL instead of a Cal.com link |
| firstName | No | First name of the attendee |
| lastName | No | Last name of the attendee |
| guests | No | Invite a guest to join a meeting |
| name | No | Host name |
| onCreateBookingSuccess | No | Callback function for successful booking creation |
| onCreateBookingError | No | Callback function triggered on booking creation failure |
| onCreateRecurringBookingSuccess | No | Callback function for successful recurring booking creation |
| onCreateRecurringBookingError | No | Callback function triggered on recurring booking creation failure |
| onCreateInstantBookingSuccess | No | Callback function for successful instant booking creation |
| onCreateInstantBookingError | No | Callback function triggered on instant booking creation failure |
| onReserveSlotSuccess | No | Callback function for successful slot reservation |
| onReserveSlotError | No | Callback function triggered on slot reservation failure |
| onDeleteSlotSuccess | No | Callback function for successful slot deletion |
| onDeleteSlotError | No | Callback function triggered on slot deletion failure |
| view | No | Specifies the layout of the booker atom into column, week, or month view |
| metadata | No | Used to pass custom metadata values into the booker. Metadata should be an object eg: `{ bookingSource: "website", userRole: "admin" }` |
| bannerUrl | No | Adds custom banner to the booker atom |
| onBookerStateChange | No | Callback function that is triggered when the state of the booker atom changes. |
| allowUpdatingUrlParams | No | Boolean indicating if the URL parameters should be updated, defaults to false. |
| confirmButtonDisabled | No | Boolean indicating if the submit button should be disabled, defaults to false. |
| timeZones | No | Array of valid IANA timezones to be used in the booker. Eg. \["Asia/Kolkata", "Europe/London"] |
| onTimeslotsLoaded | No | Callback function triggered once the available timeslots have been fetched. |
| roundRobinHideOrgAndTeam | No | Boolean indicating if the organization and team should be hidden in the booker atom sidebar for round robin scheduling type, defaults to false. |
| showNoAvailabilityDialog | No | Boolean indicating if the no availability dialog should be shown, defaults to true. |
| silentlyHandleCalendarFailures | No | Boolean when true the booker still displays slots when the third party calendars credentials are invalid or expired, Booker may show stale availability when enabled |
| hideEventMetadata | No | Boolean that controls the visibility of the event metadata sidebar. When `true`, hides the left sidebar containing event details like title, description, duration, and host information. Defaults to `false`. |
## Styling
Booker atom accepts custom styles via the `customClassNames` prop. This prop is an object that contains root level styles and nested objects for styling different parts of the booker component. Each nested object groups related styles for a specific section of the booker (e.g., eventMeta, datePicker, availableTimeSlots, etc).
Here is an example booker with root level style `bookerContainer` and nested object `datePickerCustomClassNames` with `datePickerDatesActive` style:
```js
import { Booker } from "@calcom/atoms";
export default function Booker( props : BookerProps ) {
return (
<>
>
)
}
```
Below is a list of **customClassNames** properties grouped by their parent objects:
### Root Level Styles
| Property | Description |
| :-------------- | :------------------------------------------- |
| bookerContainer | Adds styling to the whole of the booker atom |
### Event Meta Styles (`eventMetaCustomClassNames`)
| Property | Description |
| :---------------------- | :---------------------------------------------------------------- |
| eventMetaContainer | Styles the event meta component containing details about an event |
| eventMetaTitle | Adds styles to the event meta title |
| eventMetaTimezoneSelect | Adds styles to the event meta timezone selector |
### Date Picker Styles (`datePickerCustomClassNames`)
| Property | Description |
| :-------------------- | :------------------------------------------- |
| datePickerContainer | Adds styling to the date picker |
| datePickerTitle | Styles the date picker title |
| datePickerDays | Adds styling to all days in the date picker |
| datePickerDate | Adds styling to all dates in the date picker |
| datePickerDatesActive | Styles only the dates with available slots |
| datePickerToggle | Styles the left and right toggle buttons |
### Available Time Slots Styles (`availableTimeSlotsCustomClassNames`)
| Property | Description |
| :--------------------------------- | :------------------------------------------------- |
| availableTimeSlotsContainer | Adds styling to the available time slots component |
| availableTimeSlotsHeaderContainer | Styles only the header container |
| availableTimeSlotsTitle | Adds styles to the title |
| availableTimeSlotsTimeFormatToggle | Adds styles to the format toggle buttons |
| availableTimes | Styles all the available times container |
### Confirmation Step Styles (`confirmStep`)
| Property | Description |
| :------------ | :-------------------------------------------- |
| confirmButton | Styles the confirm button in the booking form |
| backButton | Styles the back button in the booking form |
Here is an example with more custom styles:
```js
import { Booker } from "@calcom/atoms";
export default function Booker( props : BookerProps ) {
return (
<>
>
)
}
```
# Cal Provider
Source: https://cal.com/docs/platform/atoms/cal-provider
Cal Provider is used to setup scheduling within your app. It is used in the root of your app, be it \_app.js or or \_app.tsx in case of
Next.js or App.js or App.ts in case of React. Here is an example:
```js
import "@calcom/atoms/globals.min.css";
import { CalProvider } from '@calcom/atoms';
function MyApp({ Component, pageProps }) {
const accessToken = "managed-user-access-token";
return (
);
}
export default MyApp;
```
Below is a list of props that can be passed to the Cal Provider.
| Name | Required | Description |
| :----------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| clientId | Yes | Your OAuth client ID |
| options | Yes | Configuration options - `apiUrl` (should be [https://api.cal.com/v2](https://api.cal.com/v2)) and `refreshUrl` (URL of endpoint you have to build that to which atoms will send expired access tokens and receive new one in return. Read how to set it up [here](https://cal.com/docs/platform/quickstart#4-backend%3A-setting-up-a-refresh-token-endpoint)) and `readingDirection` (defaults to "ltr" but can also pass "rtl" which will change direction of UI components) |
| accessToken | No | The access token of your managed user for whom cal handles scheduling. |
| autoUpdateTimezone | No | Whether to automatically update managed user timezone (default: true) |
| language | No | Language code (default: "en") |
| organizationId | No | ID of your organization |
# Calendar settings
Source: https://cal.com/docs/platform/atoms/calendar-settings
The calendar settings atom can be used to configure how your event types interact with your calendars. This atom gives you the ability to select where to add events when you're booked. Additionally, you can also select which calendars you want to check for conflicts to prevent double bookings.
Below code snippet can be used to render the calendar settings button
```js
import { CalendarSettings } from "@calcom/atoms";
export default function CalendarSettingsComponent() {
return (
<>
>
)
}
```
For a demonstration of the calendar settings atom, please refer to the video below.
Customizations can be done to the calendar settings atom via props and classnames. Below is a list of props that can be passed to the calendar settings atom
| Name | Required | Description |
| :--------- | :------- | :------------------------------------------------------------- |
| classNames | No | To pass in custom classnames from outside for styling the atom |
Along with the props, calendar settings atom accepts custom styles via the **classNames** prop. Below is a list of props that fall under this **classNames** prop.
| Name | Description |
| :------------------------------------------ | :------------------------------------------------------------------------------------------ |
| calendarSettingsCustomClassnames | Adds styling to the entire calendar settings atom |
| destinationCalendarSettingsCustomClassnames | Adds styling only to the destination calendar container |
| selectedCalendarSettingsCustomClassnames | Adds styling only to the selected calendar container |
| selectedCalendarSettingsClassNames | An object for granular styling of selected calendars component (see detailed table below) |
| destinationCalendarSettingsClassNames | An object for granular styling of destination calendar component (see detailed table below) |
### selectedCalendarSettingsClassNames Object Structure
The `selectedCalendarSettingsClassNames` prop accepts an object with the following nested structure for granular styling of the selected calendars component:
| Property Path | Description |
| :-------------------------------------------------------------------- | :---------------------------------------------------------- |
| `container` | Styles the main container of the selected calendars section |
| `header.container` | Styles the header container |
| `header.title` | Styles the header title |
| `header.description` | Styles the header description |
| `selectedCalendarsListClassNames.container` | Styles the container that holds all selected calendar items |
| `selectedCalendarsListClassNames.selectedCalendar.container` | Styles each individual calendar item container |
| `selectedCalendarsListClassNames.selectedCalendar.header.container` | Styles the header section of each calendar item |
| `selectedCalendarsListClassNames.selectedCalendar.header.title` | Styles the title of each calendar item |
| `selectedCalendarsListClassNames.selectedCalendar.header.description` | Styles the description of each calendar item |
| `selectedCalendarsListClassNames.selectedCalendar.body.container` | Styles the body section of each calendar item |
| `selectedCalendarsListClassNames.selectedCalendar.body.description` | Styles the body description of each calendar item |
| `noSelectedCalendarsMessage` | Styles the message shown when no calendars are connected |
### destinationCalendarSettingsClassNames Object Structure
The `destinationCalendarSettingsClassNames` prop accepts an object with the following nested structure for granular styling of the destination calendar component:
| Property Path | Description |
| :------------------- | :------------------------------------------------------------ |
| `container` | Styles the main container of the destination calendar section |
| `header.title` | Styles the header title text |
| `header.description` | Styles the header description text |
Additionally, if you wish to select either the Destination Calendar or the Selected Calendar, we also provide atoms specifically designed for this purpose.
**1. Destination calendar settings atom**
The destination calendar settings atom lets you can select which calendar you want to add events to when you're booked. Below code snippet can be used to render the destination calendar settings atom.
```js
import { DestinationCalendarSettings } from "@calcom/atoms";
export default function DestinationCalendars() {
const loadingStatus = <>Loading...>
return (
<>
>
)
}
```
This is how the destination calendar settings atom looks:
Customizations can be done to the destination calendar settings atom via props. Below is a list of props that can be passed to the calendar settings atom
| Name | Required | Description |
| :----------- | :------- | :------------------------------------------------------------- |
| statusLoader | No | To pass in a custom component for the loading state |
| classNames | No | To pass in custom classnames from outside for styling the atom |
**2. Selected calendar settings atom**
The selected calendar settings atom lets you select which calendars you want to check for conflicts to prevent double bookings. Below code snippet can be used to render the selected calendar settings atom.
```js
import { SelectedCalendarsSettings } from "@calcom/atoms";
export default function SelectedCalendars( props : SelectedCalendarsProps ) {
return (
<>
>
)
}
```
This is how the selected calendar settings atom looks:
Customizations can be done to the destination calendar settings atom via props. Below is a list of props that can be passed to the calendar settings atom
| Name | Required | Description |
| :--------- | :------- | :------------------------------------------------------------- |
| classNames | No | To pass in custom classnames from outside for styling the atom |
# Conferencing Apps
Source: https://cal.com/docs/platform/atoms/conferencing-apps
The Conferencing Apps Atom allows users to seamlessly install applications such as Zoom, Google Meet, and Microsoft Teams, enabling them to set these as default or optional locations for their events.
Below code snippet can be used to render Conferencing Apps Atom
```js
import { ConferencingAppsSettings } from "@calcom/atoms";
import { usePathname } from "next/navigation";
export default function ConferencingApps() {
const pathname = usePathname();
const callbackUri = `${window.location.origin}${pathname}`;
return (
<>
>
)
}
```
Below is a list of props that can be passed to the Conferencing Apps Atom
| Name | Required | Description |
| :-------------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| returnTo | No | The URL of the page to redirect to after a successful installation. |
| onErrorReturnTo | No | The URL of the page to redirect to in case an error occurs. |
| disableToasts | No | Boolean value to disable toast notifications in the atom. |
| apps | No | Array of conferencing app slugs to display in the dropdown. If provided, only these apps will be shown (if not already installed). Valid values are `'google-meet'`, `'zoom'`, and `'msteams'`. |
| disableBulkUpdateEventTypes | No | A Boolean flag that prevents the bulk update of event types modal from appearing when the default conferencing app is changed. Defaults to false |
## Google Meet
For a demonstration of installing Google Meet, setting it as the default conferencing app for all event types, and removing the app, please watch the video below.
Google meet requires Google Calendar to be installed first
## Zoom
For a demonstration of installing Zoom, setting it as the default conferencing app for all event types, and removing the app, please watch the video below.
## MS Teams Video
For a demonstration of installing MS Teams Video, setting it as the default conferencing app for all event types, and removing the app, please watch the video below.
Connecting with MS Teams requires a work/school Microsoft account.
If you continue with a personal account you will receive an error
# Event Type
Source: https://cal.com/docs/platform/atoms/event-type
The event type atom enables a user to create events that others can use to book them. The events can be created for an individual or a team. However, a team event type can only be created by a team admin or owner.
## Individual event type
Below code snippet can be used to render the create event type atom, which is a form with all the required input fields needed to create an event type.
```js
import { CreateEventType } from "@calcom/atoms";
export default function EventType() {
return (
<>
{
console.log("EventType created successfully", eventType);
}}
customClassNames={{
atomsWrapper: "border p-4 rounded-md",
buttons: { submit: "bg-red-500", cancel: "bg-gray-300" },
}}
/>
>
)
}
```
For a demonstration of the create event type atom, please refer to the video below.
## Team event type
For creating an event type for a team, you need to provide the team id of your particular team as a prop to the create event type atom. Importantly, a team event type can only be created by a managed user who has an accepted admin or owner role within the team. That means
you have to create a managed user and then add an accepted membership with an admin or owner role by making a request to the [memberships endpoint](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership). Example body:
```js
{
"userId": 1006,
"accepted": true,
"role": "OWNER"
}
```
then you have to pass the access token of this managed user to the [CalProvider](https://cal.com/docs/platform/atoms/cal-provider) to then finally be able to
use the `` component while passing `teamId={teamId}` to it to create a team event type:
```js
import { CreateEventType } from "@calcom/atoms";
export default function TeamEventType(teamId: number) {
return (
<>
{
console.log("EventType created successfully", eventType);
}}
customClassNames={{
atomsWrapper: "border p-4 rounded-md",
buttons: { submit: "bg-red-500", cancel: "bg-gray-300" },
}}
/>
>
)
}
```
For a demonstration of the create event type atom, please refer to the video below.
Below is a list of props that can be passed to the create event type atom
| Name | Required | Description |
| :--------------- | :------- | :--------------------------------------------------------------------- |
| teamId | No | Unique identifier of the team |
| customClassNames | No | To pass in custom classnames from outside for styling the atom |
| onSuccess | No | Callback function that handles successful creation of event type |
| onError | No | Callback function to handles errors at the time of event type creation |
| onCancel | No | Callback function that handles cancellation of event type form |
Along with the props, create event type atom accepts custom styles via the **customClassNames** prop. Below is a list of props that fall under this **customClassNames** prop.
| Name | Description |
| :----------- | :----------------------------------------------------------------------------------------------- |
| atomsWrapper | Adds styling to the whole create event type atom |
| buttons | Object containing classnames for the submit and cancel buttons inside the create event type atom |
Individual and team event types take in the same props.
## Event type settings
The event type settings contains various tabs that can be used to configure or make modifications to the event type that has just been created.
Below code snippet can be used to render the event type settings atom.
```js
import { EventTypeSettings } from "@calcom/atoms";
export function EventTypeTabs(eventTypeId: number) {
return (
<>
{
console.log("EventType settings updated successfully", eventType);
}}
onFormStateChange={(formState) => {
console.log("Form state changed:", formState);
// Access form data: formState.isDirty, formState.dirtyFields, formState.values
}}
customClassNames={{ atomsWrapper: "!w-[70vw] !m-auto" }}
/>
>
);
}
```
If the `eventTypeId` is of a team event type id, then only the owner or admin of the team can update the event type settings. That means
you have to create a managed user and then add an accepted membership with an admin or owner role by making a request to the [memberships endpoint](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership). Example body:
```js
{
"userId": 1006,
"accepted": true,
"role": "OWNER"
}
```
then you have to pass the access token of this managed user to the [CalProvider](https://cal.com/docs/platform/atoms/cal-provider) to then finally be able to
use the `` component while passing id of a team event type enabling admin or owner to edit team event types.
For a demonstration of the event type settings atom, please refer to the video below.
Below is a list of props that can be passed to the event type settings atom.
| Name | Required | Description | |
| :---------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------- | - |
| id | Yes | The event type id obtained at the time of event type creation | |
| tabs | No | The tabs you want the event type settings to display | |
| onSuccess | No | Callback function that triggers when the event type is successfully updated | |
| onError | No | Callback function to handles errors at the time of event type update | |
| onFormStateChange | No | Callback function that triggers when the form state changes, providing access to isDirty, dirtyFields, and current form values | |
| onDeleteSuccess | No | Callback function that triggers when the event type is successfully deleted | |
| onDeleteError | No | Callback function that handles errors at the time of event type deletion | |
| allowDelete | No | Boolean value that determines whether the delete button is displayed or not | |
| disableToasts | No | Boolean value that determines whether the toasts are displayed or not | |
| customClassNames | No | To pass in custom classnames from outside for styling the atom | |
Along with the props, event type settings atom accepts custom styles via the **customClassNames** prop. Below is a list of props that fall under this **customClassNames** prop.
| Name | Description |
| :----------- | :------------------------------------------------- |
| atomsWrapper | Adds styling to the whole event type settings atom |
Please ensure all custom classnames are valid [Tailwind CSS](https://tailwindcss.com/) classnames.
## Programmatic Form Validation and Submission
The EventTypeSettings component supports programmatic form validation and submission through a ref-based API. This allows you to validate form data and submit forms programmatically without user interaction.
```js
import { useRef } from 'react';
import { EventTypeSettings } from "@calcom/atoms";
import type { EventTypePlatformWrapperRef } from "@calcom/atoms";
export function EventTypeWithValidation(eventTypeId: number) {
const eventTypeRef = useRef(null);
const handleValidate = async () => {
const result = await eventTypeRef.current?.validateForm();
if (result?.isValid) {
console.log("Form is valid");
} else {
console.log("Validation errors:", result?.errors);
}
};
const handleSubmit = () => {
eventTypeRef.current?.handleFormSubmit({
onSuccess: () => {
// Additional success handling logic here
console.log('Event type updated successfully');
},
onError: (error) => {
// Additional error handling logic here
console.error('Error updating event type:', error);
}
});
};
return (
<>
{
console.log("EventType updated successfully", eventType);
}}
/>
>
);
}
```
### Ref Methods
| Method | Description |
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| validateForm | Validates the current event type form state and returns a promise with validation results. |
| handleFormSubmit | Programmatically submits the event type form, triggering the same validation and submission flow as clicking the save button. Unlike `validateForm`, this method will check required fields and prevent submission unless all required fields are set |
### Callbacks
The `handleFormSubmit` method accepts an optional callbacks object with the following properties:
```typescript
type EventTypeFormCallbacks = {
onSuccess?: () => void;
onError?: (error: Error) => void;
};
```
* **onSuccess**: Called when the form submission is successful. This allows you to execute additional logic after a successful update.
* **onError**: Called when an error occurs during form submission. The error parameter contains details about what went wrong, allowing you to handle specific error cases or display custom error messages.
The `validateForm` method returns an `EventTypeFormValidationResult` object with:
* `isValid`: Boolean indicating if the form passed validation
* `errors`: Object containing any validation errors found
**Note:** If a required field is not filled in, the `validateForm` method will not return any error. The validation focuses on the format and consistency of provided data rather than enforcing required field completion.
Following are the tabs that are available in the event type settings atom:
**1. Event Setup**
The event setup tab allows users to configure the fundamental aspects of their events. In this tab, users can define or update essential details such as the event title, description, duration, slug, location as well as the event URL.
**2. Availability**
The availability tab allows users to manage their scheduling preferences effectively. Within this tab, users can edit their existing availability or set new availability options based on the preferences they have previously established.
For team event types, availability for a specific event can also be configured for the entire team based on a common schedule. Otherwise each host can be assigned their own specific availability based on their schedules.
**3. Assignment**
The assignment tab is only available for team event types. It lets you configure what kind of scheduling you want to enable for your team event, where you can choose from a collective, round robin or managed event. You can also choose who amongst your team can or cannot attend the event.
**4. Limits**
The limits tab lets you configure how often you can be booked. You can add a lot of configurations via this tab, such as a buffer time before or after the event and a minimum notice period.
Also if you want to select how many time a particular event can be booked, or how far in the future the event can be booked that is also possible. Or if you want to limit the event to a specific amount of time, that can also be done via the limits tab.
Below video shows a demonstration of the limits tab.
**5. Advanced**
The advanced tab lets you customize your event type with a lot more options. For example, you can set a custom name for the event type that will appear in your calendar, or add questions that will appear on your booking page. Another option would be to add an email verification for the person who is booking the event.
Below video shows a demonstration of the all the options you get in the advanced tab.
**6. Recurring**
The recurring tab lets you set up a recurring event. You can set up recurring events such as weekly, monthly, yearly, etc for a maximum of events you want it to repeat.
Recurring events are currently experimental and causes some issues sometimes when checking for availability. We are working on fixing this.
**7. Payments**
The payments tab lets you accept payments for your events. At the moment we only support payments via Stripe.
Once you connect your Stripe account, you can set a custom price along with the currency and payment option; which will determine when to charge your customers.
# Google calendar connect
Source: https://cal.com/docs/platform/atoms/google-calendar-connect
The Google calendar connect button is used to effortlessly syncs a user's google calendar. This allows users to create, view and edit events, with options available for type and time all from the platform.
Below code snippet can be used to render the Google calendar connect button
```js
import { Connect } from "@calcom/atoms";
export default function Connect() {
return (
<>
>
)
}
```
For a demonstration of the Google calendar connect integration, please refer to the video below.
Google calendar connect supports integration for both single and multiple users. The above video demonstration showcases the integration for a single user. To enable integration for multiple users, simply pass the prop `isMultiCalendar` as `true`. This allows your application to handle multiple Google calendar accounts seamlessly, providing a more flexible experience for users who manage several calendars.
Below code snippet can be used to render the Google calendar connect button for multiple users
```js
import { Connect } from "@calcom/atoms";
export default function Connect() {
return (
<>
>
)
}
```
For a demonstration of the Google calendar connect integration for multiple users, please refer to the video below.
We offer all kinds of customizations to the Google calendar connect via props. Below is a list of props that can be passed to the Google calendar connect.
| Name | Required | Description |
| :-------------------- | :------- | :---------------------------------------------------------------------------------------- |
| className | No | To pass in custom classnames from outside for styling the atom |
| label | No | The label for the connect button |
| alreadyConnectedLabel | No | Label to display when atom is in already connected state |
| loadingLabel | No | Label to display when atom is in loading state |
| onCheckError | No | A callback function to handle errors when checking the connection status |
| redir | No | A custom redirect URL link where the user gets redirected after successful authentication |
| initialData | No | Initial data to be passed |
| isMultiCalendar | No | Specifies if the button supports integration for multiple users |
| tooltip | No | In case user wants to pass external tooltip component |
| tooltipSide | No | Specifies what direction the tooltip appears |
| isClickable | No | Boolean to disable button or not |
| onSuccess | No | A callback function to handle success when checking the connection status |
Please ensure all custom classnames are valid Tailwind CSS classnames. Note that sometimes the custom
classnames may fail to override the styling with the classnames that you might have passed via props. That
is because the clsx utility function that we use to override classnames inside our components has some
limitations. A simple get around to solve this issue is to just prefix your classnames with ! property just
before passing in any classname.
# Outlook calendar connect
Source: https://cal.com/docs/platform/atoms/outlook-calendar-connect
The Outlook calendar connect button is used to effortlessly syncs a user's outlook calendar. This allows users to create, view and edit events, with options available for type and time all from the platform.
Below code snippet can be used to render the Google calendar connect button
```js
import { Connect } from "@calcom/atoms";
export default function ConnectCalendar() {
return (
<>
>
)
}
```
For a demonstration of the Google calendar connect integration, please refer to the video below.
Outlook calendar connect supports integration for both single and multiple users. The above video demonstration showcases the integration for a single user. To enable integration for multiple users, simply pass the prop `isMultiCalendar` as `true`. This allows your application to handle multiple Outlook calendar accounts seamlessly, providing a more flexible experience for users who manage several calendars.
Below code snippet can be used to render the Outlook calendar connect button for multiple users
```js
import { Connect } from "@calcom/atoms";
export default function ConnectCalendar() {
return (
<>
>
)
}
```
For a demonstration of the Outlook calendar connect integration for multiple users, please refer to the video below.
We offer all kinds of customizations to the Outlook calendar connect via props. Below is a list of props that can be passed to the Google calendar connect.
| Name | Required | Description |
| :-------------------- | :------- | :---------------------------------------------------------------------------------------- |
| className | No | To pass in custom classnames from outside for styling the atom |
| label | No | The label for the connect button |
| alreadyConnectedLabel | No | Label to display when atom is in already connected state |
| loadingLabel | No | Label to display when atom is in loading state |
| onCheckError | No | A callback function to handle errors when checking the connection status |
| redir | No | A custom redirect URL link where the user gets redirected after successful authentication |
| initialData | No | Initial data to be passed |
| isMultiCalendar | No | Specifies if the button supports integration for multiple users |
| tooltip | No | In case user wants to pass external tooltip component |
| tooltipSide | No | Specifies what direction the tooltip appears |
| isClickable | No | Boolean to disable button or not |
| onSuccess | No | A callback function to handle success when checking the connection status |
# Payment form
Source: https://cal.com/docs/platform/atoms/payment-form
The Payment form atom is a streamlined interface that integrates with Stripe to facilitate secure payment processing for bookings. It allows users to easily enter their payment information, ensuring a smooth and efficient transaction experience at the time of booking.
Below code snippet can be used to render the Payment form atom
```js
import { PaymentForm } from "@calcom/atoms";
export default function StripePaymentForm(uid: string) {
return (
<>
>
);
}
```
For a demonstration of the Payment form, please refer to the video below.
Below is a list of props that can be passed to the Payment form.
| Name | Required | Description |
| :---------------------------- | :------- | :----------------------------------------------------------------------------------- |
| paymentUid | Yes | The uid of the payment |
| onPaymentSuccess | No | Callback function to be executed upon successful payment processing |
| onPaymentCancellation | No | Callback function to be executed upon payment processing failure |
| onEventTypePaymentInfoSuccess | No | Callback function to be executed when payment information is successfully processed. |
| onEventTypePaymentInfoFailure | No | Callback function to be executed upon payment information processing failure. |
## Combining payment form with event types atom
The Payment form atom works best when combined with the event types atom to provide a seamless payment experience. In order to combine payment and event types atom, here are the steps we recommend:
The event types atom has a payments tab which you can use to connect your stripe account and set up payments info (price, currency, etc.)
Below code snippet can be used to setup the event types atom
```js
import { EventTypeSettings } from "@calcom/atoms";
export default function EventType(id: number) {
return (
<>
>
);
}
```
With this you're all set to accept payments for your bookings.
The booker atom has a prop called `onCreateBookingSuccess` which is a callback function that gets called at the time of a successful booking creation. This function takes a parameter called `data` which contains the payment uid and another property called paymentRequired which can be used to detect if the booking requires payment or not. You can use the payment uid to access the payment form atom.
Either store the payment uid in your database, a local state variable or pass it into another page as query parameters.
Below code snippet can be used to obtain the payment uid from the booker atom
```js
import { Booker } from "@calcom/atoms";
export default function Booker( props : BookerProps ) {
return (
<>
{
if (data.data.paymentRequired) {
// assuming you have set up a separate page for payment with the same path
// if using nextjs, better to use next/router
window.location.href = `/payment/${data.data.paymentUid}`;
}
}}
/>
>
)
}
```
We recommend setting up a separate page for the payment form for the sake of a smooth and streamlined flow, but you can also do it in the same page.
From the previous step, you get redirected to the payment page when the booking is created. You can now access the payment uid present in the query parameters and render the payment form atom.
Below code snippet can be used to obtain the payment uid and pass it to payment form atom.
```js
import { PaymentForm } from "@calcom/atoms";
export default function StripePaymentForm() {
// if using nextjs, better to use the usePathname hook
const pathname = window.location.pathname;
const uid = pathname.split("/").pop();
return (
<>
>
);
}
```
Below video shows a demonstration of how we combined the event types atom and payment form in one of our of our example app to create a seamless payment experience.
Link to the example app can be found [here](https://github.com/calcom/cal.com/tree/main/packages/platform/examples/base)
# Bookings hooks
Source: https://cal.com/docs/platform/bookings-hooks
Overview of all the hooks associated with bookings.
Optimize your development workflow using our custom hooks. Our custom hooks are designed to simplify the integration of the Cal.com API into your products. With these hooks, you can effortlessly manage state, handle side effects, and optimize performance, allowing you to focus on building exceptional user experiences without the hassle of complex API interactions.
Below is a list of hooks you can find that are associated with bookings. Notably, all of these hooks are available only for platform customers.
### 1. get all bookings - `useBookings`
The useBookings hook returns an array of bookings that belong to the user whose access token is passed to [\](https://cal.com/docs/platform/atoms/cal-provider). You can filter bookings by status, event type id, attendee email etc. - [see this class](https://github.com/calcom/cal.com/blob/307b2946a2cb6dcdb32dbee6c4f448e8a01c4285/packages/platform/types/bookings/2024-08-13/inputs/get-bookings.input.ts#L32) for filters you can pass to the hook.
Below code snippet shows how to use the useBookings hook to fetch bookings for a specific user using take, skip and status filters:
```js
import { useBookings } from "@calcom/atoms";
export default function Bookings() {
const { isLoading: isLoadingUpcomingBookings, data: upcomingBookings } = useBookings({
take: 50,
skip: 0,
status: ["upcoming"],
});
return (
<>
);
})}
>
);
}
```
### 2. get specific booking - `useBooking`
The useBooking hook returns detailed information about a single booking. Simply provide the booking's unique identifier ***(bookingUid)*** as a parameter to fetch its associated data.
Below code snippet shows how to use the useBooking hook to fetch a specific booking for a user.
```js
import { useBooking } from "@calcom/atoms";
export default function Booking() {
const { isLoading: isLoadingBooking, data: booking } = useBooking("nChHoxEm1GXVPzi7TNAuWc");
return (
<>
{isLoadingBooking &&
Loading...
}
{!isLoadingBooking && !booking &&
No booking found
}
{!isLoading &&
!!booking &&
return (
Title: {booking.title}
)
}
>
);
}
```
### 3. cancel booking - `useCancelBooking`
The useCancelBooking hook allows you to cancel a booking. This hook returns a mutation function that handles the cancellation process. To cancel a booking, you'll need to provide at least the booking's unique identifier ***(uid).*** While the uid is the only mandatory parameter, you can enhance the cancellation process by including optional parameters such as ***cancellationReason*** to specify why the booking is being canceled, and ***allRemainingBookings*** to specify whether to cancel all future recurring bookings.
Below code snippet shows how to use the useCancelBooking hook to cancel a booking for a user.
```js
import { useCancelBooking } from "@calcom/atoms";
export default function CancelBooking() {
const { mutate: cancelBooking } = useCancelBooking({
onSuccess: () => {
console.log("Booking canceled successfully!")
},
});
return (
<>
>
);
}
```
### 4. get all bookings of a user as an organization admin - `useOrganizationUserBookings`
The useBookings hooks returns bookings of user associated with the access token passed to the [\](https://cal.com/docs/platform/atoms/cal-provider), but this hook
allows organization admins to fetch bookings of any organization member.
The access token passed to the [\](https://cal.com/docs/platform/atoms/cal-provider) must belong
to a managed user who is an organization admin. That means you have to create a managed user and then add an accepted membership with an admin or owner role by making a request to the [organizations memberships endpoint](https://cal.com/docs/api-reference/v2/orgs-memberships/create-a-membership). Example body:
```js
{
"userId": 1006,
"accepted": true,
"role": "ADMIN"
}
```
then you have to pass the access token of this managed user to the [CalProvider](https://cal.com/docs/platform/atoms/cal-provider) to then finally be able to
use the "useOrganizationUserBookings" by specifying "userId" which will return an array of that user's bookings. You can filter bookings by status, event type id, attendee email etc. - [see this class](https://github.com/calcom/cal.com/blob/307b2946a2cb6dcdb32dbee6c4f448e8a01c4285/packages/platform/types/bookings/2024-08-13/inputs/get-bookings.input.ts#L32) for filters you can pass to the hook.
Below code snippet shows how to use the "useOrganizationUserBookings" hook to fetch bookings for a specific user using take, skip and status filters:
```js
import { useOrganizationUserBookings } from "@calcom/atoms";
export default function Bookings() {
const someUserId = 1218;
const { isLoading: isLoadingUpcomingBookings, data: upcomingBookings } = useOrganizationUserBookings(someUserId, {
take: 50,
skip: 0,
status: ["upcoming"],
});
return (
<>
);
})}
>
);
}
```
### 5. get all organization bookings as an organization admin - `useOrganizationBookings`
The useBookings hooks returns bookings of user associated with the access token passed to the [\](https://cal.com/docs/platform/atoms/cal-provider), but this hook
allows organization admins to fetch bookings of the whole organization.
The access token passed to the [\](https://cal.com/docs/platform/atoms/cal-provider) must belong
to a managed user who is an organization admin. That means you have to create a managed user and then add an accepted membership with an admin or owner role by making a request to the [organizations memberships endpoint](https://cal.com/docs/api-reference/v2/orgs-memberships/create-a-membership). Example body:
```js
{
"userId": 1006,
"accepted": true,
"role": "ADMIN"
}
```
then you have to pass the access token of this managed user to the [CalProvider](https://cal.com/docs/platform/atoms/cal-provider) to then finally be able to
use the "useOrganizationBookings" which will return an array of organization bookings. You can filter bookings by status, user ids, event type ids, attendee email etc. - [see this class](https://github.com/calcom/cal.com/blob/307b2946a2cb6dcdb32dbee6c4f448e8a01c4285/packages/platform/types/bookings/2024-08-13/inputs/get-bookings.input.ts#L32) for filters you can pass to the hook + you can use "userIds" filter like in example below.
Below code snippet shows how to use the "useOrganizationBookings" hook to fetch bookings for a specific users using take, skip and userIds filters:
```js
import { useOrganizationBookings } from "@calcom/atoms";
export default function Bookings() {
const { isLoading: isLoadingUpcomingBookings, data: upcomingBookings } = useOrganizationBookings({
take: 50,
skip: 0,
userIds: [10, 11],
});
return (
<>
);
})}
>
);
}
```
# Calendars hooks
Source: https://cal.com/docs/platform/calendars-hooks
Overview of all the hooks associated with calendars.
### 1. `useConnectedCalendars`
The useConnectedCalendars returns an object containing all connected calendars of a user, and the destination calendar. It is useful in managing multiple calendar integrations. Each connected calendar entry contains essential properties such as the credentialId, externalId and integration which should be an object, which can be used in the hooks to add and remove selected calendars.
Below code snippet shows how to use the useConnectedCalendars hook to fetch calendars for a user.
```js
import { useConnectedCalendars } from "@calcom/atoms";
export default function ConnectedCalendars() {
const { isLoading: isLoadingConnectedCalendars, data: userCalendars } = useConnectedCalendars({});
return (
<>
{isLoadingConnectedCalendars &&
);
})}
>
);
}
```
### 2. `useAddSelectedCalendar`
The useAddSelectedCalendar lets you add a calendar to check for conflicts to prevent double bookings. This hook returns a mutation function that handles the addition process. The mutation function accepts an object with the following properties: ***credentialId*** which is the credential id of the calendar to add, ***integration*** which is the name of the integration, and ***externalId*** which is the external id of the calendar. In order to obtain those credentials, you can use the ***useConnectedCalendars*** hook.
Below code snippet shows how to use the useAddSelectedCalendar hook to add a specific calendar to check for conflicts.
```js
import { useAddSelectedCalendar } from "@calcom/atoms";
export default function AddSelectedCalendar() {
const { mutate: addSelectedCalendar } = useAddSelectedCalendar({
onSuccess: () => {
console.log("Selected calendar added successfully!");
},
onError: () => {
console.log("Error adding selected calendar");
},
});
return (
<>
>
);
}
```
### 3. `useRemoveSelectedCalendar`
The useRemoveSelectedCalendar lets you remove a calendar to check for conflicts to prevent double bookings. This hook returns a mutation function that handles the addition process. The mutation function accepts an object with the following properties: ***credentialId*** which is the credential id of the calendar to add, ***integration*** which is the name of the integration, and ***externalId*** which is the external id of the calendar. In order to obtain those credentials, you can use the ***useConnectedCalendars*** hook.
Below code snippet shows how to use the useRemoveSelectedCalendar hook to remove a specific calendar to check for conflicts.
```js
import { useRemoveSelectedCalendar } from "@calcom/atoms";
export default function RemoveSelectedCalendar() {
const { mutate: removeSelectedCalendar } = useRemoveSelectedCalendar({
onSuccess: () => {
console.log("Selected calendar removed successfully!");
},
onError: () => {
console.log("Error removing selected calendar");
},
});
return (
<>
>
);
}
```
### 4. `useDeleteCalendarCredentials`
The useDeleteCalendarCredentials hook allows you to delete a users calendar credentials. This hook returns a mutation function which handles the deletion process. The mutation function accepts an object with the following properties: ***id*** which is the credential id, and ***calendar*** is the name of the calendar which can be either google, office365 or apple.
Below code snippet shows how to use the useDeleteCalendarCredentials hook to manage deletion of calendar credentials.
```js
import { useDeleteCalendarCredentials } from "@calcom/atoms";
export default function DeleteUserCalendar() {
const { mutate: deleteCalendarCredentials } = useDeleteCalendarCredentials({
onSuccess: () => {
console.log("Calendar credentials deleted successfully!");
},
onError: () => {
console.log("Error deleting calendar credentials");
},
});
return (
<>
>
);
}
```
# Event types hooks
Source: https://cal.com/docs/platform/event-types-hooks
Overview of all the hooks associated with event types.
In order to create a team event type, you need to have an Essentials plan or above. Additionally, you also need to be a team admin or owner.
### 1. `useEventTypes`
The useEventTypes returns all event types associated with a user. Simply provide a username to fetch all their available event types. This hook is useful when you need to display or manage a user's entire collection of event configurations.
Below code snippet shows how to use the useEventTypes hook to fetch the event types of a specific user.
```js
import { useEventTypes } from "@calcom/atoms";
export default function EventTypes({ username }: { username: string }) {
const { isLoading: isLoadingEvents, data: eventTypes, refetch } = useEventTypes(username);
return (
<>
{isLoadingEvents &&
);
})}
>
);
}
```
### 2. `useTeamEventTypes`
The useTeamEventTypes returns all event types associated with a team. Simply provide the team id to fetch all their available event types. This hook is useful when you need to display or manage a team's entire collection of event configurations.
Below code snippet shows how to use the useTeamEventTypes hook to fetch the event types of a team.
```js
import { useTeamEventTypes } from "@calcom/atoms";
export default function TeamEventTypes({ id }: { id: number }) {
const { isLoading: isLoadingTeamEvents, data: teamEventTypes, refetch: refetchTeamEvents } = useTeamEventTypes(id);
return (
<>
{isLoadingTeamEvents &&
);
})}
>
);
}
```
### 3. `useEventTypeById`
The useEventTypeById returns data for a specific event type, provided you pass in the correct event type id. This hook is useful when you need to display or manage a specific event type.
Below code snippet shows how to use the useEventTypeById hook to fetch a specific event type.
```js
import { useEventTypeById } from "@calcom/atoms";
export default function EventType({ id }: { id: number }) {
const { isLoading: isLoadingEventType, data: eventType } = useEventTypeById(id);
return (
<>
{isLoadingEventType &&
Loading...
}
{!isLoadingEventType && !eventType &&
No event type found
}
{!isLoadingEventType &&
!!eventType &&
return (
Title: {eventType.slug}
)
}
>
);
}
```
### 4. `useCreateEventType`
The useCreateEventType hook allows you to create a new event type. This hook returns a mutation function that handles the event type creation process. The mutation function accepts an object with the following properties: ***lengthInMinutes*** which is the length of the event in minutes, ***title*** which is the title of the event, ***slug*** which is the slug of the event, and ***description*** which is the description of the event.
Below code snippet shows how to use the useCreateEventType hook to set up an event type.
```js
import { useCreateEventType } from "@calcom/atoms";
export default function CreateEventType() {
const { mutate: createEventType, isPending } = useCreateEventType({
onSuccess: () => {
console.log("Event type created successfully!");
},
onError: () => {
console.log("Error creating event type");
},
});
return (
<>
>
);
}
```
### 5. `useCreateTeamEventType`
The useCreateTeamEventType hook allows you to create a new team event type. This hook returns a mutation function that handles the event type creation process. The mutation function accepts an object with the following properties: ***lengthInMinutes*** which is the length of the event in minutes, ***title*** which is the title of the event, ***slug*** which is the slug of the event, ***description*** which is the description of the event, schedulingType which can be either ***COLLECTIVE***, ***ROUND\_ROBIN*** or ***MANAGED***, ***hosts*** which is an array of hosts for the event and the ***teamId*** which is the id of the team.
Below code snippet shows how to use the useCreateTeamEventType hook to set up a team event type.
```js
import { useCreateTeamEventType } from "@calcom/atoms";
export default function CreateTeamEventType() {
const { mutate: createTeamEventType, isPending } = useCreateTeamEventType({
onSuccess: () => {
console.log("Event type created successfully!");
},
onError: () => {
console.log("Error creating event type");
},
});
return (
<>
>
);
}
```
# FAQ
Source: https://cal.com/docs/platform/faq
Answers to the most common questions about the Platform API and atoms.
### 1. What is an OAuth client?
* A platform OAuth client enables you communicate with our API and manage your users.
* It contains properties such as name, redirect uris and permissions required by your users.
### 2. What is a managed user?
* A managed user is just a representation of your user within our database containing basic information like e-mail.
* It can be used to manage the setup of integrations such as Google Calendar, your users bookings. availability, etc.
* You should store information about the managed users in your database and use the access token to make API calls on their behalf.
### 3. Are a cal.com user and a managed user related?
* No, a cal.com user and a managed user are not related in any way. We can consider them as two separate entities.
* A "managed user" is completely independent of user accounts on cal.com and you don't need to register users on the cal.com web application.
### 4. What is an access token?
* At the time of creating a managed user you'll be provided with an access token and a refresh token.
* Each managed user is linked with an access token which helps us in identifying which users scheduling we need to handle.
* The access token only lasts for 60 minutes after which you can query the refresh point with your refresh token which will give you a new access token.
* Inside of atoms we handle access token refreshing part ourselves, outside of that you may need to handle the refreshing part yourselves.
* Refresh tokens should never be exposed to the frontend, keep them secure and only use them on the backend.
### 5. What is an atom?
* An atom is a customizable UI component that handles scheduling on behalf of your user.
* Everything from the front-end to the API calls is being handled by the atom, all you need to do is import the atom and drop it in your code.
### 6. What are the minimum setup requirements for using atoms?
* You need to have a project that uses React version 18 and above.
* At the moment atoms are only supported in React, so there's no way to use them in vanilla js or any other popular framework.
### 7. Can recurring events be rescheduled?
* No, at the moment you are only allowed to cancel a recurring event.
### 8. Why toggle animation is not working in the AvailabilitySettings atom?
* For the AvailabilitySettings toggle animation to work set the reading direction on the `` element:
```html
...
```
### 9. What are the authentication methods for making calls to the v2 API?
Either of the two:
* Setting `Authorization: Bearer ` header where `` is access token of the managed user.
* Setting `x-cal-client-id: ` and `x-cal-secret-key: ` where `` is OAuth client id and `` is OAuth client secret. Both can be copied from the dashboard.
### 10. When am I charged and not charged ?
* You are charged for scheduled booking only when the booking starts.
* If a booking is rescheduled you are still charged once.
* If a booking is cancelled then you are not charged for it.
### 11. What happens if there are more bookings than in my plan?
* You have to pay overage for each booking that exceeds the amount in your plan.
# Managing booking fields
Source: https://cal.com/docs/platform/guides/booking-fields
Prefilling and / or making them read-only.
## Prefilling default booking fields
If you want to pre-fill name and email fields you can pass them to the Booker atom's defaultFormValues prop:
```js
```
which will look like:
## Prefilling custom booking fields
We created an event type for managed user with custom text and select fields. Name and email fields are created by default. Here is the request:
That looks in booker like:
Let's say you want that when someone is trying to book one of your managed users that the
booking fields should be pre-filled with some data. We see that one of the booking fields has slug `coding-language` and the other
`help-with`. To pre-fill them you pass their slugs and values to the Booker atom's defaultFormValues prop:
```js
```
which now will populate the booking fields:
## Making pre-filled fields read-only
`disableOnPrefill` booking field property controls whether or not to make a booking field read only if we pass its value in the defaultFormValues prop. Here is an example request
where we create an event type with one booking field with "disableOnPrefill": true and the other with "disableOnPrefill": false:
If we pass their values to the Booker atom:
```js
```
then here is how it will look like in the Booker. The "What language will we peer code in" text field is read only:
# Booking redirects
Source: https://cal.com/docs/platform/guides/booking-redirects
Find out how to manage the booking flow.
When creating an OAuth client you can specify:
1. booking URL to manage where people land after booking after one of your users.
2. reschedule URL to your page for rescheduling a booking.
3. cancel URL to your page for cancelling a booking.
This guide will explain each of the URLs and how to create page for each of them using atoms and our hooks.
## Booking URL
After a person books one of your users, that person should see the successful booking.
Page in the booking URL will take URL parameter provided by us and then hook to fetch the booking and then display it. Here is an example:
1. Pass `my-app.com/bookings` as the redirectURI.
2. In your app, create `my-app.com/bookings/[bookingUid]` page where bookingUid will become path parameter.
3. When a booking occurs, booker will be re-directed to the redirectURI with booking UID as the bookingUid parameter aka my-app.com/bookings/\[bookingUid].
4. In the my-app.com/bookings/\[bookingUid] route create a page that imports `useBooking` hook, then extract bookingUid from URL parameter, and uses the hook to display booking information. Because
`useBooking` hook can return individual booking or an array of recurring bookings, you need to handle single booking and array of bookings cases separately:
```js
import { useBooking } from "@calcom/atoms";
export default function Bookings(props: { calUsername: string; calEmail: string }) {
const router = useRouter();
const { isLoading, data: booking, refetch } = useBooking((router.query.bookingUid as string) ?? "");
return (
<>
{!Array.isArray(booking) ? (
{booking.title}
) : (
booking.map((recurrence) =>
{recurrence.title}
)
)}
>
)
};
```
An example implementation can be found [here](https://github.com/calcom/cal.com/blob/main/packages/platform/examples/base/src/pages/%5BbookingUid%5D.tsx).
## Reschedule URL
1. Pass `my-app.com/bookings/reschedule` as the redirectURI.
2. When “Reschedule” is clicked, user will be re-directed to the redirectURI with rescheduled and eventTypeSlug query parameters `my-app.com/reschedule?rescheduleUid=buiaE8jHmNAxLrqitahCeL&eventTypeSlug=thirty-minutes`
3. In the my-app.com/reschedule route create a page that extracts `rescheduleUid` and `eventTypeSlug` from the query parameters and passes the to the `Booker` atom:
```js
const rescheduleUid = (router.query.rescheduleUid as string) ?? "";
const eventTypeSlugQueryParam = (router.query.eventTypeSlug as string) ?? "";
```
You only need rescheduleUid, eventSlug and username.
An example implementation can be found [here](https://github.com/calcom/cal.com/blob/main/packages/platform/examples/base/src/pages/booking.tsx).
## Cancel URL
1. Pass `my-app.com/bookings/cancel` as the cancelURI.
2. In your app, create `my-app.com/bookings/cancel/[bookingUid]` page where bookingUid will become path parameter.
3. In the page of my-app.com/cancel/\[bookingUid] import useCancelBooking from atoms and get access to the cancel mutation
import { useCancelBooking } from "@calcom/atoms";
```js
const { mutate: cancelBooking } = useCancelBooking({
onSuccess: () => {
refetch();
},
});
```
4. Create a cancel button that invokes mutation returned by the “useCancelBooking”. You have to pass id of the booking which you can get by fetching booking using "useBooking" hook by uid from the query params. Provide a suitable “cancellationReason”.
Because `useBooking` hook can return individual booking or an array of recurring bookings, you need to handle single booking and array of bookings cases separately:
```js
import { useBooking, useCancelBooking } from "@calcom/atoms";
...
const { isLoading, data: booking, refetch } = useBooking((router.query.bookingUid as string) ?? "");
const { mutate: cancelBooking } = useCancelBooking({
onSuccess: () => {
refetch();
},
});
...
return !Array.isArray(booking) ? (
) : (
<>
{booking.map((recurrence) => (
))}
>
);
```
An example implementation can be found [here](https://github.com/calcom/cal.com/blob/main/packages/platform/examples/base/src/pages/booking.tsx).
# Custom booking flow
Source: https://cal.com/docs/platform/guides/custom-booking-flow
Learn how to intercept a booking to introduce your custom flow and then submit the booking.
If you want to have a custom payment flow or any other custom action before the booking happens, you can intercept the booking
once the user clicks book in the [Booker atom](https://cal.com/docs/platform/atoms/booker), run whatever custom code you need and then finally
submit the booking with the intercepted booking data.
In your component that renders the Booker atom create a `interceptBooking` function that will be passed to the Booker atom `handleCreateBooking` hook. See [Booker atom](https://cal.com/docs/platform/atoms/booker) docs on how to use it - in this tutorial
we focus on the `handleCreateBooking` hook.
```
import { Booker, UseCreateBookingInput } from "@calcom/atoms";
export function BookingPage(props: { calUsername: string; calEmail: string }) {
...
const interceptBooking = useCallback((data: UseCreateBookingInput) => {
console.log(data);
}, []);
return (
);
}
```
1. When user clicks "Book" in the Booker atom the booking will not happen. Instead, the `interceptBooking` function will be called and will receive all the booking data.
2. Then, you can hide the Booker component and instead render another component, show a modal, redirect to a new page or whatever you want to do.
3. After your custom action is finished, extract the necessary information from the booking data passed to `interceptBooking` and make a POST request to
[create booking](https://cal.com/docs/api-reference/v2/bookings/create-a-booking) endpoint to actually create the booking.
# Global event types
Source: https://cal.com/docs/platform/guides/global-event-types
Event types that every managed user or a subset of managed users will have automatically
If you want all of your managed users or a subset of managed users to have the same event type set up automatically, then follow along.
## Prerequisites
1. You need to have an OAuth client set up, since we'll need the client id and client secret from the OAuth client to be included in the API requests. Here is the link for the [OAuth client setup guide](https://cal.com/docs/platform/quickstart)
2. You need to have an ESSENTIALS plan or higher
## Steps
Overview:
1. Create a team.
2. Create managed team event type with `assignAllTeamMembers: true` - it is an event type that you can define once and that will be used as a template to create event types for managed users. We call it the parent
managed event type and the event types created for managed users based on it are called children managed event types.
3. Create managed users.
4. For each managed user you want to have this event type, create a membership within the team.
Then the managed user will have the event type created. Once you have steps 1 and 2 set up, you simply need to add the managed user to the team
and the user will have the event type created. If you then update the parent managed event type then it will automatically update all of the children managed event types.
Create a team by sending a POST request to the [create a team](https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team) endpoint. Example request body:
```
{
"name": "coffee fans",
"slug": "coffee-fans"
}
```
You will need to note down the "id" of the created team from the response:
```
{
"status": "success",
"data": {
...
"id": 1041,
...
}
}
```
Now we will create the managed team event type. Make a POST request to the [create an organization team event type](https://cal.com/docs/api-reference/v2/orgs-teams-event-types/create-an-event-type) endpoint. Example request body:
```
{
"lengthInMinutes": 60,
"title": "coffee tasting",
"slug": "coffee-tasting",
"schedulingType": "managed",
"assignAllTeamMembers": true
}
```
Note that `"schedulingType"` has to be set to `"managed"` and `"assignAllTeamMembers"` has to be set to `true`. `"assignAllTeamMembers"` being `true` means that once a managed user has membership in the team this event type will be automatically created for the managed user.
You will need to note down the "id" of the created event type from the response:
```
{
"status": "success",
"data": [
{
"id": 3672,
"lengthInMinutes": 60,
"title": "coffee tasting",
"slug": "coffee-tasting",
"schedulingType": "managed",
"assignAllTeamMembers": true,
...
}
]
}
```
The team created in the previous step has no members, so we need to create managed users and later their membership in the team. To create a managed user here is the [create managed user](https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user) endpoint. Example request body:
```
{
"email": "charlie@gmail.com",
"name": "charlie",
"timeZone": "Europe/Rome"
}
```
After creating managed user you have to save its "id", "accessToken" and "refreshToken" in your database and note down the "id" for the next step. Here is response:
```
{
"status": "success",
"data": {
"user": {
"id": 1458,
"email": "charlie+clxyyy21o0003sbk7yw5z6tzg@gmail.com",
"username": "charlie-clxyyy21o0003sbk7yw5z6tzg-gmail-com",
"name": "charlie",
...
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWNjZXNzX3Rva2VuIiwiY2xpZW50SWQiOiJjbHh5eXkyMW8wMDAzc2JrN3l3NXo2dHpnIiwib3duZXJJZCI6MTQ1OCwiZXhwaXJlc0F0IjoxNzQ1NDkwODQwMDAwLCJpYXQiOjE3NDU0ODcyNTh9.FI9-Hi7O_j4QLn7SuNJlOnmk-0MHhZoXPCncsmgyCoQ",
"accessTokenExpiresAt": 1745490840000,
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoicmVmcmVzaF90b2tlbiIsImNsaWVudElkIjoiY2x4eXl5MjFvMDAwM3Niazd5dzV6NnR6ZyIsIm93bmVySWQiOjE0NTgsImV4cGlyZXNBdCI6MTc3Njk4MTYwMDAwMCwiaWF0IjoxNzQ1NDg3MjU4fQ.YYTH7WeshMR-BpbNeSYFUubjTlsAsOhdhrge-LngRiw",
"refreshTokenExpiresAt": 1776981600000
}
}
```
Now we will create a membership for this user within the team by making a POST request to the [create membership](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership) endpoint. Example body:
```
{
"userId": 1458,
"accepted": true,
"role": "MEMBER"
}
```
Note that `"accepted"` has to be `"true"` and `"userId"` has to be the id of the managed user created in the previous step.
Now, if we fetch managed user event types using the [get event types](https://cal.com/docs/api-reference/v2/event-types/get-all-event-types) endpoint and given our example
query params `eventSlug` and `username` (`?eventSlug=coffee-tasting&username=charlie-clxyyy21o0003sbk7yw5z6tzg-gmail-com`), the response will contain the "global" event type:
```
{
"status": "success",
"data": [
{
"id": 3673,
"ownerId": 1458,
"lengthInMinutes": 60,
"title": "coffee tasting",
"slug": "coffee-tasting"
...
}
]
}
```
Note, that when we create the "parent" managed event type in step 2 it has an id `3672` but the child managed event type belonging to managed user has `3673`, so they are separate entities
and the "child" managed event type is the same as having individually created event type just for that managed user.
Now, if we update the "parent" managed team event type via [update an organization team event type](https://cal.com/docs/api-reference/v2/orgs-teams-event-types/update-a-team-event-type) endpoint, and fetch
again managed user event type using the [get event types](https://cal.com/docs/api-reference/v2/event-types/get-all-event-types) endpoint with same query parameters `eventSlug` and `username` as above,
the child managed event type will also be updated automatically.
Now with this setup you can:
1. Each time you create a new managed user simply create membership within the team and have the event type created automatically.
2. If you want that already existing managed users have the event type created, you have to create team and then membership within the team just like we saw above.
3. You can create a team called "global" where you add all managed users so all managed users have the same event type or a subset of managed users have the same event type belonging to "subset-team"
if you want to have a subset of managed users have the same event type.
# Custom toasts
Source: https://cal.com/docs/platform/guides/replacing-toasts
Replace default cal.com toasts with your own
It is possible to disable default toasts for the `AvailabilitySettings` and `EventTypeSettings` atoms to then use hooks => callbacks
and listen for updates to then render your own toasts.
If we use the `AvailabilitySettings` atom, make changes and press "Save" a confirmation appears:
We can disable them using `disableToasts` prop:
```js
```
Now when changes happen and Save is clicked the toast will not appear.
You can then create functions and pass them to hooks:
```js
```
in case of success response is passed to your functions and in case of error and error.
# Configuring your team
Source: https://cal.com/docs/platform/guides/teams-setup
Learn how to set up teams via the API v2
This page guides you through the steps to set up teams via the API v2. An organization is just a team that can have children teams.
## Prerequisites
1. You need to have an OAuth client set up, since we'll need the client id and client secret from the OAuth client to be included in the API requests. Here is the link for the [OAuth client setup guide](https://cal.com/docs/platform/quickstart)
2. You need to have an ESSENTIALS plan or above
3. In order to create a team and access team info you need to be an organization admin/owner
4. In order to create and access a team event type you need to be a team admin/owner
5. For all requests made to the below teams endpoint, you need to provide `x-cal-client-id` and `x-cal-secret-key` headers.
## Steps
Create a team by sending a POST request to the [create a team](https://cal.com/docs/api-reference/v2/orgs-teams/create-a-team) endpoint. The request body would looks something like this:
```
{
"name": "Platform team",
"slug": "platform-team",
"bio": "This is the platform team!"
}
```
The API response returned will look like below.
```
{
"status": "success",
"data": {
"hideBookATeamMember": false,
"timeZone": "Europe/London",
"weekStart": "Sunday",
"id": 35137,
"parentId": 12575,
"name": "Platform team",
"slug": "platform-team",
"logoUrl": null,
"calVideoLogo": null,
"appLogo": null,
"appIconLogo": null,
"bio": "This is the platform team!",
"hideBranding": false,
"isOrganization": false,
"isPrivate": false,
"metadata": null,
"theme": null,
"brandColor": null,
"darkBrandColor": null,
"bannerUrl": null,
"timeFormat": null
}
}
```
We recommend storing the team id being returned back in the API response. This will be used in the next steps.
The team created in the previous step has no members, hence we need to add managed users (members) to the team . To create a managed user here is the [managed user](https://cal.com/docs/api-reference/v2/platform-managed-users/create-a-managed-user) endpoint . After we're done creating a managed user, we need to create membership for the team which can be done by sending a POST request to the [add a member](https://cal.com/docs/api-reference/v2/orgs-teams-memberships/create-a-membership) endpoint. The API response returned will look like below.
```
{
"status": "success",
"data": {
"id": 504378,
"userId": 1278670,
"teamId": 36147,
"accepted": true,
"role": "ADMIN",
"disableImpersonation": false,
"user": {
"avatarUrl": "https://i.cal.com/api/avatar/b0b58752-68ad-4c0d-8024-4fa382a77752.png",
"username": "rick-astley-clvmujib40001p21mxdpkhvu0-gmail",
"name": "Cal",
"email": "rick+clvmujib40001p21mxdpkhvu0@gmail.com"
}
}
}
```
Now that we have a team set up and it has members, we can create an event type for the team. To create an event type here is the [create an event type](https://cal.com/docs/api-reference/v2/orgs-event-types/create-an-event-type) endpoint. The request body would looks something like this:
```
{
"lengthInMinutes": 60,
"title": "Daily standup",
"slug": "platform-daily-standup",
"description": "Daily standup of the platform team!",
"schedulingType": "COLLECTIVE",
"hosts": [{"userId": 1399}]
}
```
The API response returned will look like below.
```
{
"status": "success",
"data": {
"id": 1954202,
"lengthInMinutes": 60,
"title": "Daily standup",
"slug": "daily-standup-for-platform",
"description": "This is a team event type for platform teams daily standup",
"locations": [
{
"type": "integration",
"integration": "cal-video"
}
],
"bookingFields": [
{
"isDefault": true,
"type": "name",
"slug": "name",
"required": true,
"disableOnPrefill": false
},
{
"isDefault": true,
"type": "email",
"slug": "email",
"required": true,
"disableOnPrefill": false
},
{
"isDefault": true,
"type": "radioInput",
"slug": "location",
"required": false,
"hidden": false
},
{
"isDefault": true,
"type": "text",
"slug": "title",
"required": true,
"disableOnPrefill": false,
"hidden": true
},
{
"isDefault": true,
"type": "textarea",
"slug": "notes",
"required": false,
"disableOnPrefill": false,
"hidden": false
},
{
"isDefault": true,
"type": "multiemail",
"slug": "guests",
"required": false,
"disableOnPrefill": false,
"hidden": false
},
{
"isDefault": true,
"type": "textarea",
"slug": "rescheduleReason",
"required": false,
"disableOnPrefill": false,
"hidden": false
}
],
"recurrence": null,
"disableGuests": false,
"slotInterval": null,
"minimumBookingNotice": 120,
"beforeEventBuffer": 0,
"afterEventBuffer": 0,
"metadata": {},
"price": 0,
"currency": "usd",
"lockTimeZoneToggleOnBookingPage": false,
"forwardParamsSuccessRedirect": true,
"successRedirectUrl": null,
"isInstantEvent": false,
"scheduleId": null,
"onlyShowFirstAvailableSlot": false,
"offsetStart": 0,
"bookingWindow": {
"disabled": true
},
"confirmationPolicy": {
"disabled": true
},
"requiresBookerEmailVerification": false,
"hideCalendarNotes": false,
"seats": {
"disabled": true
},
"useDestinationCalendarEmail": false,
"hideCalendarEventDetails": false,
"hosts": [
{
"userId": 12860,
"name": "Rick Astley",
"avatarUrl": "https://i.cal.com/api/avatar/b0b58752-68ad-4c0d-8024-4fa382a77752.png"
}
],
"teamId": 36447,
"ownerId": null,
"parentEventTypeId": null,
"schedulingType": "COLLECTIVE",
"assignAllTeamMembers": false,
"team": {
"id": 361247
}
}
}
```
We recommend storing the slug and team id being returned back in the API response. This will be used in the next steps.
Now that we have all the backend setup for teams, it's time to set up the frontend. If we want to enable a team event type in the booker atom, we need to pass the prop `isTeamEvent` as true and also another additional prop `teamId`. The `teamId` is the id of the team that we created in the previous step. Here is the code snippet for the booker atom.
```
{
console.log("booking created successfully", booking);
}}
/>
```
Another way to get teams and team event type data is via our custom hooks. Here is an example of how to use the `useTeams` and `useTeamEventTypes` hooks.
```
import { useTeams, useTeamEventTypes } from "@calcom/atoms";
export default function TeamEvent(){
const { isLoading: isLoadingTeams, data: teams } = useTeams();
const { isLoading: isLoadingTeamEventTypes, data: teamEventTypes } = useTeamEventTypes(teams?.[0]?.id || 0);
return (
<>
Teams event
)
}
```
# Introduction
Source: https://cal.com/docs/platform/introduction
Get started
Customizable UI components handling scheduling on behalf of your users
Learn how to create specific things
Learn how to use Cal.com's API to CRUD various Cal resources programmatically
## Welcome to the Platform Documentation!
Platform is the best choice for starting a scheduling business. You can white-label the design or change every line of code to make it work for you. It consists of our newly created set of APIs and plug and play UI components called atoms.
# Quickstart
Source: https://cal.com/docs/platform/quickstart
Find out how to use Cal "atoms" to integrate scheduling into your product.
## 1. Unlocking access to atoms
1. Sign up for a Platform account [here](https://app.cal.com/signup?redirect=https://app.cal.com/settings/platform/new)
## 2. Setting up an OAuth client
Once your account is created, the next step is to create an OAuth client. This allows you to connect your users to Cal and handle their scheduling with atoms.
1. After logging in using provided credentials, open OAuth clients settings page [https://app.cal.com/settings/platform/oauth-clients/create](https://app.cal.com/settings/platform/oauth-clients/create)
2. Add an OAuth client.
1. Name: anything is fine. You can use your company name or your website.
2. Redirect URIs: Used to validate origin of requests - your website's URLs from which atoms are allowed to make requests to our API. Supports wildcard syntax where "\*" would support any origin, and "*app.com" would support "example.app.com", and "https//example.com*" where it would support any origin from that domain.
3. Booking, reschedule and cancel URLs: URLs of pages where users land after a successful booking or if they want to reschedule or cancel a booking. We will pass information in the URL when redirecting to your pages and you will use our hooks and components to implement the pages. See [this guide](/platform/guides/booking-redirects).
4. Permissions - most likely you need all enabled:
1. Event type: event type is a user event that others can book. For example, Alice is a language teacher and she has an event type “30 minutes Italian lesson” that others can then book.
2. Booking: When Bob books the Italian lesson, a booking is created and shows up on the calendar that Alice connected using atoms.
3. Schedule: used to represent when a user is available. From what to what time and when can an event type be booked. For example, Alice only can be booked for the Italian lessons on Mondays and Tuesdays from 9AM to 4PM.
4. Profile: When you proceed to the chapter 2, you will create your users on our end, so that we can manage their scheduling. Profile permissions allow to either read or update users you create on our end.
5. Apps: used to connect Google Calendar, Zoom, Microsoft Teams, etc. to atoms.
## 3. Creating managed users connected to the OAuth client
In order for atoms to handle scheduling on behalf of your users, you have to create what we call a “managed user” for each of your users.
#### What is a “Managed user”?
It is a representation of your user within our database containing basic information like email and is used to manage the setup of Google Calendar.
After creating a “managed user” you will receive the user ID, an access and a refresh token that are used by atoms to handle scheduling and can be used to modify the “managed user” information, so make sure to store the tokens and the [cal.com](https://cal.com) user ID in your database. Also, you will have to connect each user on your end with the access and refresh tokens by adding new properties on your User model in database that store the tokens, for example.
#### What is it not?
It's important to clarify that a "managed user" is completely independent of a regular user account on cal.com, meaning you don't need your users to register on cal.com web application.
❗Managed users do not get a public cal.com page like normal cal.com users do aka if you create a managed user the managed user won't have cal.com/managed-user page, because the point of platform solution is to integrate scheduling into your platform,
so instead the managed user public page will be at your-platform.com/managed-user and there you fetch event types of the managed user using our api or react hooks and display them.
### Create managed users via our API
We now need the OAuth client’s “client ID” and “client secret” that you can find in [https://app.cal.com/settings/organizations/platform/oauth-clients](https://app.cal.com/settings/organizations/platform/oauth-clients).
You have to make a POST request to [https://api.cal.com/v2/oauth-clients/YOUR\_CLIENT\_ID/users](https://api.cal.com/v2/oauth-clients/:clientId/users):
1. Replace “YOUR\_CLIENT\_ID” in the URL with your “client ID”.
2. Add "x-cal-secret-key” header with the value of your “client secret”.
3. Add the request body containing an object to create the “managed user” with the following properties:
1. email: required, your user's email.
2. name: optional, full name of your user.
3. timeFormat: optional, value can be either 12 or 24 with 12 representing 12 hour time using AM and PM and 24 representing 24 hour time without AM and PM.
4. weekStart: optional, value can be “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”, “Sunday”. If none passed, "Sunday” is used as the default. Countries in North and South America start their week on Sunday while countries in Europe and Oceania on Monday.
5. timeZone: optional, in the format of “IANA timezone” e.g. “Europe/Rome”. If none passed, "Europe/London” is used as the default.
#### Example request
URL: [https://api.cal.com/v2/oauth-clients/7Dcxu2fclb10001kha9x1dreyl4/users](https://api.cal.com/v2/oauth-clients/7Dcxu2fclb10001kha9x1dreyl4/users)
Headers: `{ "x-cal-secret-key”: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX}`
Body:
```js
{
"email": "bob@example.com",
"timeZone": "America/New_York"
}
```
#### Example response
```js
{
"status": "success",
"data": {
"user": {
"id": 179,
"email": "bob@example.com",
"username": "bob"
},
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWNjZXNzX3Rva2VuIiwiY2xpZW50SWQiOiJjbHUxZmNtYjEwMDAxa2hyN3g3ZHJleWw0Iiwib3duZXJJZCI6MTc5LCJpYXQiOjE3MTE0NDI3OTR9.EsC3JRPHQnigcp_HSijKCIp8EgcWs2kj4AFxYXYc9sM",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoicmVmcmVzaF90b2tlbiIsImNsaWVudElkIjoiY2x1MWZjbWIxMDAwMWtocjd4N2RyZXlsNCIsIm93bmVySWQiOjE3OSwiaWF0IjoxNzExNDQyNzk0fQ.GjklEucgey8yWMoGz7ABntbxYdiqqQFPooQjqGd3B5I"
}
}
```
First, make sure to store the user ID, access and refresh tokens in your database and connect them to each user. For example, you can add “calAtomsAccessToken” and “calAtomsRefreshToken” properties to your user database model.
You will be able to provide an access token to our atoms so that they can handle scheduling on behalf of the user associated with the token. Access tokens expires, so you will have to refresh them using the refresh token.
Second, if `timeZone` is passed in the request, the user's default schedule from 9AM to 5PM will be created in the specified timezone. Then, using the `AvailabilitySettings` atom, user can customize their availability. However,
if the `timeZone` is not passed, then user has no default schedule and user can't be booked and user can't set availability using the `AvailabilitySettings` atom. You will have to set it up manually via the `/schedules` endpoints.
We recommend setting the `timeZone` for ease of use.
## 4. Backend: setting up a refresh token endpoint
You have to set up an endpoint on your server to which atoms can send an expired access token and receive new one in return. This exchange will be automatically handled by atoms when you provide this endpoint URL when setting up frontend in the next step.
> Q: Why do we need a separate endpoint just for this?
> A: Your OAuth client secret and users refresh tokens should never be exposed on the frontend. The OAuth client secret will reside as an environment variable in your backend and the users' refresh tokens are stored in your database, which are used by our API to refresh the access token.
You can check an example refresh token endpoint in our atoms examples app: [https://github.com/calcom/atoms-examples/blob/main/cal-sync/src/pages/api/refresh.ts](https://github.com/calcom/atoms-examples/blob/main/cal-sync/src/pages/api/refresh.ts)
Shortly:
1. Set up environment variables or pass values directly. Here are ones from the examples app above:
1. NEXT\_PUBLIC\_CALCOM\_API\_URL: [https://api.cal.com/v2](https://api.cal.com/v2)
2. NEXT\_PUBLIC\_X\_CAL\_ID: your OAuth client ID
3. X\_CAL\_SECRET\_KEY - your OAuth client secret
2. Your endpoint will receive a request from atoms.
3. Make it a GET endpoint to which “Authorization: Bearer accessToken” header can be sent to.
4. Assuming you have stored the access and refresh tokens in your database and connected them to a specific user, fetch the user based on the received access token.
5. Provide the OAuth client ID, client secret and managed user refresh token to the [`/refresh`](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens) endpoint.
6. Store in your database access and refresh tokens returned by the [`/refresh`](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens) endpoint.
7. Return access token to the request. It should be in the format of:
```js
{ accessToken: "fresh access token" }
```
The atoms will now use the new access token to handle scheduling on behalf of your user. Access token expires after 60 minutes and atoms
then will make a request to your refresh token endpoint to get a new access token while also refreshing the refresh token.
## 5. Managing refresh token expiry
Each refresh token is valid for 1 year. When a managed user's access token is refreshed, the refresh token is refreshed too.
However, to make sure that refresh tokens do not expire for less active users you have 2 options:
1. If you decode the refresh token there is `expiresAt` date (it is a jwt token so you can decode it using some library from npm). You could have a cron job that checks all of your users refresh tokens and sees if the refresh token
is about to expire, then refresh tokens using the [`/refresh`](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens) endpoint.
2. In the refresh endpoint you built in the [previous step](https://cal.com/docs/platform/quickstart#4-backend%3A-setting-up-a-refresh-token-endpoint) you could have a check that if the call to [`/refresh`](https://cal.com/docs/api-reference/v2/platform-managed-users/refresh-managed-user-tokens) fails meaning that the
refresh token has expired, call the [`/force-refresh`](https://cal.com/docs/api-reference/v2/platform-managed-users/force-refresh-tokens) endpoint - it allows you to refresh managed user tokens
using only the OAuth client ID and client secret and is intended to be used in cases when one of the tokens is lost or the refresh token is expired.
## 6. Frontend: setting up atoms
Atoms are customizable UI components handling scheduling on behalf of your users.
### 6.1 Install the atoms package
npm:
```jsx
npm install @calcom/atoms
```
yarn:
```jsx
yarn add @calcom/atoms
```
pnpm:
```jsx
pnpm add @calcom/atoms
```
### 6.2 Set up environment variables
CAL\_OAUTH\_CLIENT\_ID: OAuth client ID
CAL\_API\_URL: [https://api.cal.com/v2](https://api.cal.com/v2)
REFRESH\_URL: URL of the endpoint you implemented in step 3, for example, your.api.com/api/refresh
### 5.3 Set up root of your app
Next.js: open \_app.js or or \_app.tsx.
React: open App.js or App.ts.
First, import global css styles used by atoms.
```js
import "@calcom/atoms/globals.min.css";
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
Second, import CalProvider that provides necessary information to atoms and wrap your components with it.
```js
import "@calcom/atoms/globals.min.css";
import { CalProvider } from '@calcom/atoms';
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;
```
Third, CalProvider needs to get access token of the user for which atoms will handle scheduling, so you need to fetch user and provide its access token to the CalProvider.
```js
import "@calcom/atoms/globals.min.css";
import { CalProvider } from '@calcom/atoms';
function MyApp({ Component, pageProps }) {
const [accessToken, setAccessToken] = useState("");
useEffect(() => {
fetch(`/api/users/${pageProps.userId}`, {
}).then(async (res) => {
const data = await res.json();
setAccessToken(data.accessToken);
});
}, []);
return (
);
}
export default MyApp;
```
## 7. Frontend: using atoms
It’s very easy, just import the atom and drop it in code! For example, for users to connect their Google Calendar drop in "Connect.GoogleCalendar" component - it will handle everything.
```js
import { Connect } from "@calcom/atoms";
...
export default function Connect() {
return (
);
}
```
If you need to customize the appearance of any atom, you can pass in custom css styles via a className prop that every atom has:
```js
```
other more complex atoms will expose multiple classNames and props to react to events happening in the atoms
```js
{
console.log("Updated successfully");
}}
onUpdateError={() => {
console.log("update error");
}}
onDeleteError={() => {
console.log("delete error");
}}
onDeleteSuccess={() => {
console.log("Deleted successfully");
}}
/>;
```
## 8. Front-end: passing additional props to CalProvider
The CalProvider component offers several additional props to customize its behavior and appearance:
1. autoUpdateTimezone: By default, the atoms automatically update the user's timezone. You can disable this feature by setting autoUpdateTimezone to false.
2. onTimezoneChange: If you want to perform specific actions whenever the user's timezone changes, you can provide a callback function to the onTimezoneChange prop.
3. children: You can pass in custom child components to be rendered within the CalProvider.
4. version: Specify the API version that the atoms should use by setting the version prop.
5. language: Set the language for the atoms by providing a supported locale (es, fr, de, en, pt-BR) to the language prop.
6. labels: Override specific labels in the atoms by passing an object of custom labels to the labels prop.
```js
import "@calcom/atoms/globals.min.css";
import { CalProvider } from '@calcom/atoms';
function MyApp({ Component, pageProps }) {
const [accessToken, setAccessToken] = useState("");
useEffect(() => {
fetch(`/api/users/${pageProps.userId}`, {
}).then(async (res) => {
const data = await res.json();
setAccessToken(data.accessToken);
});
}, []);
return (
{
console.log("Timezone changed successfully")
}}
children={<>This is the child component>}
>
);
}
export default MyApp;
```
# Setup
Source: https://cal.com/docs/platform/setup
Get started with creating a platform account
Head over to the [Cal.com](https://cal.com/) landing page and create a new account by clicking on the **Get Started** button at the top right corner.
This will redirect you to the Cal.com signup page which looks like this
After you sign up and create your account, go the [platform setup page](https://app.cal.com/settings/platform/new) where you are prompted to set up your platform team.
Once your platform team is created, you'll need to subscribe via stripe for the plan that you want to choose.
Once you subscribe via stripe, you will be redirected back to the platform setup page where you'll be able to see your platform dashboard. You're ready to start building with platform, head over to Quickstart for further steps.
# User / Teams hooks
Source: https://cal.com/docs/platform/user-or-team-related-hooks
Overview of all the hooks associated with managed users or teams.
### 1. `useMe`
The useMe returns the current managed user's info. This hook is useful when you need to display a managed user's details.
Below code snippet shows how to use the useMe hook to fetch user details.
```js
import { useMe } from "@calcom/atoms";
export default function UserDetails() {
const { data: userData, isLoading: isLoadingUser } = useMe();
return (
<>
{isLoadingUser &&
Loading...
}
{!isLoadingUser && !userData &&
No user found
}
{!isLoadingUser &&
!!userData &&
return (
Username: {userData.username}
)
}
>
);
}
```
### 2. `useTeams`
The useTeams returns all teams info. This hook is useful when you need to display or manage a user's entire collection of teams.
Below code snippet shows how to use the useTeams hook to fetch team details.
```js
import { useTeams } from "@calcom/atoms";
export default function UserTeams() {
const { data: teams, isLoading: isLoadingTeams } = useTeams();
return (
<>
{isLoadingTeams &&
);
})}
>
);
}
```
# Daily
Source: https://cal.com/docs/self-hosting/apps/install-apps/daily
#### Obtaining Daily API Credentials
Go to [Daily](https://www.daily.co/) and sign into your account.
From within your dashboard, go to the [developers](https://dashboard.daily.co/developers) tab.
Copy the API key provided in the developers tab.
Now paste the API key into the `DAILY_API_KEY` field in your `.env` file.
If you have the [Daily Scale Plan](https://www.daily.co/pricing), set the `DAILY_SCALE_PLAN` variable to `true` in the `.env` file to use features like video recording.
# Google
Source: https://cal.com/docs/self-hosting/apps/install-apps/google
#### Obtaining the Google API Credentials
Go to [Google API Console](https://console.cloud.google.com/apis/dashboard). If you don't have a project in your Google Cloud subscription, create one before proceeding. Under the Dashboard pane, select "Enable APIs and Services".
In the search box, type "calendar" and select the Google Calendar API search result.
Enable the selected API to proceed.
Go to the [OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent) from the side pane. Select the app type (Internal or External) and enter the basic app details on the first page.
On the Scopes page, select "Add or Remove Scopes". Search for Calendar.event and select the scopes with values `.../auth/calendar.events`, `.../auth/calendar.readonly`, and then click "Update".
On the Test Users page, add the Google account(s) you'll be using. Verify details on the last page to complete the consent screen configuration.
From the side pane, select [Credentials](https://console.cloud.google.com/apis/credentials) and then "Create Credentials". Choose "OAuth Client ID".
Choose "Web Application" as the Application Type.
Under Authorized redirect URI's, add the URIs:
```
/api/integrations/googlecalendar/callback
/api/auth/callback/google
```
Replace `` with the URL where your application runs.
The key will be created, redirecting you back to the Credentials page. Select the new client ID under "OAuth 2.0 Client IDs", then click "Download JSON". Copy the JSON file contents and paste the entire string into the `.env` and `.env.appStore` files under the `GOOGLE_API_CREDENTIALS` key.
In the `.env` file, set the following environment variable:
```
GOOGLE_LOGIN_ENABLED=false
```
This will configure the Google integration as an Internal app, restricting login access.
### **Adding Google Calendar to Cal.com App Store**
After adding Google credentials, you can now add the Google Calendar App to the app store. Repopulate the App store by running:
Run `pnpm db-seed` to update the app store and include the newly added Google Calendar integration.
# HubSpot
Source: https://cal.com/docs/self-hosting/apps/install-apps/hubspot
### Obtaining HubSpot Client ID and Secret
Go to [HubSpot Developer](https://developer.hubspot.com/) and sign into your account, or create a new one.
From the Developer account home page, go to "Manage apps".
Click the "Create app" button located at the top right corner of the page.
In the "App info" tab, fill in any information you want for your app.
Navigate to the "Auth" tab to set up authentication for the app.
Copy the Client ID and Client Secret and add them to your `.env` file under the fields:
```
HUBSPOT_CLIENT_ID
HUBSPOT_CLIENT_SECRET
```
Set the Redirect URL for OAuth to:
```
/api/integrations/hubspot/callback
```
Replace `` with the URL where your application is hosted.
In the "Scopes" section, select "Read" and "Write" for the scope called `crm.objects.contacts`.
Click the "Save" button at the bottom of the page.
You’re all set! Any booking in Cal.com will now be created as a meeting in HubSpot for your contacts.
# Introduction
Source: https://cal.com/docs/self-hosting/apps/install-apps/introduction
Install desired apps in your self-hosted instance for better integration.
Install Google for supporting Google Calendar and Google Meet integrations
Install Microsoft to support Exchange365 integration
Install Zoom to support Zoom video conferencing integration
Install Daily to support Cal Video integration
Install HubSpot to support HubSpot CRM integration
Install SendGrid to support SendGrid Email integration
Install Stripe to support Stripe integration for paid bookings
Install Twilio to support Workflows integration for sms reminders
Install Zoho to support Zoho CRM integration
# Microsoft
Source: https://cal.com/docs/self-hosting/apps/install-apps/microsoft
#### Obtaining Microsoft Graph Client ID and Secret
Go to [Azure App Registration](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) and select "New registration".
Provide a name for your application to proceed with the registration.
Set **Who can use this application or access this API?** to **Accounts in any organizational directory (Any Azure AD directory - Multitenant)**.
Set the **Web** redirect URI to:
```
/api/integrations/office365calendar/callback
```
Replace `` with the URL where your application runs.
Use the **Application (client) ID** as the value for **MS\_GRAPH\_CLIENT\_ID** in your `.env` file.
Click on **Certificates & secrets**, create a new client secret, and use the generated value as the **MS\_GRAPH\_CLIENT\_SECRET** in your `.env` file.
# Sendgrid
Source: https://cal.com/docs/self-hosting/apps/install-apps/sendgrid
Go to [https://signup.sendgrid.com/](https://signup.sendgrid.com/) and create a new SendGrid account.
Navigate to **Settings** -> **API Keys** and create a new API key.
Copy the generated API key and add it to your `.env` file under the field:
```
SENDGRID_API_KEY
```
Go to **Settings** -> **Sender Authentication** and verify a single sender.
Copy the verified email address and add it to your `.env` file under the field:
```
SENDGRID_EMAIL
```
This app is **required** for Workflows
# Stripe
Source: https://cal.com/docs/self-hosting/apps/install-apps/stripe
### Setting up Stripe
Go to Stripe and either create a new account or log into an existing one. For testing, activate the Test-Mode toggle in the top right of the Stripe dashboard.
Open [Stripe API Keys](https://dashboard.stripe.com/apikeys), then save the token starting with `pk_...` to `NEXT_PUBLIC_STRIPE_PUBLIC_KEY` and `sk_...` to `STRIPE_PRIVATE_KEY` in the `.env` file.
Go to [Stripe Connect Settings](https://dashboard.stripe.com/settings/connect) and activate OAuth for Standard Accounts.
Add the following redirect URL, replacing `` with your application's URL:
```
/api/integrations/stripepayment/callback
```
Copy your client ID (`ca_...`) to `STRIPE_CLIENT_ID` in the `.env` file.
Open [Stripe Webhooks](https://dashboard.stripe.com/webhooks) and add:
```
/api/integrations/stripepayment/webhook
```
as the webhook for connected applications.
Select all `payment_intent` events for the webhook.
Copy the webhook secret (`whsec_...`) to `STRIPE_WEBHOOK_SECRET` in the `.env` file.
# Twilio
Source: https://cal.com/docs/self-hosting/apps/install-apps/twilio
Go to [Twilio](https://www.twilio.com/try-twilio) and create a new account.
Click on 'Get a Twilio phone number' to obtain a phone number for your account.
Copy the Account SID and add it to your `.env` file under the field:
```
TWILIO_SID
```
Copy the Auth Token and add it to your `.env` file under the field:
```
TWILIO_TOKEN
```
Copy your Twilio phone number and add it to your `.env` file under the field:
```
TWILIO_PHONE_NUMBER
```
Add your own sender ID to the `.env` file under the field:
```
NEXT_PUBLIC_SENDER_ID
```
(The fallback is set to "Cal" if not specified.)
Navigate to **Develop** -> **Messaging** -> **Services**, then create a new messaging service.
Choose a name for the messaging service. This can be anything you like.
Click 'Add Senders' and select 'Phone number' as the sender type.
Add the listed phone number to the messaging service.
Leave all other fields as they are, then complete the setup by clicking ‘View my new Messaging Service’.
Copy the Messaging Service SID and add it to your `.env` file under the field:
```
TWILIO_MESSAGING_SID
```
Go to the Twilio dashboard, create a new Verify Service, and name it as you wish.
Copy the Verify Service SID and add it to your `.env` file under the field:
```
TWILIO_VERIFY_SID
```
This app is **required** for Workflows
# Zoho
Source: https://cal.com/docs/self-hosting/apps/install-apps/zoho
#### Obtaining ZohoCRM Client ID and Secret
Go to [Zoho API Console](https://api-console.zoho.com/) and sign into your account, or create a new one.
From the API console page, navigate to "Applications".
Click the "ADD CLIENT" button at the top right and select "Server-based Applications".
Enter any desired information in the "Client Details" tab.
Navigate to the "Client Secret" tab.
Copy the Client ID and Client Secret into your `.env` file under:
```
ZOHOCRM_CLIENT_ID
ZOHOCRM_CLIENT_SECRET
```
Set the Redirect URL for OAuth to:
```
/api/integrations/zohocrm/callback
```
Replace `` with your application URL.
In the "Settings" section, check the "Multi-DC" option if you wish to use the same OAuth credentials for all data centers.
Click "Save" or "UPDATE" at the bottom of the page.
Your ZohoCRM integration can now be easily added in the Cal.com settings.
#### Obtaining Zoho Calendar Client ID and Secret
Go to [Zoho API Console](https://api-console.zoho.com/) and sign into your account, or create a new one.
Choose "Server-based Applications" and set the Redirect URL for OAuth to:
```
/api/integrations/zohocalendar/callback
```
Replace `` with your application URL.
Enter any information you want in the "Client Details" tab.
Navigate to the "Client Secret" tab.
Copy the Client ID and Client Secret to your app keys in the Cal.com admin panel at:
```
/settings/admin/apps
```
In the "Settings" section of Zoho API Console, check the "Multi-DC" option if you wish to use the same OAuth credentials across data centers.
Click "Save" or "UPDATE" at the bottom of the page.
Your Zoho Calendar integration is now ready and can be managed at:
```
/settings/my-account/calendars
```
You can access your Zoho calendar at [https://calendar.zoho.com/](https://calendar.zoho.com/).
If you use multiple calendars with Cal, make sure to enable the toggle to prevent double-bookings across calendars. This setting can be found at `/settings/my-account/calendars`.
#### Obtaining Zoho Bigin Client ID and Secret
Go to [Zoho API Console](https://api-console.zoho.com/) and sign into your account, or create a new one.
Click the "ADD CLIENT" button at the top right, and select "Server-based Applications".
Set the Redirect URL for OAuth to:
```
/api/integrations/zoho-bigin/callback
```
Replace `` with your application URL.
Navigate to the "Client Secret" tab.
Copy the Client ID and Client Secret into the `.env.appStore` file under:
```
ZOHO_BIGIN_CLIENT_ID
ZOHO_BIGIN_CLIENT_SECRET
```
In the "Settings" section, check the "Multi-DC" option if you wish to use the same OAuth credentials across data centers.
Your Zoho Bigin integration is now ready and can be added from the Cal.com app store.
# Zoom
Source: https://cal.com/docs/self-hosting/apps/install-apps/zoom
**Obtaining Zoom Client ID and Secret**
Go to [Zoom Marketplace](https://marketplace.zoom.us/) and sign in with your Zoom account.
In the upper right, click "Develop" and then "Build App".
Under "OAuth", select "Create".
Provide a name for your app.
Select "User-managed app" as the app type.
De-select the option to publish the app on the Zoom App Marketplace.
Click "Create" to proceed.
Copy the Client ID and Client Secret and add them to your `.env` file under the fields:
```
ZOOM_CLIENT_ID
ZOOM_CLIENT_SECRET
```
Set the Redirect URL for OAuth to:
```
/api/integrations/zoomvideo/callback
```
Replace `` with your application URL.
Add the redirect URL to the allow list and enable "Subdomain check". Ensure it displays "saved" below the form.
You don't need to provide basic information about your app. Instead, go to "Scopes", click "+ Add Scopes", then select the category "Meeting" on the left, and check the scope `meeting:write`.
Click "Done" to save the scope settings.
Your Zoom integration is now ready and can be easily added in the Cal.com settings.
# Database migrations
Source: https://cal.com/docs/self-hosting/database-migrations
As described in the [upgrade guide](/self-hosting/upgrading), you should use the
```
yarn workspace @calcom/prisma db-migrate
```
or
```
yarn workspace @calcom/prisma db-deploy
```
command to update the database.
We use database migrations in order to handle changes to the database schema in a more secure and stable way. This is actually very common. The thing is that when just changing the schema in `schema.prisma` without creating migrations, the update to the newer database schema can damage or delete all data in production mode, since the system sometimes doesn't know how to transform the data from A to B. Using migrations, each step is reproducible, transparent and can be undone in a simple way.
### Creating migrations
If you are modifying the codebase and make a change to the `schema.prisma` file, you must create a migration.
To create a migration for your previously changed `schema.prisma`, simply run the following:
```
yarn workspace @calcom/prisma db-migrate
```
Now, you must create a short name for your migration to describe what changed (for example, "user\_add\_email\_verified"). Then just add and commit it with the corresponding code that uses your new database schema.
Always keep an eye on what migrations Prisma is generating.\*\* Prisma often happily will drop entire columns of data because it can't figure out what to do.
### Error: The database schema is not empty
Prisma uses a database called `_prisma_migrations` to keep track of which migrations have been applied and which haven't. If your local migrations database doesn't match up with what's in the actual database, then Prisma will throw the following error:
```
Error: P3005
The database schema for `localhost:5432` is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline
```
In order to fix this, we need to tell Prisma which migrations have already been applied.
This can be done by running the following command, replacing `migration_name` with each migration that you have already applied:
```
yarn prisma migrate resolve --applied migration_name
```
You will need to run the command for each migration that you want to mark as applied.
### Resetting Prisma migrate
When your local Prisma database runs out of sync with migrations on local and you are tearing your hair out, I’ve been there, so you don’t have to:
**PostgreSQL**
```
DELETE FROM "_prisma_migrations";
```
**Quickly re-index**
```
# Run the following to easily apply all migrations in the prisma/migrations directory
ls -1a prisma/migrations/ | grep 2021 | xargs -I{} prisma migrate resolve --applied {}
```
# AWS
Source: https://cal.com/docs/self-hosting/deployments/aws
Deploying Cal.com on AWS
***
## Manual Deployment
1. Amazon Web Services account
2. Familiarity with AWS services and management console
3. Access to the Cal.com source code
1. Create an AWS Account: If not already set up, create an account on AWS.
2. Management Console: Log in to the AWS Management Console.
1. Create a New IAM User: Set up an IAM user with the necessary permissions for deploying and managing the application.
2. Set Up Required Services: Establish services like Amazon EC2, RDS for PostgreSQL, etc., as needed for your application.
1. Clone the Repository: Get the Cal.com repository onto your local environment.
2. Update Configuration: Modify the .env file to include your AWS resource details (like database endpoints).
1. Deploy Application: Utilize AWS services such as EC2 or Elastic Beanstalk to deploy the Cal.com application.
2. Database Configuration: Set up and connect the RDS instance to your application.
3. Verify Deployment: Ensure the application is operational and accessible.
1. DNS Setup: Update your DNS settings to point to your AWS deployment.
2. Monitoring and Scaling: Leverage AWS monitoring tools to keep track of your application's performance and scale resources accordingly.
### Best Practices
1. Adhere to AWS's recommended security practices.
2. Regularly update your deployment with the latest Cal.com releases.
### Additional Resources
[https://docs.aws.amazon.com/](https://docs.aws.amazon.com/)
# Azure
Source: https://cal.com/docs/self-hosting/deployments/azure
Deploying Cal.com on Azure
***
## One Click Deployment
## Manual Deployment
1. Microsoft Azure account
2. Basic knowledge of Azure services
3. Access to Cal.com source code
1. Create an Azure Account
2. Azure Portal: Familiarize yourself with the Azure Portal.
1. Creating Azure Resources: In the Azure Portal, create a new resource group for your Cal.com project.
2. Create Azure Services: Set up required services such as Azure App Service, Azure Database for PostgreSQL, etc.
#### Create Web App
#### Setup Database, Networking
#### Setup Monitoring
1. Clone Repository: Clone the Cal.com repository to your local machine.
2. Configuration Files: Update the .env file with necessary Azure configurations (e.g., database connection strings).
1. Deploying Web App: Use Azure App Service to deploy the Cal.com web application.
2. Database Setup: Deploy and configure the Azure Database for PostgreSQL with Cal.com.
3. Deployment Verification: Ensure that the application is running smoothly post-deployment.
1. DNS Configuration: Configure your DNS settings to point to the Azure deployment.
2. Monitor and Scale: Utilize Azure monitoring tools to keep track of performance and scale resources as needed.
# Elestio
Source: https://cal.com/docs/self-hosting/deployments/elestio
You can deploy Cal.com on Elestio using the button below.
## One Click Deployment
# GCP
Source: https://cal.com/docs/self-hosting/deployments/gcp
Deploying Cal.com on Google Cloud Platform (GCP)
In this guide, we will go over the steps to deploy cal.com on Google Cloud Platform (GCP). We will cover how to create a virtual machine, configure it, install Docker, and finally deploy the cal.com application.
## One Click Deployment
## Manual Deployment
### Go to the GCP Console
First, open the Google Cloud Platform console by visiting the [https://console.cloud.google.com/](https://console.cloud.google.com/) website.
### Create a New Project
If you haven't already, create a new project by clicking on the "Select a project" dropdown menu and selecting "New Project". Enter a name for your project and click on the "Create" button.
### Create a New VM Instance
Click on the navigation menu icon (three horizontal lines) and select "Compute Engine" from the list. Then, click on "VM instances" in the sub-menu.
Click on the "Create" button to create a new virtual machine.
### Select the Machine Type
Choose the machine type that best suits your needs. Ideally, 2 vCPUs and 2-4GB RAM is enough.
### Set Up Networking
Make sure the "Networking" tab is selected and click on the "Add network" button. Choose the "Default" network and click on the "Add" button.
### Create the Instance
Review the details of your virtual machine and click on the "Create" button to create the instance.
Note the public IP of the VM.
Once your virtual machine is created, you need to configure it to allow traffic on port 80.
### Open Port 80
Click on the navigation menu icon (three horizontal lines) and select "Compute Engine" from the list. Then, click on "VM instances" in the sub-menu. Find your newly created instance and click on its name to enter its details page.
Click on the "Firewalls" tab and then click on the "Add firewall rule" button. Select "Allow all" as the source and destination, set the protocol to "tcp" and the ports to "80". Click on the "Add" button to save the changes.
Now that your virtual machine is configured, you need to install Docker on it.
### Connect to Your Instance
Open a terminal window on your local machine and use SSH to connect to your virtual machine. You can find the external IP address or DNS name of your instance in the GCP console. Use the following command to connect to your instance:
```bash
gcloud ssh --project=[PROJECT_ID] --zone=[ZONE] [INSTANCE_NAME]
```
Replace `[PROJECT_ID]` with your project ID, `[ZONE]` with the zone where your instance is located, and `[INSTANCE_NAME]` with the name of your instance.
You can also use web based SSH.
### Install Docker
Once connected, update the package list and install Docker using the following commands:
```bash
sudo apt-get update
sudo apt-get install docker.io
```
### Start the Docker Service
Start the Docker service using the following command:
```bash
sudo systemctl start docker
```
Now that Docker is installed and running, you can deploy cal.com on your virtual machine.
### Pull the Docker Image
Use the following command to pull the cal.com Docker image from Docker Hub:
```bash
docker pull cal/calcom
```
### Run the Docker Container
Run the Docker container using the following command:
```bash
docker run -d -p 80:80 cal/cal.com
```
This command maps port 80 on your local machine to port 80 inside the container, so you can access cal.com from outside the container.
### Access Cal.com
Open a web browser and navigate to `http://localhost`. You should now be able to access the cal.com homepage.
Congratulations! You have successfully deployed cal.com on Google Cloud Platform.
# Railway
Source: https://cal.com/docs/self-hosting/deployments/railway
You can deploy Cal.com on Railway using the button below.
The team at Railway also have a [detailed blog post](https://blog.railway.app/p/calendso) on deploying Cal.com on their platform.
## One Click Deployment
# Render
Source: https://cal.com/docs/self-hosting/deployments/render
You can deploy Cal.com on Render using the button below.
## One Click Deployment
# Vercel
Source: https://cal.com/docs/self-hosting/deployments/vercel
## Requirements
Currently Vercel Pro Plan is required to be able to Deploy this application with Vercel, due to limitations on the number of serverless functions on the free plan.
You need a PostgresDB database hosted somewhere. [Supabase](https://supabase.com/) offer a great free option while [Heroku](https://www.heroku.com/) offers a low-cost option.
## One Click Deployment
## Manual Deployment
### Local settings
```
git clone https://github.com/\/cal.com.git
```
Copy the `.env.example` file in `apps/web`, rename it to `.env` and fill it with your settings ([See manual setup](https://github.com/calcom/cal.com#manual-setup) and [Obtaining the Google API Credentials](https://github.com/calcom/cal.com#obtaining-the-google-api-credentials))
```
yarn install
```
Schema is located in at `packages/prisma/schema.prisma`.
```
yarn workspace @calcom/prisma db-deploy
```
To look at or modify the database content
```
yarn db-studio
```
Click on the `User` model to add a new user record.
Fill out the fields (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
Open a browser to [port 3000](http://localhost:3000/) on your localhost and login with your just created, first user.
Sometimes, yarn install might fail during deployment on Vercel, in which case, you can use `YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install` as the install command instead.
#### Deployment
Override to:
```
cd ../.. && yarn build --no-deps
```
# Docker
Source: https://cal.com/docs/self-hosting/docker
The Docker configuration for Cal is an effort powered by people within the community. Cal.com, Inc. does not provide official support for Docker, but we will accept fixes and documentation. Use at your own risk.
If you want to contribute to the Docker repository, [reply here](https://github.com/calcom/docker/discussions/32).
The Docker configuration can be found [in our docker repository](https://github.com/calcom/docker).
### Requirements
Make sure you have `docker` & `docker compose` installed on the server / system.
Note: `docker compose` without the hyphen is now the primary method of using docker-compose, per the Docker documentation.
### Getting Started
1. Clone calcom-docker
```
git clone --recursive https://github.com/calcom/docker.git calcom-docker
```
2. Change into the directory
```
cd calcom-docker
```
3. Rename `.env.example` to `.env` and then update `.env`
4. Build and start Cal.com via docker compose
```
docker compose up --build
```
5. (First Run) Open a browser to [http://localhost:5555](http://localhost:5555/) to look at or modify the database content.
a. Click on the `User` model to add a new user record.
b. Fill out the fields (remembering to encrypt your password with [BCrypt](https://bcrypt-generator.com/)) and click `Save 1 Record` to create your first user.
6. Open a browser to [http://localhost:3000](http://localhost:3000/) and login with your just created, first user.
### Configuration
#### Build-time variables
These variables must be provided at the time of the docker build, and can be provided by updating the .env file. Changing these is not required for evaluation, but may be required for running in production. Currently, if you require changes to these variables, you must follow the instructions to build and publish your own image.
* NEXT\_PUBLIC\_WEBAPP\_URL
* NEXT\_PUBLIC\_LICENSE\_CONSENT
* NEXT\_PUBLIC\_TELEMETRY\_KEY
#### Important Run-time variables
* NEXTAUTH\_SECRET
### Troubleshooting
* SSL edge termination: If running behind a load balancer which handles SSL certificates, you will need to add the environmental variable `NODE_TLS_REJECT_UNAUTHORIZED=0` to prevent requests from being rejected. Only do this if you know what you are doing and trust the services/load-balancers directing traffic to your service.
* Failed to commit changes: Invalid 'prisma.user.create()': Certain versions may have trouble creating a user if the field `metadata` is empty. Using an empty json object `{}` as the field value should resolve this issue. Also, the `id` field will autoincrement, so you may also try leaving the value of `id` as empty.
# How to sync third party apps
Source: https://cal.com/docs/self-hosting/guides/appstore-and-integration/syncing-third-party-apps
1. `CALCOM_WEBHOOK_SECRET`
* 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`
* The header name is expected to contain the webhook secret. The default is `calcom-webhook-secret`
4. `CALCOM_CREDENTIAL_SYNC_ENDPOINT`
* The endpoint on your platform that your instance of [Cal.com](https://Cal.com) will make a request to if the 3rd party app credentials are expired.
5. `CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY`
* 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.
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
{
// 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;
}
```
When [Cal.com](https://Cal.com) needs to refresh the app credentials it will make a request to `CALCOM_CREDENTIAL_SYNC_ENDPOINT`. The request contains the following.
```javascript
{
calcomUserId: string;
// App slug on Cal.com
appSlug: string;
}
```
This only works if you have integrated [Cal.com](https://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.
# Organization Setup
Source: https://cal.com/docs/self-hosting/guides/organization/organization-setup
This guide will walk you through setting up and configuring the organizations feature for your self-hosted Cal.com instance. Organizations allow you to create branded, multi-tenant environments within your Cal.com deployment.
## Prerequisites
Before setting up organizations, ensure you have:
* A working Cal.com instance already installed and running
* Admin access to your Cal.com instance
* Access to modify environment variables and restart your server
## Step 1: Enable Organizations Feature
1. Login as admin using `admin@example.com`
2. Navigate to **Settings** → **Admin** → **Features**
3. Turn on the **Organizations** feature flag under the Features section
## Step 2: Configure Environment Variables
Set the following environment variables in your `.env` file:
```bash
NEXT_PUBLIC_WEBAPP_URL=http://app.cal.local:3000
NEXT_PUBLIC_WEBSITE_URL=http://app.cal.local:3000
NEXTAUTH_URL=http://app.cal.local:3000
ORGANIZATIONS_ENABLED=1
```
## Step 3: Configure Local DNS
Add the following entry to your hosts file to enable local access:
```bash
127.0.0.1 app.cal.local
```
**Host file locations:**
* **Linux/Mac**: `/etc/hosts`
* **Windows**: `C:\Windows\System32\drivers\etc\hosts`
## Step 4: Start/Restart Development Server
After making the configuration changes, start/restart your development server:
```bash
yarn dev
```
## Step 5: Create an Organization
1. Login using `pro@example.com` (or any user account)
2. Visit `http://app.cal.local:3000/settings/organizations/new`
3. Follow the onboarding steps:
* Choose a slug for the organization(say `myorg`)
* Ignore pricing information (not required for self-hosting)
* Complete the first step (remaining steps can be skipped for now)
After creating the organization, you'll be moved inside it and all existing Cal.com links will redirect to the organization URL (e.g., `yourdomain.cal.local:3000`).
## Accessing Your Organization
Now if everything above went well, all booking pages for the organization will be accessible at:
```
http://myorg.cal.local:3000/{CAL_LINK}
```
Read more about some other [Organization related environment variables](./understanding-organization-env-variables.mdx) to configure your Cal.com instance to work with multiple organizations.
# Single Organization Setup
Source: https://cal.com/docs/self-hosting/guides/organization/single-organization-setup
This guide will walk you through setting up your cal.com instance to work with an organization using the same domain.
Note that an organization's booking pages are by default accessible at `http://{orgSlug}.yourcalinstance.example/{CAL_LINK}` but with this setup, you won't need another domain, if you want to use just one organization.
## Step 1: Identify what slug you want to use for your organization
For a company with domain `yourdomain.com`, a good slug would be `yourdomain`.
## Step 2: Setup and create an organization
Follow the [Organization Setup](./organization-setup) guide to enable organizations feature.
Make sure to use the slug you decided in Step 1.
## Step 3: Add Environment Variable
Set the following environment variable in your `.env` file:
```bash
# yourdomain is the slug you decided in Step 1
NEXT_PUBLIC_SINGLE_ORG_SLUG=yourdomain
```
## Step 4: Restart Development Server
After making the configuration changes, restart your development server:
```bash
yarn dev
```
# Environment Variables
Source: https://cal.com/docs/self-hosting/guides/organization/understanding-organization-env-variables
This guide explains the key environment variables used to configure organizations in your Cal.com self-hosted instance.
## RESERVED\_SUBDOMAINS
This is a comma-separated list of subdomains that are not allowed to be used as organization slugs.
For example, if you set `RESERVED_SUBDOMAINS="app,auth,help"`, then the domains `app.cal.com`, `auth.cal.com` and `help.cal.com` are reserved for use by the Cal.com instance. This means you cannot create an organization with the slug `app`, `auth` or `help`.
## ALLOWED\_HOSTNAMES
This is a comma-separated list of domains on whose subdomains the booking pages and dashboard are allowed to work.
**Examples:**
If `ALLOWED_HOSTNAMES="cal.com,cal.dev"`, then:
* `acme.cal.com` is a valid organization booking domain and `WEBAPP_URL` can be set to `http://app.cal.com`
* `dunder.cal.dev` is also a valid organization subdomain and `WEBAPP_URL` can be set to `http://app.cal.dev`
If `ALLOWED_HOSTNAMES="cal.domain.tld"`, then:
* `WEBAPP_URL` should be set to `http://app.cal.domain.tld`
* Valid organization domains include: `acme.cal.domain.tld`, `dunder.cal.domain.tld`, `xxxx.cal.domain.tld`
Make sure your DNS is properly configured to point organization subdomains to your Cal.com instance.
# Can Cal.com sponsor my open source project?
Source: https://cal.com/docs/self-hosting/guides/sponsorship/can-calcom-sponsor-my-open-source-project
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
or
### HTML Code:
```html
```
or
```html
```
## 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](mailto:peer@cal.com) 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.
# Instance-wide theming using color tokens
Source: https://cal.com/docs/self-hosting/guides/white-labeling/color-tokens
Cal.com offers instance-wide theming capabilities with minimum friction. Administrators and developers have the flexibility to tailor the look and feel of the app to align with their brand identity or specific aesthetic preferences with very easy and minor changes.
We use color tokens, which are the primitive color values in our design system, represented by context names. Their values can easily be set inside the `apps/web/styles/globals.css` file, an example of which is shown below:
```css
**apps/web/styles/globals.css**
/* background */
:root {
--cal-bg-emphasis: #e5e7eb;
--cal-bg: white;
--cal-bg-subtle: #f3f4f6;
--cal-bg-muted: #f9fafb;
--cal-bg-inverted: #111827;
/* background -> components*/
--cal-bg-info: #dee9fc;
--cal-bg-success: #e2fbe8;
--cal-bg-attention: #fceed8;
--cal-bg-error: #f9e3e2;
--cal-bg-dark-error: #752522;
...
}
.dark {
/* background */
--cal-bg-emphasis: #2b2b2b;
--cal-bg: #101010;
--cal-bg-subtle: #2b2b2b;
--cal-bg-muted: #1c1c1c;
--cal-bg-inverted: #f3f4f6;
/* background -> components*/
--cal-bg-info: #dee9fc;
--cal-bg-success: #e2fbe8;
--cal-bg-attention: #fceed8;
--cal-bg-error: #f9e3e2;
--cal-bg-dark-error: #752522;
...
}
```
To modify the theme of an instance, the hexcodes can easily be replaced here to instantly and seamlessly. This ensures a consistent and harmonious visual experience across all sections of the application, reflecting your desired aesthetic with precision.
To have a better understanding of our design system, you can view our [design documentation here](https://design.cal.com/basics/colors). If it peaks your interest, you can view the [Figma file of our Design Tokens here](https://www.figma.com/file/9MOufQNLtdkpnDucmNX10R/Cal-DS---Components?type=design\&node-id=25883-174646\&mode=design).
By allowing themes to be applied across the entire instance, businesses can ensure that their brand identity remains consistent.
Should there be any rebranding or minor tweaks to the corporate visual identity, instance-wide theming allows for easy and swift updates. With minimal changes, the new theme can be propagated across the entire platform, eliminating the need for manual adjustments on individual sections or components.
# How to add custom CSS
Source: https://cal.com/docs/self-hosting/guides/white-labeling/custom-css
Cal.com uses [TailwindCSS](https://tailwindcss.com/) as a replacement for traditional CSS styling within the application, but some people prefer to add CSS styles themselves.
CSS files should be stored in the `styles` directory within the codebase.
Within the `styles` directory, you will find two CSS files, `fonts.css` and `global.css`. We suggest not to add to these files, and instead create new CSS files and import them into the application. This helps reduce conflicts when pulling in changes that we've made to either of the existing CSS files.
### Adding new stylesheets
Firstly, create the CSS file inside the `styles` directory.
Then, open the `pages/_app.tsx` file, and you will see the following two lines:
```js
import "../styles/fonts.css";
import "../styles/globals.css";
```
Duplicate one of these import statements and change the path to link to your new CSS stylesheet, like so:
```js
import "../styles/your-new-stylesheet.css";
```
These styles will apply to all pages and components in your application.
Due to the global nature of stylesheets, and to avoid conflicts, you may **only import them inside** **`pages/_app.tsx`**.
# How to white label the self hosted instance
Source: https://cal.com/docs/self-hosting/guides/white-labeling/introduction
We have made it very easy for you to white label your self-hosted instance.
Please update the following env variables to match your desired branding:
```
NEXT_PUBLIC_APP_NAME="acme.com"
NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS="support@acme.com"
NEXT_PUBLIC_COMPANY_NAME="ACME inc."
```
The images for the logo are placed in `/web/public` . You can update the logo by changing the value of the following constants in `/packages/lib/constants.ts` file:
1. LOGO
2. LOGO\_ICON
to the file name of your logo and logo icon, or the paths with file name to your respective logo and logo icon images from `/web/public`.
The instance wide theme can be easily updated thanks to the color tokens we have in place. Simply modify the hex-codes within the `apps/web/styles/globals.css` file against the [color tokens](/self-hosting/guides/white-labeling/color-tokens), and the entire application can be consistently whitelabeled to your brand identity.
If you're using custom SMTP server for emails, you might need to set `NODE_EXTRA_CA_CERTS` env variable equal to the path of your CA certificate so that it can be recognized by the calcom application.
# Installation
Source: https://cal.com/docs/self-hosting/installation
There are multiple ways in which you can deploy Cal.com, providing support for customers who want to implement Cal.com within their existing infrastructure stack. Let's go through them one-by-one. You can find the instructions for deployment in our README file, which is the section you see when you scroll down in our GitHub repository, or if you've got a copy of Cal.com downloaded already, you can open the file contained in the downloaded repository called `README.md`.
## Requirements
Cal.com runs with pretty minimal hardware requirements by itself. The most intensive part for the software is when you actually build the software, but once it's running it's relatively lightweight.
Cal.com works with a very large range of operating systems, as it only requires JavaScript execution to run. **Cal.com is known to work well with Windows, Mac, Linux and BSD.** Although they do work well on all of them, for production deployments we would suggest Linux as the ideal platform. Any operating system that runs Node.js should be able to work too, but these are some of the common operating systems that we know work well.
To run Cal.com, you need to install a few things. **Node.js, yarn, Git and PostgreSQL**. We use **Prisma** for database maintenance, and is one of the dependencies. We won’t publish installation guides for these as they have their own resources available on the internet. If you're on Linux/BSD, all of these things should be readily available on your package manager. Your best bet is searching for something like **Debian 12 PostgreSQL**, which will give you a guide to installing and configuring PostgreSQL on Debian Linux 12.
To ensure optimal performance and compatibility, we highly recommend using Node.js version 18 for your development environment. This version provides the best balance of stability, features, and security for this project. Please make sure to update your Node.js installation if necessary.
## Production Build
1. First, you git clone the repository with the following command, so you have a copy of the code.
```
git clone https://github.com/calcom/cal.com.git
```
If you are on windows, you would need to use the following command when cloning, with **admin privileges**:
```
git clone -c core.symlinks=true https://github.com/calcom/cal.com.git
```
2. Then, go into the directory you just cloned with
```
cd cal.com
```
and run
```
yarn
```
to install all of the dependencies. Essentially, dependencies are just things that Cal.com needs to install to be able to work.
3. Then, you just need to set up a couple of things. For that, we use a `.env` file. We just need to copy and paste the `.env.example` file and rename the copy to `.env`. Here you'll have a template with comments showing you the settings you need/might want to set.
For preview deployments on **Vercel**, please leave the following environment variables empty:
* **NEXTAUTH\_URL**
* **NEXT\_PUBLIC\_WEBSITE\_URL**
* **NEXT\_PUBLIC\_WEBAPP\_URL**
4. Next, use the command
```
openssl rand -base64 32
```
(or another secret generator tool if you prefer) to generate a key and add it under `NEXTAUTH_SECRET` in the .env file.
5. You'll also want to fill out the `.env.appStore` file similar to the `.env` file as this includes keys to enable apps.
#### Production Build
For a production build, **please make sure** to set up [E2E testing](/developing/local-development#e2e-testing) and [Upgrading](/self-hosting/upgrading) the database from earlier version, and the proceed to build as follows:
```
yarn build
yarn start
```
Please make sure to upgrade your database before you build for production
## Cron Jobs
There are a few features which require cron job setup. When self-hosting, you would probably need to set up cron jobs according to the hosting platform you are using.
For instance, if you are hosting on Vercel, you would need to set up cron jobs by following [this document](https://vercel.com/guides/how-to-setup-cron-jobs-on-vercel).
At cal.com, the cron jobs are found in the following directory:
```
/apps/web/app/api/cron
```
## App store seeder
We recommend using the admin UI/wizard instead of the seeder to enable app store apps
## API
#### Step 1
Copy the .env files from their respective example files:
```
cp apps/api/v2/.env.example apps/api/v2/.env
cp .env.example .env
```
#### Step 2
Install packages with yarn:
```
yarn
```
### Running API server
Build & Run the API V2 with yarn:
```
yarn workspace @calcom/api-v2 build
yarn workspace @calcom/api-v2 start
```
## Vercel
As Cal.com is written in Next.js, Vercel is the perfect platform to host this on (Vercel built Next.js). You can simply follow the [instructions provided by Vercel to get started](https://vercel.com/docs/concepts/get-started). All you do is fork your own version of the repository, click new on Vercel and select the repository. It'll pretty much do the rest for you. The one thing you will need to do is set the environment variables (the .env file). As you can't create a .env file on Vercel, you can go into the settings and manually add each variable. Use the .env.example file for reference as to what you should add. You can learn more about [setting environment variables on Vercel here](https://vercel.com/docs/concepts/projects/environment-variables).
## Other environments
Cal.com effectively is just a Next.js application, so any possible solution you find online pertaining to Next.js applications should work. One example is Netlify, which is pretty similar to Vercel. It says it supports Next.js, so you can deploy Cal.com on Netlify. Refer to Netlify's docs on Next.js projects for more info. Another example is on a self hosted instance people may want to configure complex reverse proxies, SSL gateways and all sorts of other stuff. We can't officially support every configuration, but for any edge case where you may want to deploy Cal.com with X, just refer to X's docs on Next.js applications and you should be fine.
That's it. Your new self hosted Cal.com instance should now be up and running.
For more details on specific deployment instructions for AWS, Azure, etc.
# License key
Source: https://cal.com/docs/self-hosting/license-key
If you wish to **self-host** Cal.com with our Commercial License, you need to purchase a License Key to do so.
You can acquire the license by contacting [cal.com/sales](https://cal.com/sales)
For development environment, please use the following as a localhost license key
```
59c0bed7-8b21-4280-8514-e022fbfc24c7
```
# SSO setup
Source: https://cal.com/docs/self-hosting/sso-setup
Cal.com supports both Security Assertion Markup Language (SAML) and OpenID Connect (OIDC), two of the industry's leading authentication protocols. We prioritize your ease of access and security by providing robust Single Sign-On (SSO) capabilities. Whether you're looking for the XML-based standard of SAML or the lightweight OIDC, our platform is equipped to integrate smoothly with your preferred identity provider, ensuring both convenience and security for your users.
You need an Enterprise License to avail this when self-hosting
### Setting up SAML login
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 from where the SAML metadata can be uploaded and configured.
3. Create a SAML application with your Identity Provider (IdP) using the instructions here - [SAML Setup](/self-hosting/sso-setup#saml-registration-with-identity-providers)
4. Remember to configure access to the IdP SAML app for all your users (who need access to Cal).
5. You will need the XML metadata from your IdP later, so keep it accessible.
6. Log in to one of the admin accounts configured in SAML\_ADMINS and then navigate to Settings -> Security.
7. You should see a SAML configuration section, copy and paste the XML metadata from step 5 and click on Save.
8. Your provisioned users can now log into Cal using SAML.
### SAML Registration with Identity Providers
This guide explains the settings you need to use to configure SAML with your Identity Provider. Once this is set up you should get an XML metadata file that should then be uploaded on your Cal.com self-hosted instance.
> **Note:** Please do not add a trailing slash at the end of the URLs. Create them exactly as shown below.
**Assertion consumer service URL / Single Sign-On URL / Destination URL:** https\://\/api/auth/saml/callback \[Replace the placeholder with the URL for your self-hosted Cal instance]
**Entity ID / Identifier / Audience URI / Audience Restriction:** [https://saml.cal.com](https://saml.cal.com)
**Response:** Signed
**Assertion Signature:** Signed
**Signature Algorithm:** RSA-SHA256
**Assertion Encryption:** Unencrypted
**Name ID Format:** EmailAddress
**Application username:** email
**Mapping Attributes / Attribute Statements:**
| Name | Name Format | Value |
| :-------- | :---------- | :------------- |
| firstName | Basic | user.firstName |
| lastName | Basic | user.lastName |
### Setting up OIDC login
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. Keep handy the Client Secret, Client ID and Well Known URL with you for the next step.
4. 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).
5. Visit `{BASE_URL}/settings/security/sso` and you should see something like this:
6. Click on Configure SSO with OIDC, and then enter the Client Secret, Client ID and Well known URL from the Step 3, and click save.
7. That's it. Now when you try to login with SSO, your OIDC provider will handle the auth.
# Upgrading
Source: https://cal.com/docs/self-hosting/upgrading
Pull the current version:
```
git pull
```
Check if dependencies got added/updated/removed
```
yarn
```
Apply database migrations by running **one of** the following commands:
In a development environment, run:
```
yarn workspace @calcom/prisma db-migrate
```
(this can clear your development database in some cases)
In a production environment, run:
```
yarn workspace @calcom/prisma db-deploy
```
Check for `.env` variables changes
```
yarn predev
```
Start the server. In a development environment, just do:
```
yarn dev
```
For a production build, run for example:
```
yarn build
yarn start
```
Enjoy the new version.