How booking works

Four things make up every booking: a booking page (what can be booked), the host's availability (when), the slots clndr.pro derives from those two, and the booking a guest makes in one of them. This page explains each one well enough that the API's answers stop surprising you.

Booking pages

A booking page is one bookable meeting type: "30-minute intro call", "Portfolio review". Hosts create them under Booking pages in the dashboard, and the API can read them but not create or edit them.

FieldDashboard labelWhat it does
slugLinkIdentifies the page in URLs and API paths. Unique per account.
duration_minutesDuration (minutes)The length of every slot, 1 to 480.
booking_typeConfirmationdirect (Instant) or approval (Needs approval). See Booking types.
buffer_time_minutesBuffer time between bookingsThe gap between one generated slot and the next.
max_days_aheadBookable up toHow far out guests can book. Later days have no slots.
visibilityPage Visibilitypublic, private or team. See Private and team pages.
availability_set_idHoursWhich of the host's schedules applies. Empty means all of them.
auto_generate_meet_linkAdd a Google Meet linkConfirmed bookings get a Google Calendar event with a Meet link.
show_on_profileList on your public profileLists the page at www.clndr.pro/{username}.
is_activeInactive pages still appear in List booking pages, but can't be fetched, have no slots and can't be booked.

description is Markdown the host writes. Render it as Markdown: the React components already do.

Availability

A host's availability is a set of weekly rules: "Monday 09:00–12:00", "Monday 14:00–17:30", "Thursday 09:00–12:00". A day can have several windows. Hosts can keep several sets (say "Office hours" and "Evenings") and point each booking page at one of them, or at none, in which case every set counts.

The times are wall-clock times in the host's timezone, the timezone on their profile (an IANA name such as Europe/London). "09:00" means 09:00 where the host is, through daylight-saving changes. There are no one-off exceptions or holidays yet; a host blocks a day by putting an event in their calendar.

Slots

List open slots returns the slots a guest can book on one day. clndr.pro builds them like this:

  1. Take the host's calendar day for the date you asked for. date=2026-10-15 means 15 October in the host's timezone.
  2. For each availability window that day, place a slot at the window's start, then the next one duration_minutes + buffer_time_minutes later, until a slot would run past the window's end.
  3. Drop slots that overlap a pending or confirmed booking, or an event on the host's calendar. Google Calendar events count once they've synced into clndr.pro. Only events that start and end within that day are checked, so an overnight or multi-day event doesn't block the day.
  4. Drop slots that have already started, and return nothing at all for days past max_days_ahead.

Every slot comes back as a UTC start and end:

{ "data": [{ "start": "2026-10-15T08:00:00.000Z", "end": "2026-10-15T08:30:00.000Z" }] }

To book one, send start and end back unchanged as startTime and endTime.

Timezones, worked through

The host is in London, with Thursday availability 09:00–12:00 and a 30-minute page with a 10-minute buffer. On Thursday 15 October 2026 London is on summer time, UTC+1.

Slot (host, London)start (UTC)Guest in New York (UTC−4)Guest in Tokyo (UTC+9)
09:00–09:3008:00Z04:00 Thu17:00 Thu
09:40–10:1008:40Z04:40 Thu17:40 Thu
10:20–10:5009:20Z05:20 Thu18:20 Thu
11:00–11:3010:00Z06:00 Thu19:00 Thu

The next slot would be 11:40–12:10, which runs past 12:00, so there isn't one.

Now move the window to 15:00–17:00 London. The last slots are 23:00 and 23:40 Thursday for the Tokyo guest, and 00:20 Friday. One call for the host's Thursday returned a slot on the guest's Friday. Two rules keep this sane in your UI:

  • Format every time in the guest's timezone (Intl.DateTimeFormat with no timeZone, or toLocaleTimeString(), does that in a browser).
  • If you show a calendar in the guest's time, group slots by their local date rather than by the date you requested. For a full week, request each day and merge the results.

Bookings

A booking is a guest's claim on a slot. Create one with Create a booking, from a publishable or a secret key. clndr.pro checks that the time doesn't overlap another pending or confirmed booking for the host. A taken time fails with 409; fetch the slots again and let the guest pick another.

A publishable key can only book a slot the slots endpoint is offering right now: anyone can copy that key out of your page, so a booking made with it must be in the future, inside the host's hours, within max_days_ahead, at the page's duration. When it isn't (a taken slot included), the message is This time slot is not available. Fetch the slots again and pick another. A secret key, which only your server holds, can book any time that doesn't overlap another booking; a taken time there reads This time slot is no longer available. Please pick another.

One guest email address gets five booking attempts per clock hour (429 past that; it resets at the top of the hour).

Booking types

Booking lifecycle

Direct pages (Instant in the dashboard) confirm on the spot. The guest gets a confirmation email from clndr.pro, the host gets a new-booking email, and if the page auto-generates Meet links, a Google Calendar event is created on the host's calendar and Google sends the guest an invite.

Approval pages create a pending booking. The host gets a booking-request email. The guest gets nothing yet, so tell them in your UI that their request was sent, not that they're booked. The slot is held: no one else can book it while it's pending.

The host then confirms or declines, in the dashboard under Meetings or through Confirm or cancel a booking. The two paths notify differently:

DashboardAPI (PATCH / DELETE)
ConfirmConfirmation email to the guest, plus the Google event and Meet link if enabledGoogle event and Meet link if enabled (Google sends the invite); no clndr.pro email
CancelCancellation email to the guest; the Google event is deletedThe Google event is deleted and Google tells the guest; no clndr.pro email

If you confirm or cancel through the API on a page without Meet links, nobody hears about it unless you email the guest yourself. clndr.pro doesn't send reminder emails yet.

Google Calendar status

sync_status on a booking records whether its Google Calendar event was created: synced, failed (with the reason in sync_failure_reason, often Google Calendar is not connected), or not_synced when no event was needed. It's written when the guest books and when the host confirms or cancels in the dashboard. Confirming or cancelling through the API (PATCH, DELETE) doesn't update it, so after those, look at google_calendar_event_id and google_meet_link instead. A failed Google call never blocks the booking itself.

Questions and answers

Each page can ask guests questions, returned with the page by Get a booking page, in order_index order.

question_typeRender as
textA single-line text input
emailAn email input
phoneA tel input
textareaA multi-line text area
selectA dropdown of options
checkboxA checkbox; send its answer as text, such as Yes

The dashboard creates the first four; select and checkbox exist in the data model for pages set up other ways.

Send answers as responses: [{ questionId, answer }], with every answer as a string. Two things the API leaves to you: it doesn't reject a booking that skips a question marked is_required, so enforce that in your form; and every questionId must belong to the page, because one unknown id means none of that booking's answers are saved. Only send ids from the page you fetched.

Private and team pages

visibility controls who can open the hosted page at www.clndr.pro/{username}/{slug}:

  • public: anyone with the link.
  • private: visitors need an access code. With Ask visitors for a code on, the page asks for one; with it off, the page looks like it doesn't exist. Hosts create codes on the page's edit screen. They look like K7Q2-M9XD-4TPA-8WNE, are case-insensitive, and expire after a period you choose. A link with the code (?c=K7Q2-M9XD-4TPA-8WNE) opens the page directly.
  • team: only signed-in members of the chosen team can book.

These checks protect the hosted page and the embeds. API keys skip them, because a key acts as the page's owner: it lists, reads and books private and team pages like any other. See Choose an integration for what that means for your site.