Back to skills
SkillHub ClubShip Full StackFull StackBackend

calcom-api

Interact with the Cal.com API v2 to manage scheduling, bookings, event types, availability, and calendars. Use this skill when building integrations that need to create or manage bookings, check availability, configure event types, or sync calendars with Cal.com's scheduling infrastructure.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
40,618
Hot score
99
Updated
March 20, 2026
Overall rating
C4.5
Composite score
4.5
Best-practice grade
C64.8

Install command

npx @skill-hub/cli install calcom-cal-com-calcom-api

Repository

calcom/cal.com

Skill path: agents/skills/calcom-api

Interact with the Cal.com API v2 to manage scheduling, bookings, event types, availability, and calendars. Use this skill when building integrations that need to create or manage bookings, check availability, configure event types, or sync calendars with Cal.com's scheduling infrastructure.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Backend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: calcom.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install calcom-api into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/calcom/cal.com before adding calcom-api to shared team environments
  • Use calcom-api for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: calcom-api
description: Interact with the Cal.com API v2 to manage scheduling, bookings, event types, availability, and calendars. Use this skill when building integrations that need to create or manage bookings, check availability, configure event types, or sync calendars with Cal.com's scheduling infrastructure.
env:
  CAL_API_KEY:
    description: "Cal.com API key (prefixed with cal_live_ or cal_test_). Required for all API requests."
    required: true
  CAL_CLIENT_ID:
    description: "OAuth client ID for platform integrations managing users on behalf of others. Sent as x-cal-client-id header."
    required: false
  CAL_SECRET_KEY:
    description: "OAuth client secret for platform integrations. Sent as x-cal-secret-key header."
    required: false
  CAL_WEBHOOK_SECRET:
    description: "Secret used to verify webhook payload signatures via X-Cal-Signature-256 header."
    required: false
---

# Cal.com API v2

This skill provides guidance for AI agents to interact with the Cal.com API v2, enabling scheduling automation, booking management, and calendar integrations.

## Base URL

All API requests should be made to:
```
https://api.cal.com/v2
```

## Required Credentials

| Environment Variable | Required | Description |
|---------------------|----------|-------------|
| `CAL_API_KEY` | Yes | Cal.com API key (prefixed with `cal_live_` or `cal_test_`). Used as Bearer token for all API requests. Generate from Settings > Developer > API Keys. |
| `CAL_CLIENT_ID` | No | OAuth client ID for platform integrations that manage users on behalf of others. Sent as `x-cal-client-id` header. |
| `CAL_SECRET_KEY` | No | OAuth client secret for platform integrations. Sent as `x-cal-secret-key` header. |
| `CAL_WEBHOOK_SECRET` | No | Secret for verifying webhook payload signatures via the `X-Cal-Signature-256` header. |

## Authentication

All API requests require authentication via Bearer token:

```
Authorization: Bearer cal_<your_api_key>
```

For detailed authentication methods including OAuth/Platform authentication, see `references/authentication.md`.

## Core Concepts

**Event Types** define bookable meeting configurations (duration, location, availability rules). Each event type has a unique slug used in booking URLs.

**Bookings** are confirmed appointments created when someone books an event type. Each booking has a unique UID for identification.

**Schedules** define when a user is available for bookings. Users can have multiple schedules with different working hours.

**Slots** represent available time windows that can be booked based on event type configuration and user availability.

## Reference Documentation

This skill includes detailed API reference documentation for each domain:

| Reference | Description |
|-----------|-------------|
| `references/authentication.md` | API key and OAuth authentication, rate limiting, security best practices |
| `references/bookings.md` | Create, list, cancel, reschedule bookings |
| `references/event-types.md` | Configure bookable meeting types |
| `references/schedules.md` | Manage user availability schedules |
| `references/slots-availability.md` | Query available time slots |
| `references/calendars.md` | Calendar connections and busy times |
| `references/webhooks.md` | Real-time event notifications |

## Quick Start

### 1. Check Available Slots

Before creating a booking, check available time slots:

```http
GET /v2/slots?startTime=2024-01-15T00:00:00Z&endTime=2024-01-22T00:00:00Z&eventTypeId=123
```

See `references/slots-availability.md` for full details.

### 2. Create a Booking

```http
POST /v2/bookings
Content-Type: application/json

{
  "start": "2024-01-15T10:00:00Z",
  "eventTypeId": 123,
  "attendee": {
    "name": "John Doe",
    "email": "[email protected]",
    "timeZone": "America/New_York"
  }
}
```

See `references/bookings.md` for all booking operations.

### 3. Set Up Webhooks

Receive real-time notifications for booking events:

```http
POST /v2/webhooks
Content-Type: application/json

{
  "subscriberUrl": "https://your-app.com/webhook",
  "triggers": ["BOOKING_CREATED", "BOOKING_CANCELLED"]
}
```

See `references/webhooks.md` for available triggers and payload formats.

## Common Workflows

**Book a meeting**: Check slots -> Create booking -> Store booking UID

**Reschedule**: Get new slots -> POST /v2/bookings/{uid}/reschedule

**Cancel**: POST /v2/bookings/{uid}/cancel with optional reason

## Best Practices

1. Always check slot availability before creating bookings
2. Store booking UIDs for future operations (cancel, reschedule)
3. Use ISO 8601 format for all timestamps
4. Implement webhook handlers for real-time updates
5. Handle rate limiting with exponential backoff

## Additional Resources

