Loading endpoint details...
Book appointment.
/api/v1/calendars/appointmentsBrowse API endpoints
Conversations
Contacts
Calendar and booking
Calendar and booking / CRM REST API
/api/v1/calendars/appointmentsCalendar and booking / CRM REST API
Loading endpoint details...
Scope: appointments:write
Request body:
| Field | Required | Description |
|---|---|---|
appointmentTypeId | Yes | Type of appointment to book |
startTime | Yes | Start time (Unix timestamp, milliseconds) |
endTime | Yes | End time (Unix timestamp, milliseconds) |
firstName | Yes | Booker's first name |
lastName | Yes | Booker's last name |
email | Yes | Booker's email |
phone | No | Booker's phone |
notes | No | Additional notes |
Behavior:
appointment.booked webhook eventSend startTime and endTime exactly as the availability endpoint returned them. When a booking is refused, error.details.reason carries a stable token you can branch on (slot_unavailable, invalid_duration, outside_hours, day_unavailable, date_unavailable, day_full, slot_in_past, too_soon, too_far_ahead); read that rather than the message, which is written for a person.
Store the id from the response. Reading a booking back from GET /api/v1/calendars/appointments needs appointments:read, the scope that also returns every customer's contact details, so a key scoped only for booking deliberately cannot list its own appointments. Keep the id (and the startTime / endTime you sent) at your end; cancelling later needs that id too.