Calendo API
The Calendo API lets you integrate scheduling into your applications. Create event types, manage availability, handle bookings, and build custom scheduling workflows.
Base URL
https://calendo.dev/api
Content Type
All requests and responses use JSON. Set the Content-Type header to application/json for all requests with a body.
Request Format
curl https://calendo.dev/api/event-types \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key"
Authentication
Calendo supports two authentication methods. Use whichever fits your use case.
Session Cookies (Browser)
When you log in via POST /api/auth/login, the response sets a secure HTTP-only session cookie. All subsequent requests from the browser automatically include this cookie. This is the recommended method for browser-based applications.
API Keys (Programmatic Access)
For server-to-server integrations, use API keys. Include your key in the X-API-Key header.
curl https://calendo.dev/api/event-types \
-H "X-API-Key: cal_your_api_key"
Creating API Keys
You can create API keys from your Calendo dashboard under Settings > API Keys. Each key can be given a label and optional expiration date. Store your key securely -- it is only shown once at creation time.
Auth
Register a new Calendo user. Creates a default booking page and availability schedule.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User's email address |
password | string | Yes | Minimum 8 characters |
name | string | Yes | User's display name |
Response
{
"user": {
"id": 1,
"email": "you@example.com",
"name": "Jane Smith",
"timezone": "America/Los_Angeles",
"created_at": "2026-03-07 10:00:00"
},
"bookingSlug": "jane-smith"
}
Example
curl -X POST https://calendo.dev/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"password": "securepass123",
"name": "Jane Smith"
}'
Authenticate with email and password. Returns a session cookie.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User's email address |
password | string | Yes | User's password |
Response
{
"user": {
"id": 1,
"email": "you@example.com",
"name": "Jane Smith",
"timezone": "America/Los_Angeles"
}
}
Example
curl -X POST https://calendo.dev/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "securepass123"}'
Log out and destroy the current session. Requires authentication.
Response
{ "ok": true }
Example
curl -X POST https://calendo.dev/api/auth/logout \
-H "Cookie: session=your_session_token"
Returns the currently authenticated user's profile. Requires authentication.
Response
{
"id": 1,
"email": "you@example.com",
"name": "Jane Smith",
"timezone": "America/Los_Angeles",
"avatar_url": null,
"created_at": "2026-03-07 10:00:00"
}
Example
curl https://calendo.dev/api/auth/me \
-H "X-API-Key: cal_your_api_key"
Event Types
Event types are bookable meeting templates. Each event type has a name, duration, and slug used in booking URLs.
Returns all active event types for the authenticated user.
Response
[
{
"id": 1,
"name": "30 Minute Call",
"slug": "30-minute-call",
"duration_minutes": 30,
"color": "#0069ff",
"description": "A quick intro call",
"is_active": 1
}
]
Example
curl https://calendo.dev/api/event-types \
-H "X-API-Key: cal_your_api_key"
Create a new bookable event type.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Event type name |
duration_minutes | integer | No | Duration in minutes (5-720, default: 30) |
description | string | No | Description shown on booking page |
color | string | No | Hex color (default: #0069ff) |
location_type | string | No | google_meet, zoom, phone, custom |
questions | array | No | Custom questions for invitees |
is_secret | boolean | No | Hidden from booking page listing |
requires_confirmation | boolean | No | Require host confirmation |
buffer_before | integer | No | Buffer time before in minutes |
buffer_after | integer | No | Buffer time after in minutes |
min_notice_hours | integer | No | Minimum scheduling notice (default: 4) |
max_future_days | integer | No | How far in advance to allow booking (default: 60) |
Example
curl -X POST https://calendo.dev/api/event-types \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{
"name": "30 Minute Call",
"duration_minutes": 30,
"description": "A quick intro call",
"color": "#0069ff"
}'
Retrieve a specific event type by ID.
Example
curl https://calendo.dev/api/event-types/1 \
-H "X-API-Key: cal_your_api_key"
Update any fields on an existing event type. Only include fields you want to change.
Example
curl -X PUT https://calendo.dev/api/event-types/1 \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{"duration_minutes": 45, "description": "Extended intro call"}'
Soft-deletes an event type (sets is_active = 0). The event type will no longer appear on your booking page.
Response
{ "ok": true }
Example
curl -X DELETE https://calendo.dev/api/event-types/1 \
-H "X-API-Key: cal_your_api_key"
Availability
Manage availability schedules (when you are open for bookings) and look up available slots for a specific user's event type.
Returns all availability schedules for the authenticated user. Requires authentication.
Response
[
{
"id": 1,
"name": "Working Hours",
"timezone": "America/Los_Angeles",
"rules": "[{\"day\":1,\"start\":\"09:00\",\"end\":\"17:00\"}, ...]",
"is_default": 1
}
]
Example
curl https://calendo.dev/api/availability-schedules \
-H "X-API-Key: cal_your_api_key"
Create a new availability schedule. Requires authentication.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Schedule name |
timezone | string | No | IANA timezone (default: America/Los_Angeles) |
rules | array | No | Weekly recurring rules: [{day, start, end}] |
overrides | array | No | Date-specific overrides |
is_default | boolean | No | Set as default schedule |
Example
curl -X POST https://calendo.dev/api/availability-schedules \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{
"name": "Evening Hours",
"timezone": "America/New_York",
"rules": [
{"day": 1, "start": "18:00", "end": "21:00"},
{"day": 3, "start": "18:00", "end": "21:00"}
]
}'
Returns available time slots for a user's event type within a date range. No authentication required.
Query Parameters
| Param | Type | Required | Description |
|---|---|---|---|
start | string | Yes | Start date (YYYY-MM-DD) |
end | string | Yes | End date (YYYY-MM-DD) |
timezone | string | No | Invitee timezone (default: UTC) |
Response
{
"slots": {
"2026-03-10": ["09:00", "09:30", "10:00", "10:30", "..."],
"2026-03-11": ["09:00", "09:30", "10:00", "..."]
}
}
Example
curl "https://calendo.dev/api/availability/jane-smith/30-minute-call?start=2026-03-10&end=2026-03-14&timezone=America/New_York"
Bookings
Create and manage bookings. Invitees can book through the public endpoint; hosts manage bookings through authenticated endpoints.
Returns all bookings for the authenticated user, ordered by start time descending. Requires authentication.
Response
[
{
"id": 1,
"event_type_name": "30 Minute Call",
"invitee_name": "Bob Johnson",
"invitee_email": "bob@example.com",
"start_time": "2026-03-10 14:00:00",
"end_time": "2026-03-10 14:30:00",
"status": "confirmed",
"duration_minutes": 30
}
]
Example
curl https://calendo.dev/api/bookings \
-H "X-API-Key: cal_your_api_key"
Book a time slot with a user. No authentication required -- this is the public booking endpoint used by invitees.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Invitee's name |
email | string | Yes | Invitee's email |
timezone | string | No | Invitee's timezone (default: UTC) |
start_time | string | Yes | ISO 8601 datetime of the slot |
answers | object | No | Answers to custom questions |
Response (201)
{
"booking": {
"uid": "a1b2c3d4-...",
"event_name": "30 Minute Call",
"invitee_name": "Bob Johnson",
"invitee_email": "bob@example.com",
"start_time": "2026-03-10 14:00:00",
"end_time": "2026-03-10 14:30:00",
"status": "confirmed",
"timezone": "America/New_York"
}
}
Example
curl -X POST https://calendo.dev/api/book/jane-smith/30-minute-call \
-H "Content-Type: application/json" \
-d '{
"name": "Bob Johnson",
"email": "bob@example.com",
"timezone": "America/New_York",
"start_time": "2026-03-10T19:00:00Z"
}'
Cancel an existing booking. Requires authentication (host only).
Response
{ "ok": true }
Example
curl -X POST https://calendo.dev/api/bookings/1/cancel \
-H "X-API-Key: cal_your_api_key"
Booking Page
Each user has a public booking page with a unique slug. Manage your booking page settings.
Retrieve your booking page settings. Requires authentication.
Response
{
"id": 1,
"slug": "jane-smith",
"display_name": "Jane Smith",
"bio": "Product Designer at Acme",
"brand_color": "#2563eb",
"welcome_message": "Pick a time that works for you!"
}
Example
curl https://calendo.dev/api/booking-page \
-H "X-API-Key: cal_your_api_key"
Update booking page settings. Requires authentication. Only include fields you want to change.
Request Body
| Field | Type | Description |
|---|---|---|
display_name | string | Name shown on booking page |
bio | string | Short bio/description |
brand_color | string | Hex color for branding |
welcome_message | string | Message shown to invitees |
slug | string | URL slug (must be unique) |
Example
curl -X PUT https://calendo.dev/api/booking-page \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{"bio": "Product Designer at Acme", "brand_color": "#7c3aed"}'
Webhooks
Register webhook URLs to receive real-time notifications about booking events.
Returns all registered webhooks for the authenticated user.
Example
curl https://calendo.dev/api/webhooks \
-H "X-API-Key: cal_your_api_key"
Register a new webhook URL.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Webhook endpoint URL (HTTPS) |
events | array | Yes | Events to subscribe to |
secret | string | No | Signing secret for verification |
Example
curl -X POST https://calendo.dev/api/webhooks \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{
"url": "https://your-app.com/webhooks/calendo",
"events": ["booking.created", "booking.cancelled"],
"secret": "whsec_your_secret"
}'
Update an existing webhook's URL, events, or secret.
Example
curl -X PUT https://calendo.dev/api/webhooks/1 \
-H "Content-Type: application/json" \
-H "X-API-Key: cal_your_api_key" \
-d '{"events": ["booking.created", "booking.cancelled", "booking.rescheduled"]}'
Remove a registered webhook.
Example
curl -X DELETE https://calendo.dev/api/webhooks/1 \
-H "X-API-Key: cal_your_api_key"
AI Chat
The AI chat endpoint powers conversational booking on your booking page. Invitees can describe their scheduling needs in natural language.
Send a message to the AI scheduling assistant. The AI will help the invitee choose an event type and find available times. No authentication required.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
booking_page_slug | string | Yes | The booking page slug |
session_id | string | No | Chat session ID (auto-generated if omitted) |
message | string | Yes | The user's message |
Response
{
"session_id": "abc-123",
"message": "I can help with that! Jane has a 30-minute call available...",
"action": {
"type": "suggest_booking",
"event_slug": "30-minute-call",
"preferred_dates": ["2026-03-10"],
"preferred_time": "afternoon"
}
}
Example
curl -X POST https://calendo.dev/api/ai/chat \
-H "Content-Type: application/json" \
-d '{
"booking_page_slug": "jane-smith",
"message": "I need a 30 minute call next Tuesday afternoon"
}'
Webhook Events
Calendo sends webhook notifications for key booking events. Your endpoint should respond with a 2xx status code within 10 seconds.
Event Types
| Event | Description |
|---|---|
booking.created | A new booking has been confirmed |
booking.cancelled | A booking has been cancelled |
booking.rescheduled | A booking has been moved to a new time |
Payload Format
{
"event": "booking.created",
"created_at": "2026-03-10T14:00:00Z",
"data": {
"booking": {
"uid": "a1b2c3d4-...",
"event_type": "30 Minute Call",
"invitee_name": "Bob Johnson",
"invitee_email": "bob@example.com",
"start_time": "2026-03-10 14:00:00",
"end_time": "2026-03-10 14:30:00",
"status": "confirmed",
"timezone": "America/New_York"
}
}
}
Signature Verification
Each webhook request includes an X-Calendo-Signature header containing an HMAC-SHA256 signature of the request body, using your webhook secret as the key.
// Verify webhook signature (Node.js)
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Retry Policy
If your endpoint returns a non-2xx status code or times out, Calendo will retry the delivery up to 3 times with exponential backoff:
- 1st retry: 1 minute after initial attempt
- 2nd retry: 5 minutes after 1st retry
- 3rd retry: 30 minutes after 2nd retry
After 3 failed attempts, the webhook delivery is marked as failed. You can check delivery status in your dashboard.
Rate Limits
Rate limits protect the API from abuse and ensure fair usage for all users. Limits are applied per IP address for public endpoints and per user for authenticated endpoints.
Limits by Endpoint Category
| Category | Limit | Window | Key |
|---|---|---|---|
| Public endpoints (booking, availability, AI chat) | 60 requests | 1 minute | IP address |
| Authenticated endpoints (CRUD operations) | 300 requests | 1 minute | User ID |
Rate Limit Headers
All API responses include rate limit information in the headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Exceeding the Limit
When you exceed the rate limit, the API returns a 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait.
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after 42 seconds."
}
}
Errors
Calendo uses standard HTTP status codes and returns errors in a consistent JSON format.
Error Format
{
"error": "Human-readable error message"
}
Status Codes
| Code | Meaning | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid input or missing required fields |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource does not exist |
409 | Conflict | Resource already exists or time slot taken |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Something went wrong on our end |