Resource-oriented scheduling API. Build booking into any app, website, or AI agent.
Four steps to book a meeting programmatically
Discover
List event types
GET /v1/event-types?host_id=HOST_IDCheck
Query available slots
POST /v1/slots/queryBook
Create booking
POST /v1/bookingsConfirm
Get booking details
GET /v1/bookings/{id}Optional API key via Bearer token. Public read endpoints work without auth.
Authorization: Bearer sk_live_your_api_key_hereGenerate API keys in Settings → API. Cancel and reschedule require either API key or guest_email verification.
All write endpoints accept an Idempotency-Key header to prevent duplicate operations.
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000Same key + same body → returns cached response. Same key + different body → VALIDATION_ERROR.
Every response uses a consistent shape
Success
{
"ok": true,
"data": { ... }
}Error
{
"ok": false,
"error": {
"code": "SLOT_NOT_AVAILABLE",
"message": "The selected slot is no longer available.",
"suggested_action": "fetch_slots_again"
}
}/v1/event-typesReturns active event types. Optionally filter by host_id.
curl "https://api.intocal.com/v1/event-types?host_id=HOST_ID"/v1/hosts/{host_id}/availabilityReturns weekly availability rules and date overrides for a host.
curl "https://api.intocal.com/v1/hosts/HOST_ID/availability"/v1/slots/queryReturns computed available time slots for a date range, respecting duration, buffers, min notice, and max booking window.
curl -X POST "https://api.intocal.com/v1/slots/query" \
-H "Content-Type: application/json" \
-d '{
"event_type_id": "evt-123",
"host_id": "host-123",
"from": "2026-03-24T00:00:00Z",
"to": "2026-03-25T00:00:00Z",
"timezone": "Europe/Tallinn"
}'/v1/bookingsCreates a confirmed booking. Validates slot availability at write time. Supports Idempotency-Key header.
curl -X POST "https://api.intocal.com/v1/bookings" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"event_type_id": "evt-123",
"host_id": "host-123",
"slot_start": "2026-03-24T13:00:00Z",
"timezone": "Europe/Tallinn",
"invitee": {
"name": "Jane Doe",
"email": "jane@example.com"
},
"metadata": { "source": "agent" }
}'/v1/bookings/{booking_id}Retrieves a single booking by ID.
curl "https://api.intocal.com/v1/bookings/bk-789"/v1/bookings/{booking_id}/cancelCancels a confirmed booking. Requires API key auth or guest_email verification.
curl -X POST "https://api.intocal.com/v1/bookings/bk-789/cancel" \
-H "Content-Type: application/json" \
-d '{
"reason": "Invitee requested cancellation",
"guest_email": "jane@example.com"
}'/v1/bookings/{booking_id}/rescheduleMoves a booking to a new time slot. Validates new slot availability. Requires API key auth or guest_email.
curl -X POST "https://api.intocal.com/v1/bookings/bk-789/reschedule" \
-H "Content-Type: application/json" \
-d '{
"new_slot_start": "2026-03-25T15:00:00Z",
"timezone": "Europe/Tallinn",
"guest_email": "jane@example.com"
}'All possible error codes returned by the API
| Code | Status | Description |
|---|---|---|
| VALIDATION_ERROR | 400 | Invalid input, missing fields, or unknown fields in request body |
| UNAUTHORIZED | 401 | Authentication required (guest_email missing or mismatched) |
| FORBIDDEN | 403 | Insufficient permissions for this action |
| NOT_FOUND | 404 | Resource not found |
| METHOD_NOT_ALLOWED | 405 | HTTP method not supported for this endpoint |
| HOST_INACTIVE | 403 | Host is not currently accepting bookings |
| EVENT_TYPE_INACTIVE | 403 | Event type is disabled |
| SLOT_NOT_AVAILABLE | 409 | Time slot is taken, outside notice window, or past max booking range |
| BOOKING_ALREADY_CANCELED | 409 | Booking has already been canceled |
| BOOKING_NOT_RESCHEDULABLE | 409 | Canceled bookings cannot be rescheduled |
| INVALID_TIMEZONE | 400 | Unrecognized IANA timezone string |
| RATE_LIMITED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Server error |
Full booking flow example
const BASE = "https://api.intocal.com/v1";
const headers = {
"Content-Type": "application/json",
"Authorization": "Bearer sk_live_your_api_key"
};
// 1. List event types
const { data: types } = await fetch(
`${BASE}/event-types?host_id=HOST_ID`, { headers }
).then(r => r.json());
// 2. Query available slots
const { data: { slots } } = await fetch(`${BASE}/slots/query`, {
method: "POST", headers,
body: JSON.stringify({
event_type_id: types[0].id,
host_id: "HOST_ID",
from: "2026-03-24T00:00:00Z",
to: "2026-03-25T00:00:00Z",
timezone: "Europe/Tallinn"
})
}).then(r => r.json());
// 3. Book the first available slot
const available = slots.filter(s => s.available);
const { data: booking } = await fetch(`${BASE}/bookings`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
event_type_id: types[0].id,
host_id: "HOST_ID",
slot_start: available[0].start,
timezone: "Europe/Tallinn",
invitee: { name: "Jane Doe", email: "jane@example.com" },
metadata: { source: "sdk" }
})
}).then(r => r.json());
console.log("Booked:", booking.id, booking.start);Using requests library
import requests, uuid
BASE = "https://api.intocal.com/v1"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer sk_live_your_api_key"
}
# 1. List event types
types = requests.get(f"{BASE}/event-types?host_id=HOST_ID",
headers=headers).json()["data"]
# 2. Query slots
slots = requests.post(f"{BASE}/slots/query", headers=headers, json={
"event_type_id": types[0]["id"],
"host_id": "HOST_ID",
"from": "2026-03-24T00:00:00Z",
"to": "2026-03-25T00:00:00Z",
"timezone": "Europe/Tallinn"
}).json()["data"]["slots"]
# 3. Book
available = [s for s in slots if s["available"]]
booking = requests.post(f"{BASE}/bookings",
headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
json={
"event_type_id": types[0]["id"],
"host_id": "HOST_ID",
"slot_start": available[0]["start"],
"timezone": "Europe/Tallinn",
"invitee": {"name": "Jane", "email": "jane@example.com"},
}
).json()["data"]
print(f"Booked: {booking['id']} at {booking['start']}")Map these 1:1 to the API endpoints for structured tool calls. Read actions (list, query, get) don't need confirmation. Write actions (book, cancel, reschedule) should confirm with the user first.
get_event_types{ host_id }get_available_slots{ event_type_id, host_id, from, to, timezone }create_booking{ event_type_id, host_id, slot_start, timezone, invitee }get_booking{ booking_id }cancel_booking{ booking_id, reason }reschedule_booking{ booking_id, new_slot_start, timezone }https://api.intocal.com/v1IntoCal API v1 · OpenAPI Spec · llms.txt · AI Plugin