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.

Base URL
https://calendarbook.crawlink.com/api/v1

Getting a key

  1. Sign in as an Admin or the Owner and open Settings → API keys.
  2. 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.
  3. 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.

Header
Authorization: Bearer ck_<organization>_<secret>

Scopes

ScopeAllows
calendars.readRead calendars — List calendars and locations.
availability.readRead availability — Ask which times are free on a given day.
bookings.readRead bookings — List and read bookings, including customer contact details.
bookings.writeCreate and change bookings — Take new bookings and move existing ones.
bookings.cancelCancel bookings — Cancel a booking. Separate from writing, because it is destructive.
bookings.overrideBook outside opening hours — Ignore opening hours and slot boundaries. Only for systems recording walk-ins.
customers.readRead customers — List and read the customer directory.
customers.writeCreate and change customers — Add customers and edit their details.

Endpoints

CallScopeWhat it does
GET /healthcalendars.readConfirms the key works and reports its organization and what it may do.
GET /calendarscalendars.readCalendars and locations, with the slot length, gaps and notice each one enforces.
GET /availabilityavailability.readFree times for one calendar: calendarId, date (YYYY-MM-DD), days (1–31) and partySize.
GET /bookingsbookings.readBookings from–to (default today to 60 days ahead), filtered by calendarId, status, search, phone or googleEventId; page and pageSize (up to 200).
POST /bookingsbookings.writeTakes a booking through the same availability engine the app uses.
GET /bookings/{id}bookings.readOne booking.
PATCH /bookings/{id}bookings.writeMoves 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.cancelCancels it, with an optional ?reason=. The record is kept.
GET /customerscustomers.readThe customer directory: search, page, pageSize.
POST /customerscustomers.writeCreates a customer (name, phone, email, notes, tags), or updates one when id is given.

Finding free times

Shell
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

Shell
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, start and customerName are required.
  • start takes "18:30" or minutes from midnight.
  • Optional: durationMinutes, partySize, customerPhone, customerEmail, customerId, notes, and status: "pending" to hold it for approval (the default is confirmed).
  • force books outside the usual rules and needs the bookings.override scope — 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.

JSON
{
  "error": {
    "code": "slot_unavailable",
    "message": "That time is already booked. Please pick another time."
  }
}
CodeStatusMeaning
missing_key401No key was sent.
invalid_key401Unknown, revoked or expired.
missing_scope403The key lacks the scope for this call.
out_of_scope403The key is limited to other calendars.
not_found404No such booking or calendar.
slot_unavailable409The time is no longer free.
rate_limited429Too many requests this minute.
invalid_body400The 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.

Send the person to
https://calendarbook.crawlink.com/authorize?client_id=YOUR_APP&redirect_uri=https://your.app/calendarbook/callback&state=RANDOM

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

Shell
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" }'
Response
{
  "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.