- [Full API Reference](https://cal.com/docs/api-reference/v2)
- [OpenAPI Specification](https://api.cal.com/v2/docs)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/authentication.md

```markdown
# Authentication API Reference

Detailed documentation for authentication methods in the Cal.com API v2.

## Authentication Methods

Cal.com API v2 supports two authentication methods:

1. **API Key Authentication** - For direct API access
2. **OAuth/Platform Authentication** - For platform integrations managing users on behalf of others

## API Key Authentication

The primary authentication method for most API consumers.

### Obtaining an API Key

1. Log in to your Cal.com account
2. Navigate to Settings > Developer > API Keys
3. Click "Create new API key"
4. Copy and securely store the generated key

### Using API Keys

Include the API key in the `Authorization` header with the `Bearer` prefix:

```http
GET /v2/bookings
Authorization: Bearer cal_live_abc123xyz...
```

### API Key Format

All Cal.com API keys are prefixed with `cal_`:
- `cal_live_...` - Production API keys
- `cal_test_...` - Test/sandbox API keys (if available)

### Example Request

```bash
curl -X GET "https://api.cal.com/v2/bookings" \
  -H "Authorization: Bearer cal_live_abc123xyz789" \
  -H "Content-Type: application/json"
```

## Refresh API Key

Generate a new API key and invalidate the current one:

```http
POST /v2/api-keys/refresh
Authorization: Bearer cal_live_current_key
Content-Type: application/json

{
  "expiresAt": "2025-12-31T23:59:59Z"
}
```

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| expiresAt | string | No | ISO 8601 expiration date for the new key |

### Response

```json
{
  "status": "success",
  "data": {
    "apiKey": "cal_live_new_key_xyz..."
  }
}
```

## Platform Authentication (OAuth)

For platform customers building integrations that manage multiple users.

### Headers for Platform Authentication

Platform customers use additional headers alongside or instead of the Bearer token:

| Header | Description |
|--------|-------------|
| `x-cal-client-id` | OAuth client ID |
| `x-cal-secret-key` | OAuth client secret key |
| `Authorization` | Bearer token (managed user access token) |

### Example Platform Request

```bash
curl -X GET "https://api.cal.com/v2/bookings" \
  -H "x-cal-client-id: your_client_id" \
  -H "x-cal-secret-key: your_secret_key" \
  -H "Authorization: Bearer managed_user_access_token" \
  -H "Content-Type: application/json"
```

### When to Use Each Header

**For endpoints acting on behalf of a managed user:**
```http
GET /v2/bookings
x-cal-client-id: your_client_id
x-cal-secret-key: your_secret_key
Authorization: Bearer managed_user_access_token
```

**For platform-level operations (managing OAuth clients):**
```http
GET /v2/oauth-clients
Authorization: Bearer cal_live_platform_admin_key
```

## API Versioning

Many endpoints require a version header:

```http
cal-api-version: 2024-08-13
```

### Example with Version Header

```bash
curl -X POST "https://api.cal.com/v2/bookings" \
  -H "Authorization: Bearer cal_live_abc123" \
  -H "cal-api-version: 2024-08-13" \
  -H "Content-Type: application/json" \
  -d '{"start": "2024-01-15T10:00:00Z", "eventTypeId": 123, ...}'
```

## Authentication Errors

### 401 Unauthorized

Returned when authentication fails:

```json
{
  "status": "error",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid API key"
  }
}
```

Common causes:
- Missing `Authorization` header
- Invalid or expired API key
- API key without `cal_` prefix
- Incorrect Bearer token format

### 403 Forbidden

Returned when authenticated but lacking permissions:

```json
{
  "status": "error",
  "error": {
    "code": "FORBIDDEN",
    "message": "You do not have permission to access this resource"
  }
}
```

Common causes:
- Accessing another user's resources
- Missing required scopes for platform tokens
- Organization/team permission restrictions

## Security Best Practices

1. **Never expose API keys in client-side code**: API keys should only be used in server-side applications

2. **Use environment variables**: Store API keys in environment variables, not in code
   ```bash
   export CAL_API_KEY="cal_live_abc123..."
   ```

3. **Rotate keys regularly**: Use the refresh endpoint to rotate keys periodically

4. **Use minimal permissions**: Request only the scopes/permissions your application needs

5. **Monitor API usage**: Check your Cal.com dashboard for unusual activity

6. **Secure transmission**: Always use HTTPS for API requests

7. **Handle keys securely in logs**: Never log full API keys - redact sensitive portions

## Rate Limiting

API requests are rate limited. When exceeded, you'll receive:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 60
```

```json
{
  "status": "error",
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests. Please retry after 60 seconds."
  }
}
```

### Rate Limit Headers

| Header | Description |
|--------|-------------|
| `X-RateLimit-Limit` | Maximum requests per window |
| `X-RateLimit-Remaining` | Remaining requests in current window |
| `X-RateLimit-Reset` | Unix timestamp when the window resets |
| `Retry-After` | Seconds to wait before retrying (on 429) |

## Testing Authentication

Verify your API key is working:

```bash
curl -X GET "https://api.cal.com/v2/me" \
  -H "Authorization: Bearer cal_live_your_api_key" \
  -H "Content-Type: application/json"
```

### Expected Response

```json
{
  "status": "success",
  "data": {
    "id": 12345,
    "email": "[email protected]",
    "username": "johndoe",
    "name": "John Doe",
    "timeZone": "America/New_York"
  }
}
```

## Common Authentication Patterns

### Server-Side Integration

```javascript
const CAL_API_KEY = process.env.CAL_API_KEY;

async function getBookings() {
  const response = await fetch('https://api.cal.com/v2/bookings', {
    headers: {
      'Authorization': `Bearer ${CAL_API_KEY}`,
      'Content-Type': 'application/json',
      'cal-api-version': '2024-08-13'
    }
  });
  
  if (!response.ok) {
    if (response.status === 401) {
      throw new Error('Invalid API key');
    }
    throw new Error(`API error: ${response.status}`);
  }
  
  return response.json();
}
```

### Handling Token Refresh

```javascript
async function makeAuthenticatedRequest(url, options = {}) {
  let response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${apiKey}`
    }
  });
  
  if (response.status === 401) {
    // Refresh the API key
    const refreshResponse = await fetch('https://api.cal.com/v2/api-keys/refresh', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({})
    });
    
    if (refreshResponse.ok) {
      const { data } = await refreshResponse.json();
      apiKey = data.apiKey;
      // Retry original request with new key
      response = await fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          'Authorization': `Bearer ${apiKey}`
        }
      });
    }
  }
  
  return response;
}
```

## Error Handling

The API returns standard HTTP status codes:

| Status Code | Description |
|-------------|-------------|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request (invalid parameters) |
| 401 | Unauthorized (invalid or missing API key) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found |
| 422 | Unprocessable Entity (validation error) |
| 429 | Too Many Requests (rate limited) |
| 500 | Internal Server Error |

### Error Response Format

```json
{
  "status": "error",
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message"
  }
}
```

### Common Error Codes

| Code | Description |
|------|-------------|
| UNAUTHORIZED | Invalid or missing authentication |
| FORBIDDEN | Insufficient permissions |
| NOT_FOUND | Resource not found |
| VALIDATION_ERROR | Invalid request parameters |
| RATE_LIMITED | Too many requests |

## Pagination

List endpoints support pagination via `take` and `skip` parameters:

| Parameter | Type | Default | Max | Description |
|-----------|------|---------|-----|-------------|
| take | number | 10 | 250 | Number of items to return |
| skip | number | 0 | - | Number of items to skip |

### Example

```http
GET /v2/bookings?take=20&skip=40
```

This returns items 41-60 (skipping the first 40, taking 20).

### Pagination Response

Some endpoints include pagination metadata:

```json
{
  "status": "success",
  "data": [...],
  "pagination": {
    "total": 150,
    "take": 20,
    "skip": 40
  }
}
```

## Troubleshooting

### "Invalid API key" Error

1. Verify the key starts with `cal_`
2. Check for extra whitespace or characters
3. Ensure the key hasn't been revoked or expired
4. Confirm you're using the correct environment (production vs test)

### "Missing Authorization header" Error

1. Ensure the header name is exactly `Authorization`
2. Include the `Bearer ` prefix (with space)
3. Check for typos in the header name

### Platform Authentication Issues

1. Verify both `x-cal-client-id` and `x-cal-secret-key` are provided
2. Ensure the managed user access token is valid
3. Check that the OAuth client has the required permissions

```

