Skip to main content
Booking is the one thing a voice agent does that needs somewhere to put the appointment. A sub-account with GoHighLevel books into a GHL calendar. A sub-account without one books into a Team Follow Up calendar, described here. The two are the same shape. Availability comes back as days of start times either way, and a booking answers with the time it actually took, so an integration written against one reads the other unchanged.

What a calendar is

A calendar is a bookable resource with hours and rules. A sub-account can have several, and a campaign names the one its agent books into. In the dashboard, open Calendars and pick a calendar. These settings are Opening hours, Appointment length, Start every, Buffer between, Bookings per slot, Minimum notice (minutes), How far ahead (days) and Dated exceptions.
Hours are validated as a whole. A window that ends at or before it starts is refused rather than wrapped past midnight, because a slot that crossed midnight would land under a different date than anyone expects. A calendar with no hours, or an appointment longer than a window, is saved but offers nothing there, so check it with Preview slots below.

Creating one

Try a definition before you save it with Preview slots: it validates the definition and returns the slots it would offer. Pass an existing calendarId as well and what is already booked is counted, so the preview shows what would really be left.

Slots and seats

Free slots answers day by day:
It is computed per request against live bookings and is never cached, because a cached slot is one somebody else may already have taken. A slot holds as many seats as appointmentsPerSlot. confirmed and showed occupy a seat; cancelled and noshow free it. A past appointment that happened keeps its seat, so a second booking can never land on a slot that was genuinely used.

Booking

Three things are worth knowing before you write the call:
  • startTime without an offset is read in the calendar’s zone. Epoch milliseconds and a full ISO instant are both accepted and are unambiguous. A bare 2026-09-24T15:00:00 is read as 15:00 where the calendar lives, which is usually what you meant.
  • The seat is checked, then claimed as the booking is written, so two callers racing for the last seat cannot both win. The loser gets 409 with a message that every seat on the slot is taken. A time outside the hours, inside the notice window or past the lookahead also gets 409, with a message saying why.
  • Read bookedStartTime from the response rather than assuming the time you asked for is the time it took.
Two people try to book the last seat at Tuesday 10:00 at the same moment. One is booked; the other is told the time is taken. Two people try to book the last seat at Tuesday 10:00 at the same moment. One is booked; the other is told the time is taken. On a call, the agent tells the second caller that time was just taken and offers others. Booking ends any chase that contact was in, exactly as when an agent books them on a call, and starts the confirmation campaign on that calendar. Rescheduling claims the new time the same way and only gives up the old seat once the new one is held. The reminders that belonged to the old time are re-anchored to the new one rather than left pointing at a time that has passed.

Time that is not a booking

An event is an entry with no contact: a meeting, a reminder, an hour held back. It carries no lead, starts no campaign and tells nobody. What it does do is occupy the seats it covers, so the agent stops offering that time.

Retiring a calendar

A delete refuses while people still have appointments on it, answering 409 with upcomingCount, so a calendar cannot quietly strand everyone who booked. force=true goes ahead and cancels them, and cancelling a booking tells the attendee.

Calendars that live somewhere else

A sub-account can connect a calendar product it already uses, such as Cal.com. List connections says which calendar systems can be connected, how each one is connected, and whether this sub-account has done it.
1

Paste the credential

Connect a calendar system checks the key with that product first, then stores it in token mode. A key the product refuses is not saved and answers CalendarKeyRefused. If the product cannot be reached, nothing is saved either and the answer is CalendarKeyCheckUnavailable, so try again in a minute.
2

Cancellations are registered at connect time

A cancellation made in that product reaches us only because the connection registered for it, with a webhook in that product. cancellations in the answer says how that went: watched when registered, pending while it is still being tried, failed with the reason in cancellationsError, or unsupported. Reconnect the system if it is not watched.
3

Read, never write

Their calendars and bookings are read through their own API and shown beside yours. Nothing here writes into that product, because the calendar is managed there.
A reconnect replaces the stored key, and the old one is gone. The webhook registered under the old key is removed first; if that fails, it is tried again with the new key. One that neither key can remove stays in your account in that product until you remove it there, and what it sends is refused.

Where to go next

Why the agent found nothing

The two settings behind almost every empty diary.

Native Calendar API

Every operation, with schemas and examples.