Skip to main content
Webhooks offer a great way to automate the flow with other apps when invitees schedule, cancel or reschedule events, or when a meeting starts or 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:
1

Subscriber URL

This is the listener URL where the payload will be sent when an event trigger is activated.The subscriber URL must meet the following requirements:
  • Cal.com SaaS: Only HTTPS URLs are accepted. HTTP, private/internal IP addresses (e.g., 10.x.x.x, 192.168.x.x, 127.0.0.1), and localhost are blocked.
  • Self-hosted: Both HTTP and HTTPS URLs are accepted, and private IP addresses are allowed for internal webhooks.
  • All environments: Cloud metadata endpoints (e.g., 169.254.169.254) and non-HTTP protocols (e.g., ftp://, file://) are always blocked.
If your subscriber URL does not meet these requirements, the webhook creation request will be rejected with an error.
2

Event triggers

You can 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
  • Instant Meeting Accepted
  • Booking No-show Updated
  • Booking Location Updated
  • After Hosts Didn't Join Cal Video
  • After Guests Didn't Join Cal Video
  • Wrong Assignment Report
  • Delegation Credential Error
  • Delegation Credential Secret Rotated
  • Delegation Credential Secret Rotation Failed
  • Delegation Credential Rotation Required
3

Secret

You can provide a secret key with this webhook to verify it 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.
4

Custom Payload

You have the option to customize the payload that you receive when a subscribed event is triggered.

Webhook payload reference

Most webhook payloads are wrapped in the following structure:
MEETING_STARTED and MEETING_ENDED are exceptions — they use a flat payload where booking fields are at the top level alongside triggerEvent, with no payload wrapper. See meeting started and meeting ended webhooks for details.
Webhook payloads are versioned. The version of the payload sent is included in the x-cal-webhook-version HTTP header. Example: x-cal-webhook-version: 2021-10-20
For seated event types, the attendees array in webhook payloads contains only the attendee associated with the specific seat that triggered the webhook. For example, when a new seat is booked, the webhook includes only that seat’s attendee — not all attendees across the entire booking. This applies to all booking-related triggers (BOOKING_CREATED, BOOKING_CANCELLED, BOOKING_RESCHEDULED, etc.).
Select a version and trigger event to view the example payload:
Fires when the location of an existing booking is changed. The payload mirrors the standard booking payload, with one addition: previousLocation holds the location before the change and existing location holds the new location.
Unlike other events, MEETING_STARTED uses a flat payload structure — booking fields are at the top level, not nested inside a payload object. This webhook fires automatically at the booking’s scheduled start time. See meeting started and meeting ended webhooks for details.
Unlike other events, MEETING_ENDED uses a flat payload structure — booking fields are at the top level, not nested inside a payload object. This webhook fires automatically at the booking’s scheduled end time. See meeting started and meeting ended webhooks for details.
Fired when a host accepts an instant meeting and becomes the organizer via the connect-and-join flow. This only triggers for the first host to accept — if the booking has already been accepted by another host, the webhook is not sent.
toUser is the redirect/forwarding user and can be null if no redirect is set.
Root-level fields (e.g., name, email, department) are duplicated for backward compatibility. The value field in responses is deprecated; use response instead. For select/multiselect fields, response includes both the label and ID.
Same structure as FORM_SUBMITTED. Triggered 15 minutes after form submission if no booking was made from the routing form.
Fired when a pending secret has been verified and promoted to active. It does not fire when a replacement secret is only minted and staged as pending.
Fired only when an automatic secret mint or promotion has kept failing continuously for 48+ hours and the credential is marked as blocked (secretRotationBlocked=true). Transient failures before that 48-hour terminal window are retried automatically and do not fire a webhook. error.code is SECRET_MINT_FAILED when minting the replacement secret failed, or SECRET_PROMOTION_FAILED when a minted pending secret could not be verified with the workspace platform.
Fired for credentials that have opted out of automatic secret rotation (optOutAutoSecretRotation=true) whose active secret is approaching expiry — it is a manual-rotation reminder, not a signal that automatic rotation failed or was blocked. Terminal automatic-rotation failures (including an abandoned pending secret) fire DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED instead. Rotate the secret manually from the delegation credential settings when you receive this event.
This webhook is triggered when a team member reports that a booking from a routing form was assigned to the wrong person. This is useful for tracking routing accuracy and improving CRM data quality.
This webhook only fires for bookings that came through a routing form and have an assignment reason.

Booking No-show Updated webhook payload

This webhook is triggered when an attendee is manually marked or unmarked as no-show on the /bookings/past page. Example payload when marking an attendee as no-show:
Example payload when unmarking an attendee as no-show:

Cal Video No-Show Detection webhooks

These webhooks are triggered automatically when hosts or guests don’t join a Cal Video meeting within the configured time after the booking starts. Unlike BOOKING_NO_SHOW_UPDATED which requires manual action, these are detected automatically by checking Cal Video participant data.
These webhooks only work for bookings that use Cal Video as the meeting location.
Example payload when host didn't join (AFTER_HOSTS_CAL_VIDEO_NO_SHOW):
Example payload when guest didn't join (AFTER_GUESTS_CAL_VIDEO_NO_SHOW):

Meeting started and meeting ended webhooks

The MEETING_STARTED and MEETING_ENDED webhooks are time-delayed — they fire automatically at the booking’s scheduled start time and end time, respectively. You do not need to take any action to trigger them beyond subscribing to these events. Key behaviors:
  • Automatic scheduling: When a booking is confirmed, Cal.com schedules the MEETING_STARTED webhook to fire at the booking’s startTime and the MEETING_ENDED webhook to fire at the booking’s endTime.
  • Cancellation handling: If a booking is cancelled or rescheduled, any pending MEETING_STARTED and MEETING_ENDED webhooks for that booking are automatically cancelled. When a booking is rescheduled, new webhooks are scheduled for the updated times.
  • Flat payload format: Unlike other webhook events, these two events use a flat payload structure. The booking data is spread at the top level alongside triggerEvent, rather than nested inside a payload object. See the example payloads for the exact structure.
  • No custom payload template support: Custom payload templates are not applied to MEETING_STARTED and MEETING_ENDED webhooks. The payload is always sent as raw JSON.
If you are migrating from a system that consumes other webhook events, note that the payload shape for MEETING_STARTED and MEETING_ENDED differs from events like BOOKING_CREATED. Ensure your webhook handler accounts for the flat structure.

Delegation credential secret rotation webhooks

Delegation credentials let an organization act on behalf of its members with a workspace platform. Microsoft 365 (Azure Entra ID) delegation credentials authenticate with a client secret that expires, so Cal.com periodically rotates it and emits webhooks so administrators can track rotation health. Google delegation credentials don’t have an expiring secret and are not part of this rotation lifecycle. Subscribe to these events on an organization-scoped webhook to be notified about the delegation credential rotation lifecycle:
  • DELEGATION_CREDENTIAL_SECRET_ROTATED — a pending secret was verified and promoted, and is now active.
  • DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED — an automatic mint or promotion attempt has kept failing for 48+ hours and rotation is now blocked for that credential (error.code is SECRET_MINT_FAILED or SECRET_PROMOTION_FAILED). Transient failures before that terminal window are retried automatically and do not fire a webhook.
  • DELEGATION_CREDENTIAL_ROTATION_REQUIRED — a reminder for credentials that opted out of automatic rotation (optOutAutoSecretRotation=true) whose active secret is nearing expiry. This event does not indicate that automatic rotation failed or was blocked — see DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED for that. In both cases, an administrator must rotate the secret manually from the delegation credential settings.
DELEGATION_CREDENTIAL_SECRET_ROTATED and DELEGATION_CREDENTIAL_SECRET_ROTATION_FAILED fire only for delegation credentials with automatic secret rotation enabled. DELEGATION_CREDENTIAL_ROTATION_REQUIRED fires only for delegation credentials that have opted out of automatic secret rotation. They are delivered asynchronously with retries on transient network errors and HTTP 408, 429, and 5xx responses.

Verifying the authenticity of the received payload

1

Add a new secret key to your webhook

Simply add a new secret key to your webhook configuration and save it.
2

Wait for the webhook to be triggered

The webhook will trigger when an event is created, cancelled, rescheduled, or when a meeting ends.
3

Create an HMAC using the secret key

Use the secret key to create an HMAC, and update it with the webhook payload received to generate an SHA256 hash.
4

Verify the payload authenticity

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:
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

Person Structure