API v1 is deprecated and will be discontinued on February 15, 2026. Please migrate to API v2 as soon as possible.
Why migrate to v2?
The v2 API includes numerous enhancements and new features that are not available in v1:
- Performance improvements: Optimized for better performance and scalability
- User-friendly response objects: Improved response structure for better developer experience
- Enhanced security: Improved security measures to protect your data
- New features: Access to new Cal.com features only available in v2
- Better error handling: More descriptive error messages and status codes
Authentication changes
In v1, you authenticated using an API key passed as a query parameter:
curl https://api.cal.com/v1/bookings?apiKey=cal_test_xxxxxx
In v2, you authenticate using an API key in the Authorization header:
curl https://api.cal.com/v2/bookings \
-H "Authorization: Bearer cal_test_xxxxxx" \
-H "cal-api-version: 2024-08-13"
Endpoint-by-endpoint migration guide
Bookings
Create a booking
V1 endpoint:
V1 request body:
{
"eventTypeId": 123,
"start": "2023-05-24T13:00:00.000Z",
"end": "2023-05-24T13:30:00.000Z",
"responses": {
"name": "John Doe",
"email": "[email protected]",
"location": {
"value": "userPhone",
"optionValue": ""
}
},
"timeZone": "Europe/London",
"language": "en",
"metadata": {}
}
V2 endpoint:
V2 request body:
{
"eventTypeId": 123,
"start": "2024-08-13T09:00:00Z",
"attendee": {
"name": "John Doe",
"email": "[email protected]",
"timeZone": "America/New_York",
"language": "en"
},
"location": {
"type": "phone"
},
"metadata": {}
}
Key differences:
responses object replaced with attendee object
end time is no longer required (calculated from event type duration)
location structure changed from {value, optionValue} to {type}
- Must include
cal-api-version: 2024-08-13 header
- Response structure is more detailed with
status and data wrapper
V1 response:
{
"booking": {
"id": 91,
"uid": "bFJeNb2uX8ANpT3JL5EfXw",
"startTime": "2023-05-25T09:30:00.000Z",
"endTime": "2023-05-25T10:30:00.000Z",
"attendees": [...],
"status": "ACCEPTED"
}
}
V2 response:
{
"status": "success",
"data": {
"id": 123,
"uid": "booking_uid_123",
"start": "2024-08-13T15:30:00Z",
"end": "2024-08-13T16:30:00Z",
"duration": 60,
"status": "accepted",
"hosts": [...],
"attendees": [...],
"eventType": {
"id": 1,
"slug": "some-event"
}
}
}
Get all bookings
V1: Not available as a dedicated endpoint
V2 endpoint:
V2 query parameters:
status: Filter by booking status (accepted, pending, cancelled, rejected)
attendeeEmail: Filter by attendee email
eventTypeId: Filter by event type
afterStart, beforeEnd: Filter by date range
take, skip: Pagination
sortStart, sortEnd, sortCreated: Sorting options
V2 response includes pagination:
{
"status": "success",
"data": [...],
"pagination": {
"totalItems": 123,
"currentPage": 2,
"totalPages": 13,
"hasNextPage": true
}
}
Cancel a booking
V1 endpoint:
DELETE /v1/bookings?id={id}&allRemainingBookings=false&cancellationReason=reason
V2 endpoint:
POST /v2/bookings/{uid}/cancel
V2 request body:
{
"cancellationReason": "User requested cancellation"
}
Key differences:
- Changed from DELETE to POST method
- Uses booking
uid in path instead of id query parameter
- Cancellation reason in request body instead of query parameter
Reschedule a booking
V1: Required creating a new booking with rescheduleUid
V2 endpoint:
POST /v2/bookings/{uid}/reschedule
V2 request body:
{
"start": "2024-08-14T10:00:00Z",
"reschedulingReason": "Conflict with another meeting"
}
Key differences:
- Dedicated reschedule endpoint in v2
- Simpler process - just provide new start time
- Automatically handles the relationship between old and new bookings
Event types
Get all event types
V1 endpoint:
V2 endpoint:
Key differences:
- V2 response includes more detailed information about each event type
- V2 includes pagination support
- V2 response wrapped in
{status, data} structure
Create an event type
V1 endpoint:
V1 request body:
{
"title": "30 Min Meeting",
"slug": "30min",
"length": 30,
"locations": [{"type": "integrations:zoom"}]
}
V2 endpoint:
V2 request body:
{
"title": "30 Min Meeting",
"slug": "30min",
"lengthInMinutes": 30,
"locations": [{"type": "zoom"}]
}
Key differences:
length renamed to lengthInMinutes for clarity
- Location types simplified (no
integrations: prefix)
- More configuration options available in v2
Update an event type
V1 endpoint:
PATCH /v1/event-types/{id}
V2 endpoint:
PATCH /v2/event-types/{id}
Key differences:
- Same HTTP method and path structure
- Request/response body structure differences match create endpoint
- V2 provides more granular control over event type settings
Schedules
Get all schedules
V1 endpoint:
V2 endpoint:
Key differences:
- V2 includes default schedule indicator
- V2 response includes more detailed availability information
- V2 supports filtering and pagination
Create a schedule
V1 endpoint:
V1 request body:
{
"name": "Working Hours",
"timeZone": "America/New_York",
"availability": [...]
}
V2 endpoint:
V2 request body:
{
"name": "Working Hours",
"timeZone": "America/New_York",
"isDefault": false,
"schedule": [...]
}
Key differences:
availability renamed to schedule in v2
isDefault flag added to set default schedule
- More flexible schedule configuration options
Webhooks
Get all webhooks
V1 endpoint:
V2 endpoint:
Create a webhook
V1 endpoint:
V1 request body:
{
"subscriberUrl": "https://example.com/webhook",
"eventTriggers": ["BOOKING_CREATED"],
"active": true
}
V2 endpoint:
V2 request body:
{
"payloadTemplate": null,
"triggers": ["BOOKING_CREATED"],
"subscriberUrl": "https://example.com/webhook",
"active": true
}
Key differences:
eventTriggers renamed to triggers
- Added
payloadTemplate for custom webhook payloads
- More webhook event types available in v2
Slots
Get available slots
V1 endpoint:
GET /v1/slots/available?eventTypeId=123&startTime=2024-01-01&endTime=2024-01-31
V2 endpoint:
GET /v2/slots/available?eventTypeId=123&startTime=2024-01-01T00:00:00Z&endTime=2024-01-31T23:59:59Z
Key differences:
- V2 requires full ISO 8601 timestamps
- V2 response includes more metadata about slot availability
- V2 supports additional filtering options (username, teamSlug, etc.)
Teams
Get all teams
V1 endpoint:
V2 endpoint:
Key differences:
- V2 includes organization context if team is part of an org
- V2 response includes more team metadata
- V2 supports pagination
Users
Get user profile
V1 endpoint:
V2 endpoint:
Key differences:
- V2 uses
/me endpoint for current user
- V2 returns more detailed profile information
- V2 includes organization and team memberships
Response structure changes
{
"status": "success",
"data": {...}
}
All v2 responses follow this consistent structure with:
status: Either “success” or “error”
data: The actual response data
error: Error details (only present when status is “error”)
Error handling
V1 errors
{
"message": "Event type not found"
}
V2 errors
{
"status": "error",
"error": {
"code": "NOT_FOUND",
"message": "Event type not found"
}
}
V2 provides more structured error responses with error codes for better error handling.
Migration checklist
Need help?
If you have questions or need assistance with migrating to v2, please contact our support team.