Endpoint reference

Calendar booking endpoints

Booking settings, booking types, open times, offers and booking a picked time through the workspace's Cal.com or Calendly.

These endpoints run calendar booking. Every route answers 503 booking_disabled while the instance has it off. Gates and scopes are in the scope map; error codes are under calendar booking refusals.

Settings

GET /booking/settings returns {settings}: mode (off, draft), chase_max_touches, chase_window_days, usable_types, and missing, which lists for each mode what it still needs.

PUT /booking/settings takes any of {mode, chase_max_touches, chase_window_days}. mode is off or draft; auto answers 403 booking_auto_send_required. Leaving off checks every booking type with its provider.

POST /booking/auto takes no body. It answers 409 booking_auto_unavailable with details.reasons while automatic booking cannot run.

GET /booking/summary returns {summary: {open, needs_you, booked_30d, median_first_response_seconds}}.

Booking types

GET /booking/profiles returns data plus pagination. Each type has id, name, connection_id, provider, event_type_ref, event_type_name, duration_minutes, scheduling_url, is_default, campaign_id, locale, slots_per_offer, min_notice_minutes, horizon_days, prospect_hours_start, prospect_hours_end, status (unchecked, ok, plan_required, reauth_required, event_type_missing), status_detail and can_lookup.

POST /booking/profiles takes {connection_id, event_type_ref} and any of the offer rules. The event type is read from the provider; one with blockers answers 400 booking_event_type_unsupported. Send an Idempotency-Key.

PATCH /booking/profiles/:id changes the offer rules. A campaign_id on either write must belong to the workspace, or the call answers 404. DELETE /booking/profiles/:id answers 409 booking_attempt_in_flight while a booking on the type is being confirmed.

GET /booking/connections/:id/event-types returns data: ref, name, duration_minutes, scheduling_url, video_location, blockers and can_lookup.

Open times

GET /booking/availability?thread_id=&contact_id=&profile_id=&timezone=&limit= returns {profile_id, timezone, timezone_source, slots: [{start_at, end_at, label}]}, read live from the provider with the booking type's minimum notice applied.

Offers

GET /booking/offers?status=&thread_id=&contact_id=&campaign_id=&limit=&cursor= returns data plus pagination. GET /booking/offers/:id returns {offer, slots, events}; each event carries kind, decided_by, confidence and evidence, the words a decision rests on.

POST /booking/offers with {thread_id, profile_id?, timezone?, slot_starts?} returns {offer, block, slots}. It sends nothing. Put the block in a reply; the offer becomes offered when that reply is sent with every time in it.

POST /booking/offers/:id/book with {slot_id} or {start_at} and send_confirmation books on the provider for the contact's stored address:

{
  "meeting": { "id": "...", "scheduled_for": "2026-11-10T14:30:00Z", "join_url": "https://..." },
  "offer": { "id": "...", "status": "booked" },
  "confirmation": { "id": "...", "status": "pending" }
}

A 202 with outcome: "unknown" means the provider's answer is being confirmed by lookup; nothing is posted again. 409 booking_slot_taken carries alternatives, already written into a draft. One booking runs per offer at a time: another while it is being confirmed answers 409 booking_attempt_in_flight.

POST /booking/offers/:id/stop, /resume and /pick/reject move the offer and return {offer}.

Booking access

PUT /integrations/connections/:id/booking-credential with {api_key, base_url} checks the key with the provider and stores it sealed. The response is {connection, booking_access, account}, where account is {name, email, can_book, can_lookup, admin}. The key is never returned.

On this page