Developers
REST API
API keys and scopes, every endpoint, errors, rate limits and connecting other apps.
A small REST API for reading availability and taking bookings from your own website, POS, chatbot or scheduling tool. Every booking goes through the same engine the app uses, so the API cannot create a booking the board would have refused.
https://calendarbook.crawlink.com/api/v1Getting a key
- Sign in as an Admin or the Owner and open Settings → API keys.
- Choose New key. Say what it is for, pick what it may do (the scopes below), optionally limit it to certain calendars, and choose an expiry: never, 30 days, 90 days or a year.
- Copy the key now. It is shown once. Only its SHA-256 is stored, so nobody — including us — can recover it. Lose it and you revoke it and issue another.
Give each integration its own key with the narrowest scopes that do the job, so one can be revoked without breaking the others. The list shows each key's requests, when it was last used and when it expires, with Revoke and Delete permanently.
Authentication
Send the key as a bearer token. X-Api-Key works too, for clients that cannot set an
Authorization header. The organization id is part of the key, so no account id is needed alongside it.
Cross-origin requests are allowed.
Authorization: Bearer ck_<organization>_<secret>Scopes
| Scope | Allows |
|---|---|
calendars.read | Read calendars — List calendars and locations. |
availability.read | Read availability — Ask which times are free on a given day. |
bookings.read | Read bookings — List and read bookings, including customer contact details. |
bookings.write | Create and change bookings — Take new bookings and move existing ones. |
bookings.cancel | Cancel bookings — Cancel a booking. Separate from writing, because it is destructive. |
bookings.override | Book outside opening hours — Ignore opening hours and slot boundaries. Only for systems recording walk-ins. |
customers.read | Read customers — List and read the customer directory. |
customers.write | Create and change customers — Add customers and edit their details. |
Endpoints
| Call | Scope | What it does |
|---|---|---|
GET /health | calendars.read | Confirms the key works and reports its organization and what it may do. |
GET /calendars | calendars.read | Calendars and locations, with the slot length, gaps and notice each one enforces. |
GET /availability | availability.read | Free times for one calendar: calendarId, date (YYYY-MM-DD), days (1–31) and partySize. |
GET /bookings | bookings.read | Bookings from–to (default today to 60 days ahead), filtered by calendarId, status, search, phone or googleEventId; page and pageSize (up to 200). |
POST /bookings | bookings.write | Takes a booking through the same availability engine the app uses. |
GET /bookings/{id} | bookings.read | One booking. |
PATCH /bookings/{id} | bookings.write | Moves it (calendarId, date, start), edits it (customer details, notes, partySize, price, paid) or changes its status. Cancelling this way also needs bookings.cancel. |
DELETE /bookings/{id} | bookings.cancel | Cancels it, with an optional ?reason=. The record is kept. |
GET /customers | customers.read | The customer directory: search, page, pageSize. |
POST /customers | customers.write | Creates a customer (name, phone, email, notes, tags), or updates one when id is given. |
Finding free times
curl "https://calendarbook.crawlink.com/api/v1/availability?calendarId=CAL_ID&date=2026-11-02&days=7" \
-H "Authorization: Bearer ck_ORG_SECRET"Each day comes back with its open windows and the individual starts on offer. Every slot carries both a
local time and an absolute startsAt instant, so a caller in another timezone never has to
redo the conversion.
Taking a booking
curl -X POST "https://calendarbook.crawlink.com/api/v1/bookings" \
-H "Authorization: Bearer ck_ORG_SECRET" \
-H "Content-Type: application/json" \
-d '{
"calendarId": "CAL_ID",
"date": "2026-11-02",
"start": "18:30",
"customerName": "Asha Menon",
"customerPhone": "+919876543210",
"notes": "First visit"
}'calendarId,date,startandcustomerNameare required.starttakes"18:30"or minutes from midnight.- Optional:
durationMinutes,partySize,customerPhone,customerEmail,customerId,notes, andstatus: "pending"to hold it for approval (the default is confirmed). forcebooks outside the usual rules and needs thebookings.overridescope — for systems recording walk-ins.
Errors
Every failure is JSON with a stable error.code. Branch on the code, not the message, which may be reworded.
{
"error": {
"code": "slot_unavailable",
"message": "That time is already booked. Please pick another time."
}
}| Code | Status | Meaning |
|---|---|---|
missing_key | 401 | No key was sent. |
invalid_key | 401 | Unknown, revoked or expired. |
missing_scope | 403 | The key lacks the scope for this call. |
out_of_scope | 403 | The key is limited to other calendars. |
not_found | 404 | No such booking or calendar. |
slot_unavailable | 409 | The time is no longer free. |
rate_limited | 429 | Too many requests this minute. |
invalid_body | 400 | The request body was malformed. |
Rate limit
120 requests a minute per key. It exists to stop a runaway script, not to meter usage — if a legitimate integration needs more, ask and we will raise it.
Connecting from another application
An application that many organizations use does not want each of them pasting a key. It can ask instead: send the person to the address below; they sign in, tick the organizations to connect, and come back to you with a one-time code.
https://calendarbook.crawlink.com/authorize?client_id=YOUR_APP&redirect_uri=https://your.app/calendarbook/callback&state=RANDOMExchange the code from your server, with your client secret, within ten minutes. You get one key per organization — shown once, like any key — and use them on the endpoints above.
curl -X POST "https://calendarbook.crawlink.com/api/connect/token" \
-H "Content-Type: application/json" \
-d '{ "client_id": "YOUR_APP", "client_secret": "YOUR_SECRET", "code": "CODE_FROM_CALLBACK" }'{
"orgs": [
{ "id": "01M2…", "name": "Sunrise Clinic", "slug": "sunrise-clinic",
"timezone": "Asia/Kolkata", "currency": "INR", "apiKey": "ck_01M2…" }
],
"apiBase": "https://calendarbook.crawlink.com/api/v1"
}A cancelled consent returns to your redirect_uri with error=access_denied. Each
organization sees the connection in its API keys with a "Connected app" badge and can revoke it there.
Registering an application — its id, return addresses and secret — is done by us; write to us with those details.
Something here does not match what you see in the app? Tell us — a person reads every message.