Skip to main content
This guide explains how to build AI agents that interact with Cal.com’s scheduling infrastructure. For agents that can execute commands on a machine, use the official Cal.com CLI instead of calling the API directly. The CLI handles authentication, versioning, and common workflows automatically.
npm install -g @calcom/cli
The CLI includes --help flags on all commands to learn about available options:
calcom --help
calcom bookings --help
calcom slots --help
Only fall back to the API approach below if your agent cannot install or execute the CLI on its machine.

Overview

Cal.com API v2 enables AI agents to:
  • Check availability - Query available time slots for any user or team
  • Create bookings - Schedule meetings on behalf of users
  • Manage event types - Create and configure different meeting types
  • Handle rescheduling and cancellations - Modify existing bookings
  • Manage schedules - Set and update user availability
  • Track credit usage - Check balances and charge credits for agent interactions

Authentication

AI agents should authenticate using an API key. Generate one in Settings → Developer → API Keys.
curl -X GET "https://api.cal.com/v2/me" \
  -H "Authorization: Bearer cal_live_xxxxxxxxxxxx" \
  -H "cal-api-version: 2024-08-13"
The cal-api-version header is required for all v2 endpoints. If you omit it, requests will return a 404 or fall back to v1 behavior. Always include cal-api-version: 2024-08-13.

Common workflows

1. Check availability

Query available slots using username and event slug—no need to look up IDs first:
curl -X GET "https://api.cal.com/v2/slots?username=bailey&eventSlug=15min&startTime=2024-01-15T00:00:00Z&endTime=2024-01-16T23:59:59Z" \
  -H "cal-api-version: 2024-08-13"
Response includes available time slots:
{
  "status": "success",
  "data": {
    "slots": {
      "2024-01-15": [
        { "time": "2024-01-15T09:00:00Z" },
        { "time": "2024-01-15T10:00:00Z" },
        { "time": "2024-01-15T14:00:00Z" }
      ]
    }
  }
}

2. Create a booking

Schedule a meeting using username and event slug. This is the most common pattern for AI agents that extract scheduling intent from natural language (e.g., “book 15min with bailey”):
curl -X POST "https://api.cal.com/v2/bookings" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "eventTypeSlug": "15min",
    "username": "bailey",
    "start": "2024-01-15T09:00:00Z",
    "attendee": {
      "name": "John Doe",
      "email": "[email protected]",
      "timeZone": "America/New_York"
    }
  }'
The booking creation endpoint is public and does not require authentication. This allows agents to book on behalf of external users.

3. Handle custom booking questions

Most Cal.com users have required questions on their booking pages (e.g., “What is this meeting about?”). If you omit required fields, the API returns a 400 error. Include responses in bookingFieldsResponses:
curl -X POST "https://api.cal.com/v2/bookings" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "eventTypeSlug": "consultation",
    "username": "bailey",
    "start": "2024-01-15T09:00:00Z",
    "attendee": {
      "name": "John Doe",
      "email": "[email protected]",
      "timeZone": "America/New_York"
    },
    "bookingFieldsResponses": {
      "notes": "Discussing the new AI integration",
      "company_size": "10-50"
    }
  }'
To discover which fields are required, fetch the event type details first. The bookingFields array shows all custom questions and their requirements.

4. Instant bookings for urgent requests

For teams handling urgent requests, use the instant flag to bypass normal scheduling and immediately ring available team members:
curl -X POST "https://api.cal.com/v2/bookings" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "eventTypeSlug": "urgent-support",
    "username": "support-team",
    "start": "2024-01-15T09:00:00Z",
    "instant": true,
    "attendee": {
      "name": "John Doe",
      "email": "[email protected]",
      "timeZone": "America/New_York"
    }
  }'
Instant bookings require the event type to be configured for instant meetings. This is ideal for AI agents routing urgent customer requests.

5. Get user’s event types

Retrieve available event types to offer booking options:
curl -X GET "https://api.cal.com/v2/event-types?username=bailey" \
  -H "Authorization: Bearer cal_live_xxxxxxxxxxxx" \
  -H "cal-api-version: 2024-08-13"

6. Reschedule a booking

Move an existing booking to a new time:
curl -X POST "https://api.cal.com/v2/bookings/{bookingUid}/reschedule" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "start": "2024-01-16T10:00:00Z",
    "rescheduleReason": "Attendee requested different time"
  }'

7. Cancel a booking

curl -X POST "https://api.cal.com/v2/bookings/{bookingUid}/cancel" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "cancellationReason": "Meeting no longer needed"
  }'

