|
| 1 | +--- |
| 2 | +title: Migrating from V1 to V2 |
| 3 | +description: A comprehensive guide to help you migrate from Cal.com API V1 to V2 |
| 4 | +--- |
| 5 | + |
| 6 | +<Warning> |
| 7 | +**API v1 is deprecated and will be discontinued on February 15, 2026.** Please migrate to API v2 as soon as possible. |
| 8 | +</Warning> |
| 9 | + |
| 10 | +This guide will help you migrate your integration from Cal.com API V1 to V2. The V2 API offers improved performance, enhanced security, better response objects, and new features that make it easier to build powerful integrations. |
| 11 | + |
| 12 | +## Why migrate to V2? |
| 13 | + |
| 14 | +- **Better performance**: Optimized for speed and scalability |
| 15 | +- **Enhanced security**: Improved authentication methods and security measures |
| 16 | +- **User-friendly responses**: Cleaner, more consistent response objects |
| 17 | +- **New features**: Access to platform features, organization management, and more |
| 18 | + |
| 19 | +## Authentication changes |
| 20 | + |
| 21 | +### V1 authentication |
| 22 | +In V1, you authenticated using an API key in the query string: |
| 23 | + |
| 24 | +```bash |
| 25 | +curl https://api.cal.com/v1/event-types?apiKey=cal_test_xxxxxx |
| 26 | +``` |
| 27 | + |
| 28 | +### V2 authentication |
| 29 | +In V2, authentication uses header-based API keys for improved security: |
| 30 | + |
| 31 | +```bash |
| 32 | +curl https://api.cal.com/v2/event-types \ |
| 33 | + -H "Authorization: Bearer cal_live_xxxxxx" |
| 34 | +``` |
| 35 | + |
| 36 | +## Base URL changes |
| 37 | + |
| 38 | +| Version | Base URL | |
| 39 | +|---------|----------| |
| 40 | +| V1 | `https://api.cal.com/v1` | |
| 41 | +| V2 | `https://api.cal.com/v2` | |
| 42 | + |
| 43 | +## Endpoint mapping |
| 44 | + |
| 45 | +### Bookings |
| 46 | + |
| 47 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 48 | +|-------------|-------------|---------| |
| 49 | +| `POST /bookings` | `POST /v2/bookings` | Enhanced response object with more booking details | |
| 50 | +| `GET /bookings/{id}` | `GET /v2/bookings/{uid}` | Returns richer booking information | |
| 51 | +| `DELETE /bookings/{id}` | `POST /v2/bookings/{uid}/cancel` | Now uses POST with cancellation reason support | |
| 52 | +| `PATCH /bookings/{id}` | `POST /v2/bookings/{uid}/reschedule` | Rescheduling is now a dedicated endpoint | |
| 53 | + |
| 54 | +**V1 example:** |
| 55 | +```bash |
| 56 | +DELETE /v1/bookings/123?apiKey=cal_test_xxx |
| 57 | +``` |
| 58 | + |
| 59 | +**V2 example:** |
| 60 | +```bash |
| 61 | +POST /v2/bookings/cal_abc123/cancel |
| 62 | +Authorization: Bearer cal_live_xxx |
| 63 | +Content-Type: application/json |
| 64 | + |
| 65 | +{ |
| 66 | + "cancellationReason": "Schedule conflict" |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +### Event types |
| 71 | + |
| 72 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 73 | +|-------------|-------------|---------| |
| 74 | +| `GET /event-types` | `GET /v2/event-types` | Improved filtering and pagination | |
| 75 | +| `POST /event-types` | `POST /v2/event-types` | Enhanced configuration options | |
| 76 | +| `GET /event-types/{id}` | `GET /v2/event-types/{id}` | More detailed response | |
| 77 | +| `DELETE /event-types/{id}` | `DELETE /v2/event-types/{id}` | Same functionality | |
| 78 | +| `PATCH /event-types/{id}` | `PATCH /v2/event-types/{id}` | More update options available | |
| 79 | + |
| 80 | +### Schedules |
| 81 | + |
| 82 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 83 | +|-------------|-------------|---------| |
| 84 | +| `GET /schedules` | `GET /v2/schedules` | Better structured response | |
| 85 | +| `POST /schedules` | `POST /v2/schedules` | Simplified schedule creation | |
| 86 | +| `GET /schedules/{id}` | `GET /v2/schedules/{id}` | Enhanced availability details | |
| 87 | +| `DELETE /schedules/{id}` | `DELETE /v2/schedules/{id}` | Same functionality | |
| 88 | +| `PATCH /schedules/{id}` | `PATCH /v2/schedules/{id}` | More flexible updates | |
| 89 | + |
| 90 | +### Users |
| 91 | + |
| 92 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 93 | +|-------------|-------------|---------| |
| 94 | +| `GET /users` | `GET /v2/me` | Now returns authenticated user profile | |
| 95 | +| `GET /users/{id}` | `GET /v2/me` | User-specific endpoint for own profile | |
| 96 | +| `PATCH /users/{id}` | `PATCH /v2/me` | Update your own profile | |
| 97 | + |
| 98 | +### Teams |
| 99 | + |
| 100 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 101 | +|-------------|-------------|---------| |
| 102 | +| `GET /teams` | `GET /v2/teams` | Enhanced team information | |
| 103 | +| `POST /teams` | `POST /v2/teams` | More configuration options | |
| 104 | +| `GET /teams/{id}` | `GET /v2/teams/{id}` | Richer team details | |
| 105 | +| `DELETE /teams/{id}` | `DELETE /v2/teams/{id}` | Same functionality | |
| 106 | +| `PATCH /teams/{id}` | `PATCH /v2/teams/{id}` | More update options | |
| 107 | + |
| 108 | +### Webhooks |
| 109 | + |
| 110 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 111 | +|-------------|-------------|---------| |
| 112 | +| `GET /webhooks` | `GET /v2/webhooks` | Better webhook management | |
| 113 | +| `POST /webhooks` | `POST /v2/webhooks` | More event types available | |
| 114 | +| `GET /webhooks/{id}` | `GET /v2/webhooks/{id}` | Enhanced webhook details | |
| 115 | +| `DELETE /webhooks/{id}` | `DELETE /v2/webhooks/{id}` | Same functionality | |
| 116 | +| `PATCH /webhooks/{id}` | `PATCH /v2/webhooks/{id}` | More configuration options | |
| 117 | + |
| 118 | +### Slots |
| 119 | + |
| 120 | +| V1 Endpoint | V2 Endpoint | Changes | |
| 121 | +|-------------|-------------|---------| |
| 122 | +| `GET /slots/available` | `GET /v2/slots/available` | Improved slot calculation and response format | |
| 123 | +| N/A | `POST /v2/slots/reserve` | New: Reserve slots before booking | |
| 124 | +| N/A | `DELETE /v2/slots/reserve/{uid}` | New: Release reserved slots | |
| 125 | + |
| 126 | +## New features in V2 |
| 127 | + |
| 128 | +### Organization management |
| 129 | +V2 introduces comprehensive organization endpoints for enterprise customers: |
| 130 | + |
| 131 | +- `GET /v2/orgs/teams` - Manage organization teams |
| 132 | +- `GET /v2/orgs/users` - Manage organization users |
| 133 | +- `GET /v2/orgs/bookings` - View all organization bookings |
| 134 | +- `GET /v2/orgs/memberships` - Manage team memberships |
| 135 | +- `GET /v2/orgs/roles` - Manage custom roles and permissions |
| 136 | + |
| 137 | +### Platform features |
| 138 | +For platform customers, V2 provides managed user capabilities: |
| 139 | + |
| 140 | +- `POST /v2/platform/managed-users` - Create managed users |
| 141 | +- `GET /v2/platform/managed-users` - List managed users |
| 142 | +- `POST /v2/platform/managed-users/{id}/refresh` - Refresh user tokens |
| 143 | +- `POST /v2/platform/webhooks` - Create platform-level webhooks |
| 144 | + |
| 145 | +### Enhanced booking management |
| 146 | +- `POST /v2/bookings/{uid}/confirm` - Confirm pending bookings |
| 147 | +- `POST /v2/bookings/{uid}/decline` - Decline booking requests |
| 148 | +- `POST /v2/bookings/{uid}/mark-absent` - Mark no-shows |
| 149 | +- `POST /v2/bookings/{uid}/reassign` - Reassign bookings to different hosts |
| 150 | +- `POST /v2/bookings/{uid}/guests` - Add guests to existing bookings |
| 151 | + |
| 152 | +### Calendar integrations |
| 153 | +- `GET /v2/calendars` - List connected calendars |
| 154 | +- `GET /v2/calendars/busy-times` - Check availability across calendars |
| 155 | +- `POST /v2/calendars/connect` - Connect calendar providers |
| 156 | +- `POST /v2/calendars/disconnect` - Disconnect calendars |
| 157 | + |
| 158 | +### Conferencing apps |
| 159 | +- `GET /v2/conferencing` - List conferencing apps |
| 160 | +- `POST /v2/conferencing/connect` - Connect conferencing providers |
| 161 | +- `POST /v2/conferencing/set-default` - Set default conferencing app |
| 162 | + |
| 163 | +## Response format changes |
| 164 | + |
| 165 | +### V1 response structure |
| 166 | +```json |
| 167 | +{ |
| 168 | + "booking": { |
| 169 | + "id": 123, |
| 170 | + "title": "Meeting", |
| 171 | + "startTime": "2024-01-15T10:00:00Z" |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +### V2 response structure |
| 177 | +```json |
| 178 | +{ |
| 179 | + "status": "success", |
| 180 | + "data": { |
| 181 | + "id": 123, |
| 182 | + "uid": "cal_abc123xyz", |
| 183 | + "title": "Meeting", |
| 184 | + "startTime": "2024-01-15T10:00:00.000Z", |
| 185 | + "endTime": "2024-01-15T11:00:00.000Z", |
| 186 | + "status": "accepted", |
| 187 | + "attendees": [...], |
| 188 | + "metadata": {...} |
| 189 | + } |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +Key improvements: |
| 194 | +- Consistent `status` and `data` wrapper |
| 195 | +- More detailed timestamps with milliseconds |
| 196 | +- Additional metadata and context |
| 197 | +- Better error messages with specific error codes |
| 198 | + |
| 199 | +## Error handling |
| 200 | + |
| 201 | +### V1 errors |
| 202 | +```json |
| 203 | +{ |
| 204 | + "message": "Event type not found" |
| 205 | +} |
| 206 | +``` |
| 207 | + |
| 208 | +### V2 errors |
| 209 | +```json |
| 210 | +{ |
| 211 | + "status": "error", |
| 212 | + "error": { |
| 213 | + "code": "NOT_FOUND", |
| 214 | + "message": "Event type not found", |
| 215 | + "details": { |
| 216 | + "eventTypeId": 123 |
| 217 | + } |
| 218 | + } |
| 219 | +} |
| 220 | +``` |
| 221 | + |
| 222 | +V2 provides: |
| 223 | +- Structured error codes for programmatic handling |
| 224 | +- More descriptive error messages |
| 225 | +- Additional context in error details |
| 226 | +- Consistent error format across all endpoints |
| 227 | + |
| 228 | +## Rate limits |
| 229 | + |
| 230 | +| Authentication Method | V1 Rate Limit | V2 Rate Limit | |
| 231 | +|----------------------|---------------|---------------| |
| 232 | +| API Key | 120 req/min | 120 req/min | |
| 233 | + |
| 234 | +## Migration checklist |
| 235 | + |
| 236 | +<Steps> |
| 237 | + <Step title="Update authentication"> |
| 238 | + Move API keys from query parameters to Authorization headers |
| 239 | + </Step> |
| 240 | + |
| 241 | + <Step title="Update base URLs"> |
| 242 | + Change all API calls from `/v1/` to `/v2/` |
| 243 | + </Step> |
| 244 | + |
| 245 | + <Step title="Update endpoint paths"> |
| 246 | + Review the endpoint mapping table and update your API calls |
| 247 | + </Step> |
| 248 | + |
| 249 | + <Step title="Update request/response handling"> |
| 250 | + Adapt your code to handle the new response structure with `status` and `data` fields |
| 251 | + </Step> |
| 252 | + |
| 253 | + <Step title="Update error handling"> |
| 254 | + Implement handling for the new structured error format |
| 255 | + </Step> |
| 256 | + |
| 257 | + <Step title="Test thoroughly"> |
| 258 | + Test all API integrations in a development environment before deploying to production |
| 259 | + </Step> |
| 260 | + |
| 261 | + <Step title="Monitor and optimize"> |
| 262 | + Take advantage of new features to optimize your integration |
| 263 | + </Step> |
| 264 | +</Steps> |
| 265 | + |
| 266 | +## Code examples |
| 267 | + |
| 268 | +### Creating a booking |
| 269 | + |
| 270 | +**V1:** |
| 271 | +```javascript |
| 272 | +const response = await fetch( |
| 273 | + 'https://api.cal.com/v1/bookings?apiKey=cal_test_xxx', |
| 274 | + { |
| 275 | + method: 'POST', |
| 276 | + headers: { 'Content-Type': 'application/json' }, |
| 277 | + body: JSON.stringify({ |
| 278 | + eventTypeId: 123, |
| 279 | + start: '2024-01-15T10:00:00Z', |
| 280 | + responses: { |
| 281 | + name: 'John Doe', |
| 282 | + email: 'john@example.com' |
| 283 | + } |
| 284 | + }) |
| 285 | + } |
| 286 | +); |
| 287 | +``` |
| 288 | + |
| 289 | +**V2:** |
| 290 | +```javascript |
| 291 | +const response = await fetch( |
| 292 | + 'https://api.cal.com/v2/bookings', |
| 293 | + { |
| 294 | + method: 'POST', |
| 295 | + headers: { |
| 296 | + 'Authorization': 'Bearer cal_live_xxx', |
| 297 | + 'Content-Type': 'application/json' |
| 298 | + }, |
| 299 | + body: JSON.stringify({ |
| 300 | + eventTypeId: 123, |
| 301 | + start: '2024-01-15T10:00:00.000Z', |
| 302 | + attendee: { |
| 303 | + name: 'John Doe', |
| 304 | + email: 'john@example.com', |
| 305 | + timeZone: 'America/New_York' |
| 306 | + } |
| 307 | + }) |
| 308 | + } |
| 309 | +); |
| 310 | + |
| 311 | +const data = await response.json(); |
| 312 | +if (data.status === 'success') { |
| 313 | + console.log('Booking created:', data.data); |
| 314 | +} |
| 315 | +``` |
| 316 | + |
| 317 | +### Fetching event types |
| 318 | + |
| 319 | +**V1:** |
| 320 | +```python |
| 321 | +import requests |
| 322 | + |
| 323 | +response = requests.get( |
| 324 | + 'https://api.cal.com/v1/event-types', |
| 325 | + params={'apiKey': 'cal_test_xxx'} |
| 326 | +) |
| 327 | +event_types = response.json()['event_types'] |
| 328 | +``` |
| 329 | + |
| 330 | +**V2:** |
| 331 | +```python |
| 332 | +import requests |
| 333 | + |
| 334 | +response = requests.get( |
| 335 | + 'https://api.cal.com/v2/event-types', |
| 336 | + headers={'Authorization': 'Bearer cal_live_xxx'} |
| 337 | +) |
| 338 | + |
| 339 | +data = response.json() |
| 340 | +if data['status'] == 'success': |
| 341 | + event_types = data['data'] |
| 342 | +``` |
| 343 | + |
| 344 | +## Getting help |
| 345 | + |
| 346 | +If you encounter issues during migration: |
| 347 | + |
| 348 | +1. Check the [V2 API Reference](/docs/api-reference/v2/introduction) for detailed endpoint documentation |
| 349 | +2. Review the [differences between V1 and V2](/docs/api-reference/v2/v1-v2-differences) |
| 350 | +3. Contact [Cal.com support](https://go.cal.com/support) for migration assistance |
| 351 | + |
| 352 | +## Timeline |
| 353 | + |
| 354 | +- **Now**: V2 is available and recommended for all new integrations |
| 355 | +- **February 15, 2026**: V1 will be discontinued |
| 356 | + |
| 357 | +Start your migration today to ensure a smooth transition and take advantage of V2's enhanced capabilities. |
0 commit comments