Documentation Index Fetch the complete documentation index at: https://mintlify.com/calcom/cal.com/llms.txt
Use this file to discover all available pages before exploring further.
Webhooks allow your application to receive real-time notifications when events occur in Cal.com. Instead of polling the API, webhooks push data to your server as events happen.
Overview
Cal.com webhooks deliver HTTP POST requests to your specified URL when events occur:
Real-time notifications for booking events
Automatic retries with exponential backoff
Signature verification for security
Custom payload templates for flexibility
Multiple webhook versions for backward compatibility
Webhook Types
Webhooks can be created at different scopes:
User Webhooks Triggered for events related to a specific user
Event Type Webhooks Triggered for bookings of a specific event type
Team Webhooks Triggered for events within a team
Webhook Events
Cal.com supports webhooks for the following event triggers:
Core Booking Events
Event Description BOOKING_CREATEDNew booking created BOOKING_RESCHEDULEDBooking time changed BOOKING_CANCELLEDBooking cancelled BOOKING_REJECTEDBooking request rejected BOOKING_REQUESTEDNew booking requires approval BOOKING_PAIDPayment completed for booking BOOKING_PAYMENT_INITIATEDPayment process started BOOKING_NO_SHOW_UPDATEDNo-show status updated
Meeting Events
Event Description MEETING_STARTEDVideo meeting started MEETING_ENDEDVideo meeting ended INSTANT_MEETINGInstant meeting created RECORDING_READYMeeting recording available RECORDING_TRANSCRIPTION_GENERATEDTranscription completed
Other Events
Event Description OOO_CREATEDOut of office entry created FORM_SUBMITTEDRouting form submitted with booking FORM_SUBMITTED_NO_EVENTRouting form submitted without booking ROUTING_FORM_FALLBACK_HITNo routing rules matched AFTER_HOSTS_CAL_VIDEO_NO_SHOWHost no-show detected AFTER_GUESTS_CAL_VIDEO_NO_SHOWGuest no-show detected DELEGATION_CREDENTIAL_ERRORCredential delegation error WRONG_ASSIGNMENT_REPORTAssignment error reported
Creating Webhooks
Create a User Webhook
Endpoint: POST /v2/webhooks
Request:
curl -X POST https://api.cal.com/v2/webhooks \
-H "Authorization: Bearer cal_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"subscriberUrl": "https://your-app.com/webhooks/cal",
"active": true,
"triggers": [
"BOOKING_CREATED",
"BOOKING_RESCHEDULED",
"BOOKING_CANCELLED"
],
"secret": "your_webhook_secret"
}'
Response:
{
"status" : "success" ,
"data" : {
"id" : "webhook_123" ,
"subscriberUrl" : "https://your-app.com/webhooks/cal" ,
"active" : true ,
"triggers" : [
"BOOKING_CREATED" ,
"BOOKING_RESCHEDULED" ,
"BOOKING_CANCELLED"
],
"secret" : "your_webhook_secret" ,
"version" : "2021-10-20" ,
"createdAt" : "2024-03-15T10:00:00Z"
}
}
Create an Event Type Webhook
Endpoint: POST /v2/event-types/:eventTypeId/webhooks
curl -X POST https://api.cal.com/v2/event-types/123/webhooks \
-H "Authorization: Bearer cal_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"subscriberUrl": "https://your-app.com/webhooks/event-type",
"active": true,
"triggers": ["BOOKING_CREATED", "BOOKING_CANCELLED"]
}'
Create a Team Webhook
Endpoint: POST /v2/teams/:teamId/event-types/:eventTypeId/webhooks
curl -X POST https://api.cal.com/v2/teams/456/event-types/123/webhooks \
-H "Authorization: Bearer cal_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"subscriberUrl": "https://your-app.com/webhooks/team",
"active": true,
"triggers": ["BOOKING_CREATED"]
}'
Managing Webhooks
List Webhooks
Response:
{
"status" : "success" ,
"data" : [
{
"id" : "webhook_123" ,
"subscriberUrl" : "https://your-app.com/webhooks/cal" ,
"active" : true ,
"triggers" : [ "BOOKING_CREATED" , "BOOKING_CANCELLED" ],
"version" : "2021-10-20"
}
]
}
Get Webhook Details
GET /v2/webhooks/:webhookId
Update Webhook
PATCH /v2/webhooks/:webhookId
Request:
curl -X PATCH https://api.cal.com/v2/webhooks/webhook_123 \
-H "Authorization: Bearer cal_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"active": false,
"triggers": ["BOOKING_CREATED"]
}'
Delete Webhook
DELETE /v2/webhooks/:webhookId
Webhook Payload
Standard Payload Structure
All webhooks follow this structure:
{
"triggerEvent" : "BOOKING_CREATED" ,
"createdAt" : "2024-03-15T10:00:00Z" ,
"payload" : {
// Event-specific data
}
}
Booking Created Payload
{
"triggerEvent" : "BOOKING_CREATED" ,
"createdAt" : "2024-03-15T10:00:00Z" ,
"payload" : {
"bookingId" : 123 ,
"uid" : "booking_abc123" ,
"title" : "30 Minute Meeting between John Doe and Jane Smith" ,
"type" : "30min" ,
"description" : "Quick sync meeting" ,
"startTime" : "2024-03-20T15:00:00Z" ,
"endTime" : "2024-03-20T15:30:00Z" ,
"status" : "ACCEPTED" ,
"organizer" : {
"name" : "John Doe" ,
"email" : "john@example.com" ,
"timeZone" : "America/New_York" ,
"utcOffset" : -240
},
"attendees" : [
{
"name" : "Jane Smith" ,
"email" : "jane@example.com" ,
"timeZone" : "America/Los_Angeles" ,
"utcOffset" : -420 ,
"firstName" : "Jane" ,
"lastName" : "Smith"
}
],
"location" : "https://meet.google.com/abc-defg-hij" ,
"responses" : {
"name" : {
"label" : "your_name" ,
"value" : "Jane Smith"
},
"email" : {
"label" : "email_address" ,
"value" : "jane@example.com"
}
},
"eventTitle" : "30 Minute Meeting" ,
"eventDescription" : "A brief meeting to discuss project updates" ,
"price" : 0 ,
"currency" : "usd" ,
"length" : 30 ,
"requiresConfirmation" : false
}
}
Booking Cancelled Payload
{
"triggerEvent" : "BOOKING_CANCELLED" ,
"createdAt" : "2024-03-15T11:00:00Z" ,
"payload" : {
"bookingId" : 123 ,
"uid" : "booking_abc123" ,
"title" : "30 Minute Meeting" ,
"status" : "CANCELLED" ,
"cancelledBy" : "john@example.com" ,
"cancellationReason" : "Conflict with another meeting" ,
"organizer" : {
"name" : "John Doe" ,
"email" : "john@example.com"
},
"attendees" : [
{
"name" : "Jane Smith" ,
"email" : "jane@example.com"
}
]
}
}
Booking Rescheduled Payload
{
"triggerEvent" : "BOOKING_RESCHEDULED" ,
"createdAt" : "2024-03-15T12:00:00Z" ,
"payload" : {
"bookingId" : 123 ,
"uid" : "booking_abc123" ,
"title" : "30 Minute Meeting" ,
"startTime" : "2024-03-21T15:00:00Z" ,
"endTime" : "2024-03-21T15:30:00Z" ,
"rescheduleId" : 456 ,
"rescheduleUid" : "booking_def456" ,
"rescheduleStartTime" : "2024-03-20T15:00:00Z" ,
"rescheduleEndTime" : "2024-03-20T15:30:00Z" ,
"rescheduledBy" : "jane@example.com" ,
"organizer" : {
"name" : "John Doe" ,
"email" : "john@example.com"
},
"attendees" : [
{
"name" : "Jane Smith" ,
"email" : "jane@example.com"
}
]
}
}
Meeting Started Payload
{
"triggerEvent" : "MEETING_STARTED" ,
"createdAt" : "2024-03-20T15:00:00Z" ,
"payload" : {
"booking" : {
"id" : 123 ,
"startTime" : "2024-03-20T15:00:00Z" ,
"endTime" : "2024-03-20T15:30:00Z" ,
"title" : "30 Minute Meeting" ,
"status" : "ACCEPTED" ,
"user" : {
"name" : "John Doe" ,
"email" : "john@example.com" ,
"timeZone" : "America/New_York"
},
"attendees" : [
{
"name" : "Jane Smith" ,
"email" : "jane@example.com"
}
]
}
}
}
Webhook Signature Verification
Webhooks include a signature in the X-Cal-Signature-256 header for verification.
Verifying Webhook Signatures
const crypto = require ( 'crypto' );
function verifyWebhookSignature ( payload , signature , secret ) {
const expectedSignature = crypto
. createHmac ( 'sha256' , secret )
. update ( JSON . stringify ( payload ))
. digest ( 'hex' );
return crypto . timingSafeEqual (
Buffer . from ( signature ),
Buffer . from ( expectedSignature )
);
}
// Express middleware
app . post ( '/webhooks/cal' , ( req , res ) => {
const signature = req . headers [ 'x-cal-signature-256' ];
const secret = process . env . WEBHOOK_SECRET ;
if ( ! verifyWebhookSignature ( req . body , signature , secret )) {
return res . status ( 401 ). send ( 'Invalid signature' );
}
// Process webhook
const { triggerEvent , payload } = req . body ;
console . log ( `Received ${ triggerEvent } :` , payload );
res . status ( 200 ). send ( 'OK' );
});
Custom Payload Templates
You can customize webhook payloads using templates:
curl -X POST https://api.cal.com/v2/webhooks \
-H "Authorization: Bearer cal_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"subscriberUrl": "https://your-app.com/webhooks",
"active": true,
"triggers": ["BOOKING_CREATED"],
"payloadTemplate": "{
\"event\": \"{{type}}\",
\"booking\": {
\"id\": {{bookingId}},
\"title\": \"{{title}}\",
\"start\": \"{{startTime}}\",
\"end\": \"{{endTime}}\"
},
\"organizer\": \"{{organizer.name}}\",
\"attendee\": \"{{attendees.0.name}}\"
}"
}'
Available template variables:
{{type}} - Event type
{{title}} - Booking title
{{bookingId}} - Booking ID
{{startTime}} - Start time
{{endTime}} - End time
{{organizer.name}} - Organizer name
{{organizer.email}} - Organizer email
{{attendees.0.name}} - First attendee name
{{attendees.0.email}} - First attendee email
Webhook Delivery
Delivery Behavior
Timeout : 30 seconds per attempt
Retries : Up to 5 attempts with exponential backoff
Backoff : 1s, 2s, 4s, 8s, 16s
Success : Any 2xx status code
Failure : Non-2xx status code or timeout
Responding to Webhooks
Your endpoint should:
Respond with a 2xx status code within 30 seconds
Process webhooks asynchronously if needed
Return quickly to avoid timeouts
app . post ( '/webhooks/cal' , async ( req , res ) => {
// Respond immediately
res . status ( 200 ). send ( 'OK' );
// Process webhook asynchronously
processWebhookAsync ( req . body ). catch ( console . error );
});
async function processWebhookAsync ( data ) {
// Long-running processing here
await updateDatabase ( data );
await sendNotifications ( data );
}
Webhook Versions
Webhooks support versioning for backward compatibility:
Version 2021-10-20 (Current)
The current webhook payload format. See payload examples above.
Specifying Webhook Version
{
"subscriberUrl" : "https://your-app.com/webhooks" ,
"active" : true ,
"triggers" : [ "BOOKING_CREATED" ],
"version" : "2021-10-20"
}
Testing Webhooks
webhook.site - Get a temporary URL for testing
ngrok - Expose your local server
Postman - Mock webhook server
Testing with ngrok
# Start ngrok
ngrok http 3000
# Use the ngrok URL in your webhook configuration
https://abc123.ngrok.io/webhooks/cal
Test Webhook Endpoint
const express = require ( 'express' );
const app = express ();
app . use ( express . json ());
app . post ( '/webhooks/cal' , ( req , res ) => {
console . log ( 'Webhook received:' );
console . log ( JSON . stringify ( req . body , null , 2 ));
res . status ( 200 ). send ( 'OK' );
});
app . listen ( 3000 , () => {
console . log ( 'Webhook server listening on port 3000' );
});
Error Handling
Webhook Delivery Failures
If webhook delivery fails after all retries:
The webhook remains active
Future events will continue to trigger
Check webhook logs in Cal.com dashboard
Common Issues
Ensure your endpoint responds within 30 seconds
Process webhooks asynchronously
Return 200 status immediately
Use valid SSL certificates
Don’t use self-signed certificates
Ensure certificate is not expired
Verify webhook signature correctly
Use the secret provided when creating webhook
Check signature header name: X-Cal-Signature-256
Implement idempotency using booking ID
Track processed webhook IDs
Handle duplicate deliveries gracefully
Best Practices
Handle duplicate webhook deliveries: const processedWebhooks = new Set ();
app . post ( '/webhooks/cal' , async ( req , res ) => {
const { payload } = req . body ;
const webhookId = ` ${ payload . bookingId } - ${ req . body . createdAt } ` ;
if ( processedWebhooks . has ( webhookId )) {
return res . status ( 200 ). send ( 'Already processed' );
}
processedWebhooks . add ( webhookId );
// Process webhook
await processBooking ( payload );
res . status ( 200 ). send ( 'OK' );
});
Maintain webhook logs for debugging: app . post ( '/webhooks/cal' , async ( req , res ) => {
// Log webhook
await logWebhook ({
timestamp: new Date (),
triggerEvent: req . body . triggerEvent ,
payload: req . body . payload ,
headers: req . headers
});
// Process webhook
await processWebhook ( req . body );
res . status ( 200 ). send ( 'OK' );
});
Track webhook delivery success rates:
Monitor response times
Alert on repeated failures
Track processing errors
Review webhook logs regularly
Always verify webhook signatures
Use HTTPS only
Validate payload structure
Rate limit webhook endpoints
Next Steps
Authentication Secure your webhook endpoints
API Reference Browse webhook endpoints
Rate Limits Understand webhook rate limits
Examples See webhook implementation examples