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

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
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
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.

Note
Public endpoints (booking, availability lookup, AI chat) do not require authentication.

Auth

POST /api/auth/register Create a new account

Register a new Calendo user. Creates a default booking page and availability schedule.

Request Body

FieldTypeRequiredDescription
emailstringYesUser's email address
passwordstringYesMinimum 8 characters
namestringYesUser's display name

Response

json
{
  "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
curl -X POST https://calendo.dev/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "securepass123",
    "name": "Jane Smith"
  }'
POST /api/auth/login Log in to an existing account

Authenticate with email and password. Returns a session cookie.

Request Body

FieldTypeRequiredDescription
emailstringYesUser's email address
passwordstringYesUser's password

Response

json
{
  "user": {
    "id": 1,
    "email": "you@example.com",
    "name": "Jane Smith",
    "timezone": "America/Los_Angeles"
  }
}

Example

curl
curl -X POST https://calendo.dev/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "securepass123"}'
POST /api/auth/logout End session

Log out and destroy the current session. Requires authentication.

Response

json
{ "ok": true }

Example

curl
curl -X POST https://calendo.dev/api/auth/logout \
  -H "Cookie: session=your_session_token"
GET /api/auth/me Get current user

Returns the currently authenticated user's profile. Requires authentication.

Response

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

GET /api/event-types List all event types

Returns all active event types for the authenticated user.

Response

json
[
  {
    "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
curl https://calendo.dev/api/event-types \
  -H "X-API-Key: cal_your_api_key"
POST /api/event-types Create an event type

Create a new bookable event type.

Request Body

FieldTypeRequiredDescription
namestringYesEvent type name
duration_minutesintegerNoDuration in minutes (5-720, default: 30)
descriptionstringNoDescription shown on booking page
colorstringNoHex color (default: #0069ff)
location_typestringNogoogle_meet, zoom, phone, custom
questionsarrayNoCustom questions for invitees
is_secretbooleanNoHidden from booking page listing
requires_confirmationbooleanNoRequire host confirmation
buffer_beforeintegerNoBuffer time before in minutes
buffer_afterintegerNoBuffer time after in minutes
min_notice_hoursintegerNoMinimum scheduling notice (default: 4)
max_future_daysintegerNoHow far in advance to allow booking (default: 60)

Example

curl
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"
  }'
GET /api/event-types/:id Get a single event type

Retrieve a specific event type by ID.

Example

curl
curl https://calendo.dev/api/event-types/1 \
  -H "X-API-Key: cal_your_api_key"
PUT /api/event-types/:id Update an event type

Update any fields on an existing event type. Only include fields you want to change.

Example

curl
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"}'
DELETE /api/event-types/:id Delete an event type

Soft-deletes an event type (sets is_active = 0). The event type will no longer appear on your booking page.

Response

json
{ "ok": true }

Example

curl
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.

GET /api/availability-schedules List availability schedules

Returns all availability schedules for the authenticated user. Requires authentication.

Response

json
[
  {
    "id": 1,
    "name": "Working Hours",
    "timezone": "America/Los_Angeles",
    "rules": "[{\"day\":1,\"start\":\"09:00\",\"end\":\"17:00\"}, ...]",
    "is_default": 1
  }
]

Example

curl
curl https://calendo.dev/api/availability-schedules \
  -H "X-API-Key: cal_your_api_key"
POST /api/availability-schedules Create availability schedule

Create a new availability schedule. Requires authentication.

Request Body

FieldTypeRequiredDescription
namestringYesSchedule name
timezonestringNoIANA timezone (default: America/Los_Angeles)
rulesarrayNoWeekly recurring rules: [{day, start, end}]
overridesarrayNoDate-specific overrides
is_defaultbooleanNoSet as default schedule

Example

curl
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"}
    ]
  }'
GET /api/availability/:username/:event-slug Get available time slots (public)

Returns available time slots for a user's event type within a date range. No authentication required.

Query Parameters

ParamTypeRequiredDescription
startstringYesStart date (YYYY-MM-DD)
endstringYesEnd date (YYYY-MM-DD)
timezonestringNoInvitee timezone (default: UTC)

Response

json
{
  "slots": {
    "2026-03-10": ["09:00", "09:30", "10:00", "10:30", "..."],
    "2026-03-11": ["09:00", "09:30", "10:00", "..."]
  }
}

Example

curl
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.

GET /api/bookings List bookings

Returns all bookings for the authenticated user, ordered by start time descending. Requires authentication.

Response

json
[
  {
    "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
curl https://calendo.dev/api/bookings \
  -H "X-API-Key: cal_your_api_key"
POST /api/book/:username/:event-slug Create a booking (public)

Book a time slot with a user. No authentication required -- this is the public booking endpoint used by invitees.

Request Body

FieldTypeRequiredDescription
namestringYesInvitee's name
emailstringYesInvitee's email
timezonestringNoInvitee's timezone (default: UTC)
start_timestringYesISO 8601 datetime of the slot
answersobjectNoAnswers to custom questions

Response (201)

json
{
  "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
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"
  }'
POST /api/bookings/:id/cancel Cancel a booking

Cancel an existing booking. Requires authentication (host only).

Response

json
{ "ok": true }

Example

curl
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.

GET /api/booking-page Get your booking page

Retrieve your booking page settings. Requires authentication.

Response

json
{
  "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
curl https://calendo.dev/api/booking-page \
  -H "X-API-Key: cal_your_api_key"
PUT /api/booking-page Update your booking page

Update booking page settings. Requires authentication. Only include fields you want to change.

Request Body

FieldTypeDescription
display_namestringName shown on booking page
biostringShort bio/description
brand_colorstringHex color for branding
welcome_messagestringMessage shown to invitees
slugstringURL slug (must be unique)

Example

curl
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.

GET /api/webhooks List webhooks

Returns all registered webhooks for the authenticated user.

Example

curl
curl https://calendo.dev/api/webhooks \
  -H "X-API-Key: cal_your_api_key"
POST /api/webhooks Create a webhook

Register a new webhook URL.

Request Body

FieldTypeRequiredDescription
urlstringYesWebhook endpoint URL (HTTPS)
eventsarrayYesEvents to subscribe to
secretstringNoSigning secret for verification

Example

curl
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"
  }'
PUT /api/webhooks/:id Update a webhook

Update an existing webhook's URL, events, or secret.

Example

curl
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"]}'
DELETE /api/webhooks/:id Delete a webhook

Remove a registered webhook.

Example

curl
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.

POST /api/ai/chat Send a chat message

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

FieldTypeRequiredDescription
booking_page_slugstringYesThe booking page slug
session_idstringNoChat session ID (auto-generated if omitted)
messagestringYesThe user's message

Response

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

EventDescription
booking.createdA new booking has been confirmed
booking.cancelledA booking has been cancelled
booking.rescheduledA booking has been moved to a new time

Payload Format

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

javascript
// 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:

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

CategoryLimitWindowKey
Public endpoints (booking, availability, AI chat)60 requests1 minuteIP address
Authenticated endpoints (CRUD operations)300 requests1 minuteUser ID

Rate Limit Headers

All API responses include rate limit information in the headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix 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.

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

json
{
  "error": "Human-readable error message"
}

Status Codes

CodeMeaningDescription
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid input or missing required fields
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions
404Not FoundResource does not exist
409ConflictResource already exists or time slot taken
429Too Many RequestsRate limit exceeded
500Internal Server ErrorSomething went wrong on our end