* refactor: consolidate agent config folders into agents directory - Move .claude/skills and .claude/rules content to agents/ - Remove duplicate .cursor/ and .goose/ folders - Create symlinks from .claude/ and .cursor/ to agents/ - Convert review.mdc to quality-review-checklist.md with proper frontmatter Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: add Cal.com APIv2 skills to agents directory Move the Cal.com API v2 skills from PR #27445 into the consolidated agents/skills/ directory structure. This includes: - SKILL.md - Main skill file with API overview - references/authentication.md - Authentication methods - references/bookings.md - Bookings API reference - references/calendars.md - Calendars API reference - references/event-types.md - Event types API reference - references/schedules.md - Schedules API reference - references/slots-availability.md - Slots and availability API reference - references/webhooks.md - Webhooks API reference Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * fix: update calcom-api skill to use Claude Code frontmatter format Remove non-standard frontmatter fields (license, metadata) and keep only the Claude Code supported fields (name, description) as per the Claude Code skills specification. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: restructure calcom-api SKILL.md as index file Convert SKILL.md from a comprehensive API doc (317 lines) to a concise index file (108 lines) that references the detailed documentation in the references/ folder. This follows the Claude Code skills pattern of keeping SKILL.md focused with supporting files for detailed content. The SKILL.md now: - Provides a quick start guide with essential examples - References all 7 detailed reference docs in a table - Lists common workflows and best practices - Points to external resources Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * docs: preserve deleted content in reference files Move content that was removed from SKILL.md to appropriate reference files: - Add Error Handling and Pagination sections to authentication.md - Add Organization endpoints to event-types.md - Add Core Concepts section back to SKILL.md This ensures no useful API documentation is lost during the restructuring. Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
407 lines
9.0 KiB
Markdown
407 lines
9.0 KiB
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": "user@example.com",
|
|
"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
|