Files
calendar/skills/calcom-api/references/authentication.md
T
Peer RichelsenGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
3f053b4e22 feat: add Cal.com APIv2 skills for AI agents (#27445)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-31 12:14:23 +00:00

7.5 KiB

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:

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

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:

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

{
  "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

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:

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):

GET /v2/oauth-clients
Authorization: Bearer cal_live_platform_admin_key

API Versioning

Many endpoints require a version header:

cal-api-version: 2024-08-13

Example with Version Header

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:

{
  "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:

{
  "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

    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/1.1 429 Too Many Requests
Retry-After: 60
{
  "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:

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

Expected Response

{
  "status": "success",
  "data": {
    "id": 12345,
    "email": "user@example.com",
    "username": "johndoe",
    "name": "John Doe",
    "timeZone": "America/New_York"
  }
}

Common Authentication Patterns

Server-Side Integration

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

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;
}

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