### references/bookings.md

```markdown
# Bookings API Reference

Detailed documentation for booking-related endpoints in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/bookings | List bookings |
| POST | /v2/bookings | Create a booking |
| GET | /v2/bookings/{bookingUid} | Get a booking |
| POST | /v2/bookings/{bookingUid}/cancel | Cancel a booking |
| POST | /v2/bookings/{bookingUid}/reschedule | Reschedule a booking |
| POST | /v2/bookings/{bookingUid}/confirm | Confirm a pending booking |
| POST | /v2/bookings/{bookingUid}/decline | Decline a booking |
| PATCH | /v2/bookings/{bookingUid}/location | Update booking location |
| POST | /v2/bookings/{bookingUid}/mark-absent | Mark attendee as no-show |
| POST | /v2/bookings/{bookingUid}/reassign | Reassign booking to another host |
| GET | /v2/bookings/{bookingUid}/references | Get booking references |

## List Bookings

```http
GET /v2/bookings
```

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| status | string | No | Filter by status: `upcoming`, `recurring`, `past`, `cancelled`, `unconfirmed` |
| attendeeEmail | string | No | Filter by attendee email |
| attendeeName | string | No | Filter by attendee name |
| eventTypeId | number | No | Filter by event type ID |
| eventTypeIds | string | No | Comma-separated event type IDs |
| teamsIds | string | No | Comma-separated team IDs |
| afterStart | string | No | Filter bookings starting after this ISO 8601 date |
| beforeEnd | string | No | Filter bookings ending before this ISO 8601 date |
| sortStart | string | No | Sort by start time: `asc` or `desc` |
| sortEnd | string | No | Sort by end time: `asc` or `desc` |
| sortCreated | string | No | Sort by creation time: `asc` or `desc` |
| take | number | No | Number of results (default: 10, max: 250) |
| skip | number | No | Pagination offset |

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": 12345,
      "uid": "abc123def456",
      "title": "30 Minute Meeting",
      "description": "Discussion about project",
      "start": "2024-01-15T10:00:00.000Z",
      "end": "2024-01-15T10:30:00.000Z",
      "status": "accepted",
      "eventTypeId": 123,
      "attendees": [
        {
          "name": "John Doe",
          "email": "[email protected]",
          "timeZone": "America/New_York"
        }
      ],
      "hosts": [
        {
          "id": 456,
          "name": "Jane Smith",
          "email": "[email protected]"
        }
      ],
      "location": "https://cal.com/video/abc123",
      "meetingUrl": "https://cal.com/video/abc123",
      "metadata": {},
      "createdAt": "2024-01-10T08:00:00.000Z"
    }
  ]
}
```

## Create a Booking

```http
POST /v2/bookings
```

### Request Body

```json
{
  "start": "2024-01-15T10:00:00Z",
  "eventTypeId": 123,
  "attendee": {
    "name": "John Doe",
    "email": "[email protected]",
    "timeZone": "America/New_York",
    "language": "en"
  },
  "guests": ["[email protected]", "[email protected]"],
  "meetingUrl": "https://cal.com/team/meeting",
  "metadata": {
    "customField": "value"
  },
  "bookingFieldsResponses": {
    "notes": "Please prepare the quarterly report"
  }
}
```

### Required Fields

| Field | Type | Description |
|-------|------|-------------|
| start | string | ISO 8601 booking start time |
| eventTypeId | number | ID of the event type to book |
| attendee.name | string | Attendee's full name |
| attendee.email | string | Attendee's email address |
| attendee.timeZone | string | Attendee's timezone (IANA format) |

### Optional Fields

| Field | Type | Description |
|-------|------|-------------|
| attendee.language | string | Attendee's preferred language |
| guests | array | Additional guest email addresses |
| meetingUrl | string | Custom meeting URL |
| metadata | object | Custom metadata |
| bookingFieldsResponses | object | Responses to custom booking fields |

### Response

```json
{
  "status": "success",
  "data": {
    "id": 12345,
    "uid": "abc123def456",
    "title": "30 Minute Meeting",
    "start": "2024-01-15T10:00:00.000Z",
    "end": "2024-01-15T10:30:00.000Z",
    "status": "accepted",
    "eventTypeId": 123,
    "attendees": [...],
    "hosts": [...],
    "location": "https://cal.com/video/abc123"
  }
}
```

## Get a Booking

```http
GET /v2/bookings/{bookingUid}
```

### Path Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| bookingUid | string | Unique booking identifier |

### Response

Returns the full booking object with all details.

## Cancel a Booking

```http
POST /v2/bookings/{bookingUid}/cancel
```

### Request Body

```json
{
  "cancellationReason": "Schedule conflict"
}
```

### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| cancellationReason | string | No | Reason for cancellation |

## Reschedule a Booking

```http
POST /v2/bookings/{bookingUid}/reschedule
```

### Request Body

```json
{
  "start": "2024-01-16T14:00:00Z",
  "reschedulingReason": "Conflict with another meeting"
}
```

### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| start | string | Yes | New booking start time (ISO 8601) |
| reschedulingReason | string | No | Reason for rescheduling |

## Confirm a Booking

For event types that require confirmation:

```http
POST /v2/bookings/{bookingUid}/confirm
```

## Decline a Booking

```http
POST /v2/bookings/{bookingUid}/decline
```

### Request Body

```json
{
  "reason": "Not available at this time"
}
```

## Update Booking Location

```http
PATCH /v2/bookings/{bookingUid}/location
```

### Request Body

```json
{
  "location": "https://zoom.us/j/123456789"
}
```

## Mark Attendee as No-Show

```http
POST /v2/bookings/{bookingUid}/mark-absent
```

### Request Body

```json
{
  "attendeeEmail": "[email protected]",
  "noShow": true
}
```

## Reassign Booking

Reassign a booking to a different host:

```http
POST /v2/bookings/{bookingUid}/reassign
```

Or to a specific user:

```http
POST /v2/bookings/{bookingUid}/reassign/{userId}
```

## Get Booking References

Get external references (calendar events, video meetings) for a booking:

```http
GET /v2/bookings/{bookingUid}/references
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "type": "google_calendar",
      "uid": "calendar-event-id",
      "meetingUrl": "https://meet.google.com/abc-defg-hij"
    }
  ]
}
```

## Booking Statuses

| Status | Description |
|--------|-------------|
| accepted | Booking is confirmed |
| pending | Awaiting confirmation |
| cancelled | Booking was cancelled |
| rejected | Booking was declined |

## Common Use Cases

### Book a Meeting

1. Get available slots: `GET /v2/slots?eventTypeId=123&startTime=...&endTime=...`
2. Create booking: `POST /v2/bookings` with selected slot
3. Store the booking UID for future operations

### Reschedule Flow

