Scheduling & conference calls
const scheduling = client.site(siteId).scheduling
Previously this lived on a separate SDK surface, which is why it never appeared
in openapi.json and no non-JavaScript starter had it. It is now on the main
client, so every framework binding and every starter reaches it the same way.
Booking
const { eventTypes } = await scheduling.listEventTypes()
const { eventType, questions } = await scheduling.getEventType('discovery-call')
const { slots } = await scheduling.getAvailableSlots('discovery-call', {
from: new Date(),
to: addDays(new Date(), 14),
})
const booking = await scheduling.confirmBooking({
eventTypeSlug: 'discovery-call',
startAt: slots[0].startAt,
invitee: { name, email, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone },
})
Ask for the window you're about to render, not the whole month. Slot computation walks every host's calendar and busy times, so a wide range is a slow one.
confirmBooking returns pending rather than confirmed when the event
type requires approval. Say "requested" in the UI for that case — telling
someone their meeting is booked when staff still have to accept it is the kind
of thing they plan a day around.
Three tokens, not one
A confirmed booking yields manageToken, rescheduleToken and cancelToken
separately. That is deliberate: a cancel link in an email must not also be
able to reschedule, and neither should be able to read the whole booking. One
token for all three would make every emailed link as powerful as the strongest
thing it enables.
getBooking(token, type) requires the type to match the token you hold.
Both sides can reschedule and cancel
// Invitee — with the token from their email
await scheduling.rescheduleBooking({ token, newStartAt, reason })
await scheduling.cancelBooking({ token, reason })
// Staff — with the API key
await scheduling.rescheduleBookingAsStaff({ bookingId, newStartAt, actorUserId })
await scheduling.cancelBookingAsStaff({ bookingId, reason, actorUserId })
Both paths call the same service, which is what keeps the two sides honest:
- the invitee and every host are notified either way;
- the reminder jobs queued against the old time are cancelled either way, so nobody gets "your meeting starts in 15 minutes" for a slot that moved;
- the booking records which side made the change.
actorUserId on the staff calls is what lets a customer's history say "they
rescheduled" rather than leaving an unexplained change. A cancellation with no
actor is the kind of thing that turns into an argument later.
Staff calls need the scheduling:write scope, which maps to the same
scheduling.manage permission the dashboard requires. It is deliberately not
publishable — a browser token able to cancel any booking by id would let
anyone reading the page source cancel every meeting the org has.
reason on a cancellation reaches the hosts. Worth collecting: "something came
up" and "I booked the wrong service" lead to different follow-ups, and the
second is recoverable revenue.
The conference link
Event types with a meetingProvider mint a conference URL on confirmation.
Rescheduling can re-mint the link. Read conferenceLink back from the
reschedule result rather than reusing the one from confirmation — otherwise
the calendar invite you send points at a dead room.
Non-JavaScript starters
All six carry the same surface: scheduling(siteId) on Swift, Kotlin, Dart and
Vapor, scheduling($siteId) on Laravel, and
BdStarter.Bd.Resources.Scheduling on Phoenix — including both the
invitee-token and staff paths.