Skip to main content
The Cal ID API is a REST API that lets you manage everything in Cal ID programmatically — event types, availability and schedules, bookable slots, bookings, teams, memberships, contacts, and webhooks. All requests and responses use JSON, and every endpoint is authenticated with an API key.

Base URL

All requests are made to https://api.cal.id.

Authentication

Cal ID authenticates requests with an API key sent as a Bearer token in the Authorization header.
1

Create an API key

In the Cal ID dashboard, go to Settings → Developer → API keys and create a key. Keys are prefixed with calid_. See Get your API key for the full walkthrough.
2

Send it with every request

Include the key in the Authorization header:
To manage a team’s resources (team event types, memberships, and schedules), use an API key belonging to a team owner or admin.
Your API key grants full access to your account. Keep it secret — never commit it to source control, embed it in client-side code, or share it in public links.

Sending a request body

POST and PATCH requests must carry a Content-Type: application/json header. Without it the request is rejected with 415 Unsupported Media Type before the body is parsed, even when the JSON you sent is perfectly valid.

Quickstart

Retrieve the authenticated user’s profile to confirm your key works:
For the full path from a fresh API key to a confirmed booking, see the Quickstart guide.

Response format

Most responses are a JSON envelope built from success, data, message, and meta — but not every endpoint returns all four, and error responses from outside the API’s routing layer do not use the envelope at all. Write your client to read data defensively rather than assuming a fixed shape.
The four shapes observed in testing:
The last shape is the one that breaks clients. When you typo a URL or use the wrong verb, the response has no success field at all, and error is a plain string ("Not Found") rather than the { code, message } object the API’s own errors use. Code that branches on if (!body.success) or reads body.error.code will throw instead of reporting a clean 404. Check the HTTP status code first, then the body.
The data field holds the resource or resources you requested. Read it rather than the top level.
data is not always an object or a list of objects with the shape you expect. GET /users/{userslug} returns data as an array, not a single user object — even though it looks up one user by slug. Index into it (data[0]) rather than reading fields off data directly.

Status codes

Do not treat 500 as a transient fault and retry it with backoff by default. On Cal ID, a 500 most often means the request asked for something the scheduling rules do not permit. Only 429 is reliably worth retrying.
See Error codes for every error.code value and the details shape that comes with each.

Pagination

Pagination is not uniform across the API. There are three different behaviours, and the default page size is not the same everywhere — so check this table before you write a paging loop.

The standard envelope shape

/event-types/, /booking/, /teams/*, and /webhook/ page with page and limit and report progress in a top-level meta.pagination object.

Contacts nest their pagination, with different key names

GET /contacts/ and GET /contacts/{id}/meetings put the records under data.rows and the counts under data.meta. The keys are not the ones used above — there is no total, page, or totalPages.
Page these endpoints by advancing offset while data.meta.hasMore is true.

Schedules are not paginated at all

GET /schedule/ and GET /teams/{teamId}/schedules return the complete list in data and carry no meta object. They accept page and limit in the query string without complaint, but ignore them — passing ?limit=1 still returns every schedule. Do not write a paging loop against these endpoints; it will either never terminate or silently re-read the same full list.

Limit ceilings

For /event-types/, /contacts/, and /teams/*, the maximum limit is 100. Asking for more is rejected:
The 100 ceiling is confirmed for /event-types/, /contacts/, and /teams/*. It was not tested on /booking/ or /webhook/, which already default to 100 — assume the same ceiling until you have verified otherwise.
Never rely on a default page size. GET /event-types/ returning 10 records does not mean you have 10 event types; it means you did not pass limit. Always set limit explicitly and page until the results are exhausted.

Dates and times

Almost every endpoint sends and receives timestamps as ISO-8601 strings — 2026-09-08T03:30:00.000Z. GET /availability/ is the exception. It returns RFC-1123 date strings instead:
A parser that assumes ISO-8601 everywhere will fail on GET /availability/ responses. Parse that endpoint’s dates as RFC-1123, or normalise them before they reach the rest of your code. Which other endpoints, if any, share this format has not been established — treat ISO-8601 as the rule and check /availability/ output explicitly.
GET /availability/ also requires the dateFrom query parameter. Calling it without one returns 400, not an unbounded list:

Filtering and sorting

Most list endpoints accept filters and sort keys as query parameters. For example, List bookings supports filtering by status, eventTypeIds, attendeeEmail, and date ranges (afterStartDate, beforeEndDate, afterCreatedDate, …), plus sorting with sortStart, sortCreated, and sortUpdated. See each endpoint’s Query Parameters for the full set.
GET /booking/ defaults to status=upcoming. With no status parameter you will not see past bookings, and there is no “all” value — page each bucket (upcoming, past, cancelled, unconfirmed, recurring) separately.

Developer guides and references

Quickstart

From a fresh API key to a confirmed booking in five requests.

Error codes

Every error.code the API returns, and what to do about each.

Get your API key

Create and manage the keys that authenticate your requests.

Find your Event Type ID

Locate the IDs you’ll pass to booking and event-type endpoints.

Webhooks

Subscribe to booking and meeting events in real time.

Integration overview

How the API is structured, from servers to authentication.

Rate limits

Stay under your allowance and recover cleanly from a 429.

Guides

Task-shaped recipes for bookings, slots, schedules, teams, and contacts.