1. Get new available slots: `GET /v2/slots?eventTypeId=123&startTime=...&endTime=...`
2. Reschedule: `POST /v2/bookings/{uid}/reschedule` with new start time

### Cancel with Notification

1. Cancel: `POST /v2/bookings/{uid}/cancel` with reason
2. Attendees automatically receive cancellation emails

```

### references/event-types.md

```markdown
# Event Types API Reference

Detailed documentation for event type endpoints in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/event-types | List event types |
| POST | /v2/event-types | Create an event type |
| GET | /v2/event-types/{eventTypeId} | Get an event type |
| PATCH | /v2/event-types/{eventTypeId} | Update an event type |
| DELETE | /v2/event-types/{eventTypeId} | Delete an event type |

## List Event Types

```http
GET /v2/event-types
```

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| take | number | No | Number of results (default: 10, max: 250) |
| skip | number | No | Pagination offset |

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": 123,
      "title": "30 Minute Meeting",
      "slug": "30min",
      "description": "A quick 30 minute call",
      "lengthInMinutes": 30,
      "locations": [
        {
          "type": "integration",
          "integration": "cal-video"
        }
      ],
      "bookingFields": [],
      "disableGuests": false,
      "slotInterval": null,
      "minimumBookingNotice": 120,
      "beforeEventBuffer": 0,
      "afterEventBuffer": 0,
      "schedulingType": null,
      "metadata": {},
      "requiresConfirmation": false,
      "price": 0,
      "currency": "usd",
      "hidden": false
    }
  ]
}
```

## Create an Event Type

```http
POST /v2/event-types
```

### Request Body

```json
{
  "title": "30 Minute Meeting",
  "slug": "30min",
  "description": "A quick 30 minute call to discuss your needs",
  "lengthInMinutes": 30,
  "locations": [
    {
      "type": "integration",
      "integration": "cal-video"
    }
  ],
  "bookingFields": [
    {
      "type": "textarea",
      "name": "notes",
      "label": "Additional Notes",
      "required": false,
      "placeholder": "Any additional information..."
    }
  ],
  "disableGuests": false,
  "slotInterval": 15,
  "minimumBookingNotice": 120,
  "beforeEventBuffer": 5,
  "afterEventBuffer": 5,
  "scheduleId": 1,
  "requiresConfirmation": false,
  "hidden": false
}
```

### Required Fields

| Field | Type | Description |
|-------|------|-------------|
| title | string | Display name of the event type |
| slug | string | URL-friendly identifier |
| lengthInMinutes | number | Duration of the event |

### Optional Fields

| Field | Type | Description |
|-------|------|-------------|
| description | string | Description shown on booking page |
| locations | array | Meeting location options |
| bookingFields | array | Custom form fields |
| disableGuests | boolean | Prevent attendees from adding guests |
| slotInterval | number | Minutes between available slots |
| minimumBookingNotice | number | Minimum minutes before booking |
| beforeEventBuffer | number | Buffer time before event (minutes) |
| afterEventBuffer | number | Buffer time after event (minutes) |
| scheduleId | number | ID of schedule to use |
| requiresConfirmation | boolean | Require host confirmation |
| hidden | boolean | Hide from public profile |

## Location Types

### Cal Video (Built-in)

```json
{
  "type": "integration",
  "integration": "cal-video"
}
```

### Zoom

```json
{
  "type": "integration",
  "integration": "zoom"
}
```

### Google Meet

```json
{
  "type": "integration",
  "integration": "google-meet"
}
```

### Microsoft Teams

```json
{
  "type": "integration",
  "integration": "msteams"
}
```

### In-Person

```json
{
  "type": "address",
  "address": "123 Main St, City, Country"
}
```

### Phone Call (Host Calls)

```json
{
  "type": "userPhone"
}
```

### Phone Call (Attendee Provides)

```json
{
  "type": "attendeePhone"
}
```

### Custom Link

```json
{
  "type": "link",
  "link": "https://custom-meeting.com/room"
}
```

## Booking Fields

Custom form fields for collecting information from attendees.

### Text Field

```json
{
  "type": "text",
  "name": "company",
  "label": "Company Name",
  "required": true,
  "placeholder": "Enter your company name"
}
```

### Textarea

```json
{
  "type": "textarea",
  "name": "notes",
  "label": "Additional Notes",
  "required": false
}
```

### Select (Dropdown)

```json
{
  "type": "select",
  "name": "topic",
  "label": "Meeting Topic",
  "required": true,
  "options": [
    { "value": "sales", "label": "Sales Inquiry" },
    { "value": "support", "label": "Support" },
    { "value": "other", "label": "Other" }
  ]
}
```

### Radio Buttons

```json
{
  "type": "radio",
  "name": "preference",
  "label": "Preferred Contact Method",
  "required": true,
  "options": [
    { "value": "email", "label": "Email" },
    { "value": "phone", "label": "Phone" }
  ]
}
```

### Checkbox

```json
{
  "type": "checkbox",
  "name": "terms",
  "label": "I agree to the terms",
  "required": true
}
```

### Phone Number

```json
{
  "type": "phone",
  "name": "phone",
  "label": "Phone Number",
  "required": false
}
```

## Get an Event Type

```http
GET /v2/event-types/{eventTypeId}
```

### Path Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| eventTypeId | number | Event type ID |

## Update an Event Type

```http
PATCH /v2/event-types/{eventTypeId}
```

### Request Body

Only include fields you want to update:

```json
{
  "title": "Updated Meeting Title",
  "lengthInMinutes": 45,
  "hidden": false
}
```

## Delete an Event Type

```http
DELETE /v2/event-types/{eventTypeId}
```

## Team Event Types

For team event types, use the team-scoped endpoints:

### List Team Event Types

```http
GET /v2/teams/{teamId}/event-types
```

### Create Team Event Type

```http
POST /v2/teams/{teamId}/event-types
```

Additional fields for team event types:

```json
{
  "title": "Team Meeting",
  "slug": "team-meeting",
  "lengthInMinutes": 30,
  "schedulingType": "ROUND_ROBIN",
  "hosts": [
    { "userId": 1, "isFixed": false },
    { "userId": 2, "isFixed": false }
  ]
}
```

### Scheduling Types

| Type | Description |
|------|-------------|
| ROUND_ROBIN | Distributes bookings among team members |
| COLLECTIVE | All team members must attend |
| MANAGED | Parent event type that creates child event types |

## Private Links

Create private booking links that bypass public visibility:

### List Private Links

```http
GET /v2/event-types/{eventTypeId}/private-links
```

### Create Private Link

```http
POST /v2/event-types/{eventTypeId}/private-links
```

## Organization Event Types

For organization-level event type management:

### List Organization Teams

```http
GET /v2/organizations/{orgId}/teams
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": 1,
      "name": "Sales Team",
      "slug": "sales",
      "parentId": null,
      "isOrganization": false
    }
  ]
}
```

### Get Team Event Types (Organization Scope)

```http
GET /v2/organizations/{orgId}/teams/{teamId}/event-types
```

### Create Team Event Type (Organization Scope)

```http
POST /v2/organizations/{orgId}/teams/{teamId}/event-types
```

Team event types support different scheduling modes:

| Mode | Description |
|------|-------------|
| COLLECTIVE | All team members must attend the meeting |
| ROUND_ROBIN | Distributes bookings among team members based on availability and priority |
| MANAGED | Parent event type that creates child event types for team members |

## Event Type Webhooks

Configure webhooks specific to an event type:

### List Event Type Webhooks

```http
GET /v2/event-types/{eventTypeId}/webhooks
```

### Create Event Type Webhook

```http
POST /v2/event-types/{eventTypeId}/webhooks
```

```json
{
  "subscriberUrl": "https://your-app.com/webhook",
  "triggers": ["BOOKING_CREATED"],
  "active": true
}
```

```