Credit management

If your AI agent runs on the Cal.com platform, you can track usage by checking and charging credits through the API. This is useful for metering agent interactions against your account’s credit balance.

Check available credits

Before performing a billable action, verify that the user or team has sufficient credits:
curl -X GET "https://api.cal.com/v2/credits/available" \
  -H "Authorization: Bearer cal_live_xxxxxxxxxxxx" \
  -H "cal-api-version: 2024-08-13"
Response:
{
  "status": "success",
  "data": {
    "hasCredits": true,
    "balance": {
      "monthlyRemaining": 450,
      "additional": 200
    }
  }
}
The balance object breaks down your remaining credits:
  • monthlyRemaining — credits included in your current billing cycle
  • additional — purchased credits outside the monthly allowance

Charge credits

After a completed agent interaction, charge the appropriate number of credits:
curl -X POST "https://api.cal.com/v2/credits/charge" \
  -H "Authorization: Bearer cal_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "credits": 5,
    "creditFor": "AI_AGENT",
    "externalRef": "agent-thread-abc-1711432800000"
  }'
Response:
{
  "status": "success",
  "data": {
    "charged": true,
    "remainingBalance": {
      "monthlyRemaining": 445,
      "additional": 200
    }
  }
}
ParameterRequiredDescription
creditsYesNumber of credits to charge (minimum 1)
creditForYesUsage type — use AI_AGENT for agent interactions
externalRefNoUnique reference string for idempotency. Prevents double-charging if the same request is retried.
Always include an externalRef tied to your agent’s conversation or thread ID. This prevents duplicate charges if a network retry sends the same request twice.

Example: check-then-charge pattern

const headers = {
  "Authorization": "Bearer cal_live_xxxxxxxxxxxx",
  "Content-Type": "application/json",
  "cal-api-version": "2024-08-13"
};

// 1. Check credits before starting work
const available = await fetch("https://api.cal.com/v2/credits/available", { headers });
const { data } = await available.json();

if (!data.hasCredits) {
  throw new Error("No credits available");
}

// 2. Perform the agent interaction
const result = await runAgentTask();

// 3. Charge credits after completion
await fetch("https://api.cal.com/v2/credits/charge", {
  method: "POST",
  headers,
  body: JSON.stringify({
    credits: 5,
    creditFor: "AI_AGENT",
    externalRef: `thread-${threadId}-${Date.now()}`
  })
});

Best practices for AI agents

Handle time zones correctly

Always specify time zones explicitly. Store user preferences and pass them in requests:
{
  "attendee": {
    "timeZone": "Europe/London"
  }
}

Implement retry logic

API requests may occasionally fail. Implement exponential backoff:
async function callWithRetry(fn: () => Promise<Response>, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fn();
      if (response.ok) return response;
      if (response.status === 429) {
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
      throw new Error(`API error: ${response.status}`);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await sleep(Math.pow(2, i) * 1000);
    }
  }
}

Validate availability before booking

Always check slots before attempting to create a booking to avoid conflicts:
// 1. Get available slots
const slots = await getAvailableSlots("bailey", "15min", startDate, endDate);

// 2. Verify the desired slot is available
const isAvailable = slots.some(slot => slot.time === desiredTime);

// 3. Create booking only if slot is available
if (isAvailable) {
  await createBooking("bailey", "15min", desiredTime, attendee);
}

Use webhooks for real-time updates

Configure webhooks to receive notifications when bookings are created, rescheduled, or cancelled:
curl -X POST "https://api.cal.com/v2/webhooks" \
  -H "Authorization: Bearer cal_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "cal-api-version: 2024-08-13" \
  -d '{
    "subscriberUrl": "https://your-agent.com/webhooks/cal",
    "eventTriggers": ["BOOKING_CREATED", "BOOKING_RESCHEDULED", "BOOKING_CANCELLED"],
    "active": true
  }'

Rate limits

API key authentication allows 120 requests per minute by default. Contact support if you need higher limits for production agents.

API reference

For complete endpoint documentation, see the API v2 Reference. Key endpoints for agents:
EndpointDescription
GET /v2/slotsCheck available time slots
POST /v2/bookingsCreate a new booking
POST /v2/bookings/:uid/rescheduleReschedule a booking
POST /v2/bookings/:uid/cancelCancel a booking
GET /v2/event-typesList event types
GET /v2/schedulesGet user schedules
POST /v2/webhooksConfigure webhooks
GET /v2/credits/availableCheck credit balance
POST /v2/credits/chargeCharge credits for usage