Bookings
Create a booking
Books a slot on one of your booking pages. Fetch the slots first and send the chosen slot's start and end unchanged. On a direct page the booking is confirmed straight away: the guest gets a confirmation email, the host is notified, and if the page creates Meet links a Google Calendar event is added and Google invites the guest. On an approval page the booking is pending: the host gets a request email and the guest hears nothing until the host confirms it with PATCH /bookings/{id}. With a publishable key, the start and end must match a slot that List open slots offers right now (future, inside the host's hours, within max_days_ahead), because anyone can copy that key from your page. A secret key, which only your server holds, can book any time that doesn't overlap another pending or confirmed booking, even outside the host's hours. One guest email address gets 5 booking attempts per clock hour. Scope: bookings:create. Keys: secret and publishable.
/bookingscreateBookingAuthorizations
bearerAuthhttp (bearer)Authorization: Bearer clndr_sk_… (secret) or clndr_pk_… (publishable).
apiKeyHeaderapiKeyThe same key in a custom header, for clients that can't set Authorization.
Server
https://www.clndr.pro/api/v1Production
Request Body
Content-Type: application/jsonrequired
id of one of your booking pages.
Confirmation emails go here.
A slot's start, unchanged.
The same slot's end.
Responses
201The new booking. It doesn't include the guest's answers; read them with Get a booking.application/json
400A required field is missing, the body isn't JSON, guestEmail isn't an email address, the timestamps don't parse or end before they start, or responses isn't an array.application/json
What went wrong, in plain English.
401The key is missing, unknown, revoked or expired.application/json
What went wrong, in plain English.
403The key lacks bookings:create, or bookingPageId belongs to another account.application/json
What went wrong, in plain English.
409The slot can't be booked. With a publishable key the time isn't an open slot ("This time slot is not available. Fetch the slots again and pick another."); with any key, another booking got there first ("This time slot is no longer available. Please pick another."). Fetch the slots again and let the guest pick another.application/json
What went wrong, in plain English.
429Either the key's per-minute rate limit (with Retry-After and X-RateLimit headers), or this guest email has used its 5 booking attempts for the current clock hour ("Too many booking requests. Please try again later.", no headers; resets at the top of the hour).application/json
What went wrong, in plain English.
500Creating the booking failed on our side ("Failed to create meeting" or "An unexpected error occurred"). Check with List bookings whether it exists before you retry.application/json
What went wrong, in plain English.
curl https://www.clndr.pro/api/v1/bookings \
--request POST \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"bookingPageId": "8b6f2c1e-4a1d-4f0b-9a63-2f0c5d7e9b14",
"guestName": "Grace Hopper",
"guestEmail": "grace@example.com",
"startTime": "2026-10-15T08:40:00.000Z",
"endTime": "2026-10-15T09:10:00.000Z",
"responses": [
{
"questionId": "0e4b7a2c-9d1f-4b3e-a6c8-5f2d1e9b7c40",
"answer": "Moving our sales demos onto clndr.pro."
}
]
}'fetch('https://www.clndr.pro/api/v1/bookings', {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
bookingPageId: '8b6f2c1e-4a1d-4f0b-9a63-2f0c5d7e9b14',
guestName: 'Grace Hopper',
guestEmail: 'grace@example.com',
startTime: '2026-10-15T08:40:00.000Z',
endTime: '2026-10-15T09:10:00.000Z',
responses: [
{
questionId: '0e4b7a2c-9d1f-4b3e-a6c8-5f2d1e9b7c40',
answer: 'Moving our sales demos onto clndr.pro.'
}
]
})
})requests.post("https://www.clndr.pro/api/v1/bookings",
headers={
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
},
json={
"bookingPageId": "8b6f2c1e-4a1d-4f0b-9a63-2f0c5d7e9b14",
"guestName": "Grace Hopper",
"guestEmail": "grace@example.com",
"startTime": "2026-10-15T08:40:00.000Z",
"endTime": "2026-10-15T09:10:00.000Z",
"responses": [
{
"questionId": "0e4b7a2c-9d1f-4b3e-a6c8-5f2d1e9b7c40",
"answer": "Moving our sales demos onto clndr.pro."
}
]
}
)fetch('https://www.clndr.pro/api/v1/bookings', {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
bookingPageId: '8b6f2c1e-4a1d-4f0b-9a63-2f0c5d7e9b14',
guestName: 'Grace Hopper',
guestEmail: 'grace@example.com',
startTime: '2026-10-15T08:40:00.000Z',
endTime: '2026-10-15T09:10:00.000Z',
responses: [
{
questionId: '0e4b7a2c-9d1f-4b3e-a6c8-5f2d1e9b7c40',
answer: 'Moving our sales demos onto clndr.pro.'
}
]
})
}){
"data": {
"id": "c3a7e5d1-2b9f-4c6e-8a1d-7f4b0e2c9a58",
"booking_page_id": "8b6f2c1e-4a1d-4f0b-9a63-2f0c5d7e9b14",
"user_id": "5d2e9f40-7c1b-4e8a-b0d6-3a9f1c2e8d77",
"guest_name": "Grace Hopper",
"guest_email": "grace@example.com",
"start_time": "2026-10-15T08:40:00+00:00",
"end_time": "2026-10-15T09:10:00+00:00",
"status": "confirmed",
"cancellation_reason": null,
"reminder_sent": false,
"google_meet_link": "https://meet.google.com/abc-defg-hij",
"google_calendar_event_id": "6v1m0r2k8f3t5q9b7n4c",
"google_calendar_id": "primary",
"sync_status": "synced",
"last_synced_at": "2026-10-10T12:31:07.481+00:00",
"sync_failure_reason": null,
"created_at": "2026-10-10T12:31:05.902+00:00",
"updated_at": "2026-10-10T12:31:07.481+00:00"
}
}{
"error": "`guestEmail` must be a valid email address"
}{
"error": "Missing API key. Send `Authorization: Bearer <key>` or `x-clndr-key` header."
}{
"error": "This booking page does not belong to the API key owner"
}{
"error": "This time slot is not available. Fetch the slots again and pick another."
}{
"error": "Too many booking requests. Please try again later."
}{
"error": "Failed to create meeting"
}