### references/schedules.md

```markdown
# Schedules API Reference

Detailed documentation for schedule management endpoints in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/schedules | List all schedules |
| POST | /v2/schedules | Create a schedule |
| GET | /v2/schedules/default | Get default schedule |
| GET | /v2/schedules/{scheduleId} | Get a schedule |
| PATCH | /v2/schedules/{scheduleId} | Update a schedule |
| DELETE | /v2/schedules/{scheduleId} | Delete a schedule |

## Understanding Schedules

Schedules define when a user is available for bookings. Key concepts:

- **Working Hours**: Regular weekly availability (e.g., Mon-Fri 9am-5pm)
- **Date Overrides**: Exceptions to regular hours (e.g., holiday, special hours)
- **Timezone**: The timezone in which availability is defined
- **Default Schedule**: The primary schedule used when no specific schedule is assigned

## List Schedules

```http
GET /v2/schedules
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": 1,
      "name": "Working Hours",
      "isDefault": true,
      "timeZone": "America/New_York",
      "workingHours": [
        {
          "days": [1, 2, 3, 4, 5],
          "startTime": 540,
          "endTime": 1020
        }
      ],
      "availability": [
        {
          "id": 1,
          "days": [1, 2, 3, 4, 5],
          "startTime": "1970-01-01T09:00:00.000Z",
          "endTime": "1970-01-01T17:00:00.000Z"
        }
      ],
      "dateOverrides": [],
      "isManaged": false,
      "readOnly": false,
      "isLastSchedule": false
    }
  ]
}
```

## Create a Schedule

```http
POST /v2/schedules
```

### Request Body

```json
{
  "name": "Working Hours",
  "timeZone": "America/New_York",
  "isDefault": true,
  "availability": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "09:00",
      "endTime": "17:00"
    }
  ],
  "dateOverrides": [
    {
      "date": "2024-12-25",
      "startTime": null,
      "endTime": null
    }
  ]
}
```

### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| name | string | Yes | Schedule name |
| timeZone | string | Yes | IANA timezone identifier |
| isDefault | boolean | No | Set as default schedule |
| availability | array | Yes | Weekly availability rules |
| dateOverrides | array | No | Date-specific overrides |

### Availability Object

| Field | Type | Description |
|-------|------|-------------|
| days | array | Days of week (0=Sunday, 1=Monday, ..., 6=Saturday) |
| startTime | string | Start time in HH:MM format |
| endTime | string | End time in HH:MM format |

### Date Override Object

| Field | Type | Description |
|-------|------|-------------|
| date | string | Date in YYYY-MM-DD format |
| startTime | string/null | Start time (null = unavailable) |
| endTime | string/null | End time (null = unavailable) |

## Get Default Schedule

```http
GET /v2/schedules/default
```

Returns the user's default schedule.

## Get a Schedule

```http
GET /v2/schedules/{scheduleId}
```

### Path Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| scheduleId | number | Schedule ID |

## Update a Schedule

```http
PATCH /v2/schedules/{scheduleId}
```

### Request Body

Only include fields you want to update:

```json
{
  "name": "Updated Schedule Name",
  "availability": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "08:00",
      "endTime": "18:00"
    }
  ]
}
```

## Delete a Schedule

```http
DELETE /v2/schedules/{scheduleId}
```

Note: You cannot delete your last schedule. At least one schedule must exist.

## Common Schedule Patterns

### Standard Business Hours (Mon-Fri 9-5)

```json
{
  "name": "Business Hours",
  "timeZone": "America/New_York",
  "availability": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "09:00",
      "endTime": "17:00"
    }
  ]
}
```

### Split Schedule (Morning and Afternoon)

```json
{
  "name": "Split Hours",
  "timeZone": "America/New_York",
  "availability": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "09:00",
      "endTime": "12:00"
    },
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "14:00",
      "endTime": "18:00"
    }
  ]
}
```

### Different Hours Per Day

```json
{
  "name": "Variable Hours",
  "timeZone": "America/New_York",
  "availability": [
    {
      "days": [1, 3, 5],
      "startTime": "09:00",
      "endTime": "17:00"
    },
    {
      "days": [2, 4],
      "startTime": "10:00",
      "endTime": "19:00"
    }
  ]
}
```

### Weekend Availability

```json
{
  "name": "Weekend Support",
  "timeZone": "America/New_York",
  "availability": [
    {
      "days": [0, 6],
      "startTime": "10:00",
      "endTime": "14:00"
    }
  ]
}
```

### Holiday Override (Unavailable)

```json
{
  "dateOverrides": [
    {
      "date": "2024-12-25",
      "startTime": null,
      "endTime": null
    },
    {
      "date": "2024-01-01",
      "startTime": null,
      "endTime": null
    }
  ]
}
```

### Special Hours Override

```json
{
  "dateOverrides": [
    {
      "date": "2024-12-24",
      "startTime": "09:00",
      "endTime": "12:00"
    }
  ]
}
```

## Organization/Team Schedules

For organization-level schedule management:

### List Organization Schedules

```http
GET /v2/organizations/{orgId}/schedules
```

### List User Schedules in Organization

```http
GET /v2/organizations/{orgId}/users/{userId}/schedules
```

### Create User Schedule in Organization

```http
POST /v2/organizations/{orgId}/users/{userId}/schedules
```

### Team Member Schedules

```http
GET /v2/organizations/{orgId}/teams/{teamId}/users/{userId}/schedules
```

## Working Hours Format

The API returns working hours in two formats:

### Minutes from Midnight

```json
{
  "workingHours": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": 540,
      "endTime": 1020
    }
  ]
}
```

- `540` = 9:00 AM (9 * 60 minutes)
- `1020` = 5:00 PM (17 * 60 minutes)

### ISO Time Format

```json
{
  "availability": [
    {
      "days": [1, 2, 3, 4, 5],
      "startTime": "1970-01-01T09:00:00.000Z",
      "endTime": "1970-01-01T17:00:00.000Z"
    }
  ]
}
```

When creating/updating, use HH:MM format:

```json
{
  "startTime": "09:00",
  "endTime": "17:00"
}
```

## Best Practices

1. **Always specify timezone**: Schedules are timezone-aware
2. **Use date overrides sparingly**: For recurring patterns, create separate schedules
3. **Test availability**: After creating a schedule, verify with the slots endpoint
4. **Consider buffer times**: Set buffers on event types, not schedules

```

