Booking Pages
Booking pages are public, agent-created scheduling links — a hosted booking flow
provisioned entirely by agents through the API. An agent creates a page for one of its
calendars, sends the hosted URL to a human, and when the human picks a slot the
booking lands on the agent’s calendar as a confirmed event and an event.created
webhook fires (carrying a booking_page_id correlation field). Every hosted page
is “Powered by Chronary”.
What you’ll accomplish
Section titled “What you’ll accomplish”Create a booking page, share its hosted link, let a human book a slot, and receive the resulting event + webhook. You’ll also learn how to restrict bookable hours and how slots are computed.
Prerequisites
Section titled “Prerequisites”- A Chronary account with an API key
- A calendar to receive bookings (see the Calendars guide)
Create a booking page
Section titled “Create a booking page”The page is bound to a calendar_id. Optional fields tune the bookable slots:
duration_minutes (default 30), buffer_minutes (padding around existing events),
window_days (how far ahead bookings are allowed, default 14), min_notice_minutes
(minimum lead time), timezone, and availability_constraints (weekly working hours).
curl -X POST https://api.chronary.ai/v1/booking-pages \ -H "Authorization: Bearer chr_sk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "calendar_id": "cal_your_calendar", "title": "Intro call", "description": "A 30-minute intro chat.", "duration_minutes": 30, "window_days": 14, "availability_constraints": { "mon": { "start": "09:00", "end": "17:00" }, "tue": { "start": "09:00", "end": "17:00" }, "wed": { "start": "09:00", "end": "17:00" }, "thu": { "start": "09:00", "end": "17:00" }, "fri": { "start": "09:00", "end": "17:00" } } }'import Chronary from '@chronary/sdk';
const chronary = new Chronary({ apiKey: process.env.CHRONARY_API_KEY });
const page = await chronary.bookingPages.create({ calendar_id: 'cal_your_calendar', title: 'Intro call', duration_minutes: 30, window_days: 14,});
console.log(page.booking_url); // → https://api.chronary.ai/book/<slug>from chronary import Chronary
chronary = Chronary(api_key="chr_sk_your_key_here")
page = chronary.booking_pages.create( calendar_id="cal_your_calendar", title="Intro call", duration_minutes=30, window_days=14,)print(page.booking_url)chronary booking-pages create \ --calendar cal_your_calendar \ --title "Intro call" \ --duration 30 --window-days 14Tool: create_booking_page{ "calendar_id": "cal_your_calendar", "title": "Intro call", "duration_minutes": 30 }→ returns booking_url to share with a humanThe response includes a slug and a booking_url (https://api.chronary.ai/book/<slug>).
The slug is an unguessable token — anyone holding the URL can view and book, so treat
it like a secret address (the same model as an iCal feed URL).
The hosted page
Section titled “The hosted page”Open the booking_url in a browser and you get a server-rendered scheduling page:
the visitor picks a day and time, enters their name and email, and confirms. No
login, no JavaScript required. On confirmation Chronary creates a confirmed event
on the bound calendar and shows the visitor a confirmation screen.
Programmatic booking (JSON)
Section titled “Programmatic booking (JSON)”You can also drive the flow yourself — e.g. to embed a custom booking widget. Both endpoints are public (no API key; the slug is the credential).
List available slots:
curl https://api.chronary.ai/book/<slug>/slots{ "booking_page": { "slug": "<slug>", "title": "Intro call", "duration_minutes": 30, "timezone": "UTC" }, "slots": [ { "start": "2026-07-15T16:00:00.000Z", "end": "2026-07-15T16:30:00.000Z" }, { "start": "2026-07-15T16:30:00.000Z", "end": "2026-07-15T17:00:00.000Z" } ]}Submit a booking:
curl -X POST https://api.chronary.ai/book/<slug> \ -H "Content-Type: application/json" \{ "booking_page_id": "bkp_...", "event": { "id": "evt_...", "title": "Intro call — Ada Lovelace", "start_time": "...", "end_time": "...", "status": "confirmed" } }Reacting to bookings with webhooks
Section titled “Reacting to bookings with webhooks”A booking fires the standard event.created webhook, plus a booking_page_id
field so you can tell inbound bookings apart from events created via the API:
{ "type": "event.created", "data": { "calendar_id": "cal_your_calendar", "booking_page_id": "bkp_...", "event": { "id": "evt_...", "title": "Intro call — Ada Lovelace", "status": "confirmed", ... } }}Subscribe a webhook to event.created (see the Webhooks guide)
and branch on booking_page_id to run your post-booking workflow. Invitee name,
email, and notes are stored in the event’s metadata.
How slots are computed
Section titled “How slots are computed”Available slots are the calendar’s free time, sliced into fixed-length slots of
duration_minutes, within [now + min_notice_minutes, now + window_days]. Chronary
subtracts:
- existing events on the calendar (any non-cancelled status),
- recurring-series occurrences,
- connected human-calendar busy time (if the calendar’s agent has a Google or Microsoft connection), and
- time outside
availability_constraintsworking hours (when set),
then pads existing events by buffer_minutes on each side. Omit
availability_constraints to make any free time inside the window bookable.
Manage booking pages
Section titled “Manage booking pages”curl https://api.chronary.ai/v1/booking-pages \ -H "Authorization: Bearer chr_sk_your_key_here"curl -X PATCH https://api.chronary.ai/v1/booking-pages/bkp_xxx \ -H "Authorization: Bearer chr_sk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "active": false }'curl -X DELETE https://api.chronary.ai/v1/booking-pages/bkp_xxx \ -H "Authorization: Bearer chr_sk_your_key_here"Setting active: false (or deleting) stops the hosted URL from resolving.
Already-booked events are unaffected.
Plan limits
Section titled “Plan limits”Booking pages are available on every plan. Free includes 1 booking page; Pro includes 25; Custom is unlimited. Each booking creates an event, so booking volume counts toward your monthly events quota.