# Scheduling Bookings

Create, manage, and check availability for bookings. Bookings link to an opportunity via deal_id (field name preserved for backward compatibility) and surface in the Meetings card on the opportunity page. Scheduler bookings are separate from the opportunity's next_action_* fields, which are for ad-hoc reminders only. AI-agent-friendly: human-readable responses, self-correcting errors with alternatives, nearest-slot suggestions. Includes voice-optimised endpoints (text/plain responses) designed for Retell AI voice agents.

**Base URL:** `https://api.trustpager.com/functions/v1/api/v1`

## Endpoints

### GET /scheduling-bookings

List bookings with filters. Returns upcoming/past bookings sorted by start time. Includes management_token and management_token_expires_at for each booking (null on bookings created before self-service management was introduced).

**Scopes:** `company:read` — [full detail](./scheduling-bookings/get-scheduling-bookings.md)

### GET /scheduling-bookings/:id

Get a single booking by ID with full details including linked event type name. Returns management_token (UUID used to construct the self-service management URL: https://app.trustpager.com/book/{company_slug}/manage/{management_token}) and management_token_expires_at (set to 24 hours after the booking end time; null on old bookings). The management token is NOT returned in create responses -- it is delivered to the booker only via the Google Calendar invite description and booking reminder emails using the {management_url} template variable.

**Scopes:** `company:read` — [full detail](./scheduling-bookings/get-scheduling-bookings-id.md)

### POST /scheduling-bookings

Create a booking. Auto-creates CRM opportunity + contact (response field names like deal_id are preserved for backward compatibility). Flat request body (no nested objects). Email format is validated before slot logic runs -- malformed addresses (missing TLD, no domain) return INVALID_EMAIL; invalid attendee emails return INVALID_ATTENDEE_EMAIL. On slot conflict, returns SLOT_UNAVAILABLE error with nearest alternatives. Accepts event type by ID, slug, or name.

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings.md)

### POST /scheduling-bookings/:id/cancel

Cancel a booking. Updates status, removes Google Calendar event (notifies all attendees), and cancels pending reminders. Does not affect the opportunity's next_action fields (bookings and next_action are independent).

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings-id-cancel.md)

### POST /scheduling-bookings/check-availability

Quick check if a specific date/time slot is available. Always returns nearest_before and nearest_after slots -- perfect for conversational booking flows.

**Scopes:** `company:read` — [full detail](./scheduling-bookings/post-scheduling-bookings-check-availability.md)

### POST /scheduling-bookings/available-slots

Get all available time slots for a date range. Returns slots grouped by date with human-readable formatting. Integrates with Google Calendar freebusy to block busy times.

**Scopes:** `company:read` — [full detail](./scheduling-bookings/post-scheduling-bookings-available-slots.md)

### POST /scheduling-bookings/:id/mark-attended

Mark a booking as attended. Sets status to "attended", clears the linked opportunity's next action, cancels pending reminders, and logs a CRM activity with full booking context.

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings-id-mark-attended.md)

### POST /scheduling-bookings/:id/mark-late

Mark a booking as late. Sets status to "late", sends late notifications to the booker (if configured on the event type), and logs a CRM activity.

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings-id-mark-late.md)

### POST /scheduling-bookings/:id/mark-no-show

Mark a booking as no-show. Sets status to "no_show", sends no-show notifications, schedules rebooking reminders (if configured), and logs a CRM activity.

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings-id-mark-no-show.md)

### POST /scheduling-bookings/:id/notetaker

Attach the TrustPager Notetaker to an existing confirmed booking. The bot joins 60 seconds before the meeting start time, transcribes with speaker attribution, and writes the transcript to the linked CRM opportunity. Idempotent -- safe to call multiple times (returns already_scheduled: true if already registered). Requires: (1) TrustPager Notetaker enabled in company settings, (2) booking must have a google_meet_link, (3) booking must not be cancelled. Credits: 23 credits per recorded minute, billed after the meeting ends.

**Scopes:** `company:write` — [full detail](./scheduling-bookings/post-scheduling-bookings-id-notetaker.md)

### POST /scheduling/voice/:event_type_id/slots

Voice-agent slot picker. Returns text/plain — a human-readable listing of available slots with a header block showing event type name, duration, host names, and description. Designed to be consumed verbatim by a Retell AI voice agent as a custom tool response. The AI never sees raw JSON or date ranges — just readable text it can speak directly. Slots are tagged with exact booking keys (slot:"YYYY-MM-DD HH:MM") for use in the /book endpoint.

**Scopes:** `scheduling:read` — [full detail](./scheduling-bookings/post-scheduling-voice-event-type-id-slots.md)

### POST /scheduling/voice/:event_type_id/book

Voice-agent booking confirmation. Returns text/plain — a plain English sentence the AI reads to the caller to confirm the appointment. On success, includes event type name, duration, formatted start/end time, host names, description, Google Meet link, and booking ID. On failure, always returns HTTP 200 with a bolded warning the AI must not ignore — prevents the AI from falsely confirming a booking that failed. Supports Retell custom tool format: {"call":{...},"name":"tool_name","args":{...}}.

**Scopes:** `scheduling:write` — [full detail](./scheduling-bookings/post-scheduling-voice-event-type-id-book.md)

### POST /scheduling/voice/cancel-booking

Voice-agent booking cancellation. Returns text/plain. Resolves the caller by phone number (from args.phone, or Retell call envelope from_number/to_number as fallback), then cancels the matching upcoming booking. When the caller has multiple upcoming bookings, omit booking_selector on the first call to receive a numbered disambiguation list; re-fire with the caller's choice to execute the cancellation. Always returns HTTP 200 - failures begin with "BOOKING CANCELLATION FAILED:" and must not be read as confirmations.

**Scopes:** `scheduling:write` — [full detail](./scheduling-bookings/post-scheduling-voice-cancel-booking.md)

### POST /scheduling/voice/reschedule-booking

Voice-agent booking reschedule. Returns text/plain. Resolves the caller by phone, then moves an existing booking to a new slot. New booking is created first (slot-race protection), then the old booking is cancelled. If the old cancel fails, a rollback is attempted on the new booking. Uses the same two-shot disambiguation pattern as cancel-booking when multiple upcoming bookings exist. Always returns HTTP 200 - failures begin with "RESCHEDULE FAILED:".

**Scopes:** `scheduling:write` — [full detail](./scheduling-bookings/post-scheduling-voice-reschedule-booking.md)