### references/slots-availability.md

```markdown
# Slots and Availability API Reference

Detailed documentation for checking availability and managing slots in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/slots | Get available time slots |
| POST | /v2/slots/reservations | Reserve a slot temporarily |
| DELETE | /v2/slots/reservations/{uid} | Release a reserved slot |
| GET | /v2/calendars/busy-times | Get busy times from calendars |

## Get Available Slots

Check available time slots for booking an event type.

```http
GET /v2/slots
```

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| startTime | string | Yes | ISO 8601 start of date range |
| endTime | string | Yes | ISO 8601 end of date range |
| eventTypeId | number | Conditional | Event type ID (required if no slug) |
| eventTypeSlug | string | Conditional | Event type slug (required if no ID) |
| usernameList | string | Conditional | Comma-separated usernames for team events |
| timeZone | string | No | Timezone for slot display (default: UTC) |
| duration | number | No | Override event duration in minutes |
| rescheduleUid | string | No | Booking UID if rescheduling |

### Example Request

```http
GET /v2/slots?startTime=2024-01-15T00:00:00Z&endTime=2024-01-22T00:00:00Z&eventTypeId=123&timeZone=America/New_York
```

### Response

```json
{
  "status": "success",
  "data": {
    "slots": {
      "2024-01-15": [
        {
          "time": "2024-01-15T09:00:00.000Z"
        },
        {
          "time": "2024-01-15T09:30:00.000Z"
        },
        {
          "time": "2024-01-15T10:00:00.000Z"
        }
      ],
      "2024-01-16": [
        {
          "time": "2024-01-16T09:00:00.000Z"
        }
      ]
    }
  }
}
```

### Response with Attendees (Seated Events)

For event types with `seatsPerTimeSlot` configured:

```json
{
  "status": "success",
  "data": {
    "slots": {
      "2024-01-15": [
        {
          "time": "2024-01-15T09:00:00.000Z",
          "attendees": 3,
          "seatsAvailable": 7
        }
      ]
    }
  }
}
```

## Reserve a Slot

Temporarily reserve a slot while the user completes the booking form. This prevents double-booking.

```http
POST /v2/slots/reservations
```

### Request Body

```json
{
  "eventTypeId": 123,
  "slotUtcStartDate": "2024-01-15T09:00:00.000Z",
  "slotUtcEndDate": "2024-01-15T09:30:00.000Z"
}
```

### Response

```json
{
  "status": "success",
  "data": {
    "uid": "reservation-uid-123",
    "eventTypeId": 123,
    "slotUtcStartDate": "2024-01-15T09:00:00.000Z",
    "slotUtcEndDate": "2024-01-15T09:30:00.000Z",
    "expiresAt": "2024-01-15T08:10:00.000Z"
  }
}
```

Reservations automatically expire after a short period (typically 10 minutes).

## Release a Reserved Slot

Release a slot reservation if the user abandons the booking flow.

```http
DELETE /v2/slots/reservations/{uid}
```

### Path Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| uid | string | Reservation UID |

## Get Busy Times

Check busy times from connected calendars.

```http
GET /v2/calendars/busy-times
```

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| startTime | string | Yes | ISO 8601 start of date range |
| endTime | string | Yes | ISO 8601 end of date range |
| loggedInUsersTz | string | No | User's timezone |
| credentialId | number | No | Specific calendar credential ID |

### Response

```json
{
  "status": "success",
  "data": [
    {
      "start": "2024-01-15T10:00:00.000Z",
      "end": "2024-01-15T11:00:00.000Z",
      "title": "Existing Meeting",
      "source": "google_calendar"
    }
  ]
}
```

## Routing Form Slots

For routing forms that direct to different event types:

```http
POST /v2/routing-forms/{routingFormId}/calculate-slots
```

### Request Body

```json
{
  "startTime": "2024-01-15T00:00:00Z",
  "endTime": "2024-01-22T00:00:00Z",
  "timeZone": "America/New_York",
  "responses": {
    "field1": "value1",
    "field2": "value2"
  }
}
```

## Understanding Slot Availability

Slots are calculated based on:

1. **User's Schedule**: Working hours defined in their schedule
2. **Existing Bookings**: Times already booked
3. **Calendar Busy Times**: Events from connected calendars
4. **Buffer Times**: Before/after event buffers
5. **Minimum Notice**: Minimum booking notice period
6. **Booking Limits**: Daily/weekly/monthly booking limits

## Best Practices

### Efficient Slot Fetching

1. **Limit date range**: Request only the dates you need to display
2. **Cache results**: Slots don't change frequently, cache for short periods
3. **Use timezone parameter**: Request slots in user's timezone to avoid conversion

### Preventing Double Bookings

1. **Reserve slots**: Use slot reservations for multi-step booking flows
2. **Handle expiration**: Reservations expire - handle gracefully
3. **Verify before booking**: Always verify slot is still available before creating booking

### Example Booking Flow

```
1. User selects date range
   GET /v2/slots?startTime=...&endTime=...&eventTypeId=123

2. User selects a slot
   POST /v2/slots/reservations
   {
     "eventTypeId": 123,
     "slotUtcStartDate": "2024-01-15T09:00:00Z",
     "slotUtcEndDate": "2024-01-15T09:30:00Z"
   }

3. User fills booking form

4. Create booking
   POST /v2/bookings
   {
     "start": "2024-01-15T09:00:00Z",
     "eventTypeId": 123,
     "attendee": {...}
   }

5. If user abandons, release reservation
   DELETE /v2/slots/reservations/{uid}
```

## Timezone Handling

All times in the API are in UTC (ISO 8601 format). Use the `timeZone` parameter to receive slots in a specific timezone for display purposes.

```http
GET /v2/slots?startTime=2024-01-15T00:00:00Z&endTime=2024-01-22T00:00:00Z&eventTypeId=123&timeZone=Europe/London
```

The response times will still be in UTC, but the slot calculation will respect the user's timezone for determining available hours.

```

### references/calendars.md

```markdown
# Calendars API Reference

Detailed documentation for calendar integration endpoints in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/calendars | List connected calendars |
| GET | /v2/calendars/busy-times | Get busy times |
| GET | /v2/calendars/{calendar}/check | Check calendar connection |
| POST | /v2/calendars/{calendar}/connect | Connect a calendar |
| DELETE | /v2/calendars/{calendar}/disconnect | Disconnect a calendar |
| GET | /v2/calendars/{calendar}/credentials | Get calendar credentials |
| GET | /v2/destination-calendars | List destination calendars |
| GET | /v2/selected-calendars | List selected calendars |

## List Connected Calendars

```http
GET /v2/calendars
```

### Response

```json
{
  "status": "success",
  "data": {
    "connectedCalendars": [
      {
        "integration": {
          "type": "google_calendar",
          "title": "Google Calendar",
          "slug": "google-calendar"
        },
        "credentialId": 123,
        "primary": {
          "externalId": "primary",
          "name": "[email protected]",
          "email": "[email protected]",
          "isSelected": true,
          "readOnly": false
        },
        "calendars": [
          {
            "externalId": "primary",
            "name": "[email protected]",
            "email": "[email protected]",
            "isSelected": true,
            "readOnly": false
          },
          {
            "externalId": "calendar-id-2",
            "name": "Work Calendar",
            "email": "[email protected]",
            "isSelected": true,
            "readOnly": false
          }
        ]
      }
    ],
    "destinationCalendar": {
      "id": 1,
      "integration": "google_calendar",
      "externalId": "primary",
      "name": "[email protected]"
    }
  }
}
```

## Get Busy Times

Check busy times from connected calendars to understand availability.

```http
GET /v2/calendars/busy-times
```

### Query Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| startTime | string | Yes | ISO 8601 start of date range |
| endTime | string | Yes | ISO 8601 end of date range |
| loggedInUsersTz | string | No | User's timezone |
| credentialId | number | No | Specific calendar credential ID |

### Example Request

```http
GET /v2/calendars/busy-times?startTime=2024-01-15T00:00:00Z&endTime=2024-01-22T00:00:00Z&loggedInUsersTz=America/New_York
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "start": "2024-01-15T10:00:00.000Z",
      "end": "2024-01-15T11:00:00.000Z",
      "title": "Team Meeting",
      "source": "google_calendar"
    },
    {
      "start": "2024-01-16T14:00:00.000Z",
      "end": "2024-01-16T15:00:00.000Z",
      "title": "Client Call",
      "source": "google_calendar"
    }
  ]
}
```

## Calendar Connection

### Check Calendar Connection

```http
GET /v2/calendars/{calendar}/check
```

### Path Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| calendar | string | Calendar type (e.g., `google-calendar`, `office365-calendar`) |

### Connect a Calendar

```http
POST /v2/calendars/{calendar}/connect
```

This initiates the OAuth flow for calendar connection.

### Disconnect a Calendar

```http
DELETE /v2/calendars/{calendar}/disconnect
```

## Supported Calendar Types

| Type | Slug | Description |
|------|------|-------------|
| Google Calendar | google-calendar | Google Workspace calendars |
| Microsoft 365 | office365-calendar | Outlook/Microsoft 365 calendars |
| Apple Calendar | apple-calendar | iCloud calendars (CalDAV) |
| CalDAV | caldav-calendar | Generic CalDAV calendars |

## Destination Calendars

The destination calendar is where new bookings are created.

### List Destination Calendars

```http
GET /v2/destination-calendars
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": 1,
      "integration": "google_calendar",
      "externalId": "primary",
      "name": "[email protected]",
      "userId": 123,
      "eventTypeId": null,
      "credentialId": 456
    }
  ]
}
```

## Selected Calendars

Selected calendars are checked for conflicts when calculating availability.

### List Selected Calendars

```http
GET /v2/selected-calendars
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "integration": "google_calendar",
      "externalId": "primary",
      "credentialId": 123
    },
    {
      "integration": "google_calendar",
      "externalId": "work-calendar-id",
      "credentialId": 123
    }
  ]
}
```

## ICS Feed

### Check ICS Feed

```http
GET /v2/calendars/ics-feed/check
```

### Save ICS Feed

```http
POST /v2/calendars/ics-feed/save
```

```json
{
  "url": "https://calendar.example.com/feed.ics"
}
```

## Calendar Events

### Get Calendar Event

```http
GET /v2/calendars/{calendar}/events/{eventUid}
```

### Response

```json
{
  "status": "success",
  "data": {
    "id": "event-id-123",
    "title": "Meeting",
    "description": "Discussion",
    "start": {
      "time": "2024-01-15T10:00:00.000Z",
      "timeZone": "America/New_York"
    },
    "end": {
      "time": "2024-01-15T11:00:00.000Z",
      "timeZone": "America/New_York"
    },
    "attendees": [
      {
        "email": "[email protected]",
        "name": "Attendee Name",
        "responseStatus": "accepted"
      }
    ],
    "status": "accepted",
    "source": "google"
  }
}
```

## Understanding Calendar Integration

### How Calendars Affect Availability

1. **Selected Calendars**: Events from selected calendars block availability
2. **Destination Calendar**: New bookings are created in this calendar
3. **Busy Times**: The API aggregates busy times from all selected calendars

### Calendar Sync Flow

```
1. User connects calendar (OAuth)
   POST /v2/calendars/google-calendar/connect

2. User selects which calendars to check for conflicts
   (Done via Cal.com dashboard)

3. User sets destination calendar for new bookings
   (Done via Cal.com dashboard)

4. When checking slots:
   - API fetches busy times from all selected calendars
   - Busy times are excluded from available slots

5. When booking is created:
   - Event is created in destination calendar
   - Confirmation emails sent to attendees
```

### Cal.com Event Identification

Cal.com events in external calendars can be identified by their iCalUID ending with `@Cal.com` (e.g., `[email protected]`).

## Team Calendar Integration

For team-level calendar management:

### Team Conferencing

```http
GET /v2/organizations/{orgId}/teams/{teamId}/conferencing
```

### Connect Team Calendar

```http
POST /v2/organizations/{orgId}/teams/{teamId}/conferencing/{app}/connect
```

## Best Practices

1. **Check connection status**: Verify calendar is connected before operations
2. **Handle OAuth expiry**: Calendar tokens may expire, handle re-authentication
3. **Respect rate limits**: Calendar APIs have their own rate limits
4. **Cache busy times**: Busy times don't change frequently, cache appropriately
5. **Use webhooks**: Subscribe to booking events instead of polling calendars

```

### references/webhooks.md

```markdown
# Webhooks API Reference

Detailed documentation for webhook management endpoints in the Cal.com API v2.

## Endpoints Overview

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v2/webhooks | List webhooks |
| POST | /v2/webhooks | Create a webhook |
| GET | /v2/webhooks/{webhookId} | Get a webhook |
| PATCH | /v2/webhooks/{webhookId} | Update a webhook |
| DELETE | /v2/webhooks/{webhookId} | Delete a webhook |

## List Webhooks

```http
GET /v2/webhooks
```

### Response

```json
{
  "status": "success",
  "data": [
    {
      "id": "webhook-id-123",
      "subscriberUrl": "https://your-app.com/webhook",
      "triggers": ["BOOKING_CREATED", "BOOKING_CANCELLED"],
      "active": true,
      "payloadTemplate": null,
      "secret": "whsec_..."
    }
  ]
}
```

## Create a Webhook

```http
POST /v2/webhooks
```

### Request Body

```json
{
  "subscriberUrl": "https://your-app.com/webhook",
  "triggers": ["BOOKING_CREATED", "BOOKING_CANCELLED", "BOOKING_RESCHEDULED"],
  "active": true,
  "payloadTemplate": null,
  "secret": "your-webhook-secret"
}
```

### Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| subscriberUrl | string | Yes | URL to receive webhook payloads |
| triggers | array | Yes | Events that trigger the webhook |
| active | boolean | No | Enable/disable webhook (default: true) |
| payloadTemplate | string | No | Custom payload template |
| secret | string | No | Secret for signature verification |

## Webhook Triggers

| Trigger | Description |
|---------|-------------|
| BOOKING_CREATED | New booking created |
| BOOKING_CANCELLED | Booking cancelled |
| BOOKING_RESCHEDULED | Booking rescheduled |
| BOOKING_CONFIRMED | Pending booking confirmed |
| BOOKING_REJECTED | Booking rejected |
| BOOKING_REQUESTED | Booking request received (requires confirmation) |
| BOOKING_PAYMENT_INITIATED | Payment started |
| BOOKING_NO_SHOW_UPDATED | Attendee marked as no-show |
| MEETING_STARTED | Video meeting started |
| MEETING_ENDED | Video meeting ended |
| RECORDING_READY | Meeting recording available |
| INSTANT_MEETING | Instant meeting created |
| RECORDING_TRANSCRIPTION_GENERATED | Transcription ready |
| FORM_SUBMITTED | Routing form submitted |

## Webhook Payload

### BOOKING_CREATED Payload

```json
{
  "triggerEvent": "BOOKING_CREATED",
  "createdAt": "2024-01-15T10:00:00.000Z",
  "payload": {
    "type": "30min",
    "title": "30 Minute Meeting",
    "description": "Meeting description",
    "startTime": "2024-01-15T10:00:00.000Z",
    "endTime": "2024-01-15T10:30:00.000Z",
    "organizer": {
      "id": 123,
      "name": "Jane Smith",
      "email": "[email protected]",
      "timeZone": "America/New_York"
    },
    "attendees": [
      {
        "name": "John Doe",
        "email": "[email protected]",
        "timeZone": "America/New_York"
      }
    ],
    "location": "https://cal.com/video/abc123",
    "destinationCalendar": {
      "integration": "google_calendar",
      "externalId": "calendar-id"
    },
    "uid": "booking-uid-123",
    "metadata": {},
    "responses": {
      "name": "John Doe",
      "email": "[email protected]"
    }
  }
}
```

### BOOKING_CANCELLED Payload

```json
{
  "triggerEvent": "BOOKING_CANCELLED",
  "createdAt": "2024-01-15T12:00:00.000Z",
  "payload": {
    "uid": "booking-uid-123",
    "title": "30 Minute Meeting",
    "startTime": "2024-01-15T10:00:00.000Z",
    "endTime": "2024-01-15T10:30:00.000Z",
    "cancellationReason": "Schedule conflict",
    "organizer": {...},
    "attendees": [...]
  }
}
```

### BOOKING_RESCHEDULED Payload

```json
{
  "triggerEvent": "BOOKING_RESCHEDULED",
  "createdAt": "2024-01-15T11:00:00.000Z",
  "payload": {
    "uid": "new-booking-uid",
    "rescheduleUid": "original-booking-uid",
    "title": "30 Minute Meeting",
    "startTime": "2024-01-16T14:00:00.000Z",
    "endTime": "2024-01-16T14:30:00.000Z",
    "reschedulingReason": "Conflict with another meeting",
    "organizer": {...},
    "attendees": [...]
  }
}
```

## Signature Verification

Webhooks include a signature header for verification:

```
X-Cal-Signature-256: sha256=<signature>
```

### Verification Example (Node.js)

```javascript
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return `sha256=${expectedSignature}` === signature;
}

// In your webhook handler
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-cal-signature-256'];
  const payload = JSON.stringify(req.body);
  
  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  const { triggerEvent, payload: data } = req.body;
  // ...
  
  res.status(200).send('OK');
});
```

## Get a Webhook

```http
GET /v2/webhooks/{webhookId}
```

## Update a Webhook

```http
PATCH /v2/webhooks/{webhookId}
```

### Request Body

```json
{
  "active": false,
  "triggers": ["BOOKING_CREATED"]
}
```

## Delete a Webhook

```http
DELETE /v2/webhooks/{webhookId}
```

## Event Type Webhooks

Create webhooks specific to an event type:

### List Event Type Webhooks

```http
GET /v2/event-types/{eventTypeId}/webhooks
```

### Create Event Type Webhook

```http
POST /v2/event-types/{eventTypeId}/webhooks
```

```json
{
  "subscriberUrl": "https://your-app.com/webhook",
  "triggers": ["BOOKING_CREATED"],
  "active": true
}
```

## Organization Webhooks

For organization-wide webhooks:

### List Organization Webhooks

```http
GET /v2/organizations/{orgId}/webhooks
```

### Create Organization Webhook

```http
POST /v2/organizations/{orgId}/webhooks
```

## OAuth Client Webhooks

For platform integrations:

### List OAuth Client Webhooks

```http
GET /v2/oauth-clients/{clientId}/webhooks
```

### Create OAuth Client Webhook

```http
POST /v2/oauth-clients/{clientId}/webhooks
```

## Custom Payload Templates

Customize webhook payloads using templates:

```json
{
  "subscriberUrl": "https://your-app.com/webhook",
  "triggers": ["BOOKING_CREATED"],
  "payloadTemplate": "{\"event\": \"{{triggerEvent}}\", \"booking_id\": \"{{payload.uid}}\", \"attendee\": \"{{payload.attendees[0].email}}\"}"
}
```

### Available Template Variables

- `{{triggerEvent}}` - Event type
- `{{payload.uid}}` - Booking UID
- `{{payload.title}}` - Event title
- `{{payload.startTime}}` - Start time
- `{{payload.endTime}}` - End time
- `{{payload.organizer.name}}` - Organizer name
- `{{payload.organizer.email}}` - Organizer email
- `{{payload.attendees[0].name}}` - First attendee name
- `{{payload.attendees[0].email}}` - First attendee email

## Best Practices

1. **Always verify signatures**: Use the webhook secret to verify payloads
2. **Respond quickly**: Return 200 within 5 seconds, process async if needed
3. **Handle retries**: Webhooks are retried on failure, implement idempotency
4. **Use HTTPS**: Always use HTTPS endpoints for security
5. **Log payloads**: Store webhook payloads for debugging
6. **Monitor failures**: Track webhook delivery failures

## Retry Policy

Failed webhook deliveries are retried with exponential backoff:

- 1st retry: 1 minute
- 2nd retry: 5 minutes
- 3rd retry: 30 minutes
- 4th retry: 2 hours
- 5th retry: 24 hours

After 5 failed attempts, the webhook is marked as failed.

```