> ## Documentation Index
> Fetch the complete documentation index at: https://developers.huechat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Appointments and scheduling

> Configure appointment types, resources and availability, find slots, and synchronize the complete booking lifecycle through 30 account-scoped API operations.

The Appointments API is the system-to-system scheduling surface for HueChat.
An ERP, CRM, website, mobile app or partner platform can configure the booking
catalog, find available times, create customer appointments and maintain their
full lifecycle. Every request is restricted to the account that issued the API
key.

## Before you start

Create a [scoped API key](/api-keys) with the smallest set of permissions the
integration needs:

| Scope                   | Use it for                                                                                               |
| ----------------------- | -------------------------------------------------------------------------------------------------------- |
| `appointments:read`     | Appointments, catalog, settings, resources, services, availability, slots and reports                    |
| `appointments:write`    | Create, edit, reschedule and change appointment status                                                   |
| `appointments:settings` | Configure settings, resources, services and availability; the key owner must be an account administrator |
| `contacts:read`         | Resolve a supplied `contact_id`                                                                          |
| `contacts:write`        | Create or synchronize the contact first through the Contacts API                                         |
| `deals:write`           | Create or change an appointment linked with `deal_id`                                                    |
| `deals:read`            | Include linked-deal metadata in appointment detail                                                       |

<Warning>
  Use the account id that issued the key. A key from another account receives
  `403`; resource, service, appointment, contact and deal identifiers are never
  resolved across accounts. Appointment configuration writes also verify that
  the key's current owner is still an administrator.
</Warning>

The account must have native Appointments enabled. A plan or feature gate that
is not enabled returns `402` without weakening the other authorization checks.

## Complete API coverage

The public contract contains 30 operations. Appointment types are called
**services** in request fields; resources can represent a doctor, employee,
room, branch, device or any other capacity that can receive a booking.

### Booking and discovery

| Method | Route                                  | Scope               | Purpose                                                                |
| ------ | -------------------------------------- | ------------------- | ---------------------------------------------------------------------- |
| `GET`  | `/appointments`                        | `appointments:read` | Read appointments and the scheduling context for an RFC3339 range      |
| `GET`  | `/appointments/{id}`                   | `appointments:read` | Read one appointment, its status history and an authorized linked deal |
| `GET`  | `/appointments/external/{externalId}`  | `appointments:read` | Resolve the stable identifier from an external system                  |
| `GET`  | `/appointments/catalog`                | `appointments:read` | Read active services and their eligible resources                      |
| `GET`  | `/appointments/settings`               | `appointments:read` | Read timezone, slot interval, booking horizon and confirmation policy  |
| `GET`  | `/appointments/resources`              | `appointments:read` | List active and archived resources                                     |
| `GET`  | `/appointments/resources/{resourceId}` | `appointments:read` | Read one resource                                                      |
| `GET`  | `/appointments/services`               | `appointments:read` | List active and archived appointment types                             |
| `GET`  | `/appointments/services/{serviceId}`   | `appointments:read` | Read one appointment type                                              |
| `GET`  | `/appointments/availability`           | `appointments:read` | Read weekly rules and one-off open or closed exceptions                |
| `GET`  | `/appointments/slots`                  | `appointments:read` | Find currently bookable times by service and optional resource         |
| `GET`  | `/appointments/reports`                | `appointments:read` | Read status totals and service-level performance                       |

### Booking mutations

| Method  | Route                         | Scope                | Purpose                                                                           |
| ------- | ----------------------------- | -------------------- | --------------------------------------------------------------------------------- |
| `POST`  | `/appointments`               | `appointments:write` | Create or safely replay an external appointment                                   |
| `PATCH` | `/appointments/{id}`          | `appointments:write` | Update customer details and, for an active booking, its service, resource or time |
| `PATCH` | `/appointments/{id}/status`   | `appointments:write` | Move through tentative, booked, confirmed, completed, cancelled or no-show states |
| `PATCH` | `/appointments/{id}/schedule` | `appointments:write` | Reschedule an active appointment to an available slot                             |

### Administrator configuration

Every operation in this table requires `appointments:settings` and an
administrator key owner.

| Method   | Route                                                 | Purpose                                                              |
| -------- | ----------------------------------------------------- | -------------------------------------------------------------------- |
| `PUT`    | `/appointments/settings`                              | Create or update native scheduling policy                            |
| `POST`   | `/appointments/resources`                             | Create a doctor, room, branch or other resource                      |
| `PUT`    | `/appointments/resources/{resourceId}`                | Update a resource                                                    |
| `DELETE` | `/appointments/resources/{resourceId}`                | Archive a resource while retaining appointment history               |
| `POST`   | `/appointments/resources/{resourceId}/restore`        | Restore an archived resource                                         |
| `POST`   | `/appointments/services`                              | Create an appointment type with duration, buffers and optional price |
| `PUT`    | `/appointments/services/{serviceId}`                  | Update an appointment type                                           |
| `DELETE` | `/appointments/services/{serviceId}`                  | Archive a service while retaining appointment history                |
| `POST`   | `/appointments/services/{serviceId}/restore`          | Restore an archived service                                          |
| `PUT`    | `/appointments/services/{serviceId}/resources`        | Replace the resources eligible for a service                         |
| `POST`   | `/appointments/availability/rules`                    | Replace one resource's weekly rule for one weekday                   |
| `POST`   | `/appointments/availability/rules/bulk`               | Atomically replace up to seven weekly rules                          |
| `POST`   | `/appointments/availability/exceptions`               | Add a one-off open or closed interval                                |
| `DELETE` | `/appointments/availability/exceptions/{exceptionId}` | Remove an availability exception                                     |

All routes above are relative to `/api/v2/accounts/{accountId}`.

## Endpoint behavior, one by one

### Read and discovery operations

* `GET /appointments` returns appointments plus resources, services, settings,
  availability rules, overlapping exceptions and service-resource links. Its
  default window is 14 days; optional RFC3339 `start` and `end` may span at
  most 366 days. Use a focused endpoint when the integration does not need the
  combined scheduling context.
* `GET /appointments/{id}` accepts a HueChat `public_id` or UUID and returns
  the enriched appointment with chronological status history. Linked-deal
  data is omitted unless the key also has `deals:read`.
* `GET /appointments/external/{externalId}` finds the account-local record by
  the calling system's stable identifier. Use it to reconcile after a timeout
  or when the external system does not store a HueChat ID.
* `GET /appointments/catalog` returns active appointment types, durations,
  buffers and each service's eligible active resources. It is the smallest
  complete catalog response for an external booking interface.
* `GET /appointments/settings` returns the account timezone, slot interval,
  minimum notice, booking horizon, cancellation notice, calendar defaults and
  confirmation policy without changing them.
* `GET /appointments/resources` lists bookable people, rooms, branches,
  devices or other capacity, including archived rows. Each row includes its
  type, timezone, color, position and active state.
* `GET /appointments/resources/{resourceId}` returns one account-local
  resource UUID or `404` when it is unavailable to that account.
* `GET /appointments/services` lists active and archived appointment types,
  with duration, before/after buffers, optional price, currency, order and
  active state.
* `GET /appointments/services/{serviceId}` returns one account-local service
  UUID or `404` when it is unavailable to that account.
* `GET /appointments/availability` returns all weekly rules and exceptions
  overlapping optional RFC3339 `start` and `end`. The default range begins now
  and ends one year later; the requested range cannot exceed 366 days.
* `GET /appointments/slots` requires `date` plus a service ID or exact name.
  It accepts an optional resource ID/name, `preferred_time`, and `limit` from 1
  to 50. Each result identifies the service and resource and gives absolute
  start/end plus local date, local time and timezone.
* `GET /appointments/reports` returns lifecycle totals, AI-booked count and a
  per-service breakdown. The default range is the previous month; optional
  RFC3339 `start` and `end` cannot span more than 366 days.

### Booking write operations

* `POST /appointments` creates a booking from `external_id`, customer data,
  appointment type and time. It accepts UUIDs or exact active names, optional
  automatic resource selection, and either RFC3339 `starts_at` or local
  `date` plus `time`. An identical retry returns the original record.
* `PATCH /appointments/{id}` updates the editable customer record and can move
  an active appointment in the same transaction. Send resource, service,
  start time, customer fields and the current `version`; stale versions fail
  with `409`.
* `PATCH /appointments/{id}/status` changes lifecycle state with an optional
  `reason` and required `version`. The appointment and its status-history row
  commit together.
* `PATCH /appointments/{id}/schedule` moves a tentative, booked or confirmed
  appointment to the supplied resource UUID, service UUID and RFC3339 start.
  Availability conflicts, invalid catalog combinations and stale versions are
  rejected instead of overwriting newer work.

### Configuration operations

* `PUT /appointments/settings` saves a complete, coherent native/external
  mode, timezone, slot interval, notice limits, calendar defaults and
  confirmation policy. Enabling native mode retires superseded external
  booking configuration atomically.
* `POST /appointments/resources` creates a capacity resource with required
  name and type plus optional description, IANA timezone, hex color and
  position.
* `PUT /appointments/resources/{resourceId}` changes only supplied resource
  fields and can activate or deactivate it.
* `DELETE /appointments/resources/{resourceId}` archives the resource so it is
  unavailable for new scheduling while all historical appointments remain.
* `POST /appointments/resources/{resourceId}/restore` makes an archived
  resource available for configuration and booking again.
* `POST /appointments/services` creates an appointment type with a 5–1440
  minute duration, optional buffers, non-negative price, three-letter currency,
  color and position.
* `PUT /appointments/services/{serviceId}` changes only supplied service
  fields, including duration, buffers, price, currency, position and active
  state.
* `DELETE /appointments/services/{serviceId}` archives the appointment type
  while preserving bookings that used it.
* `POST /appointments/services/{serviceId}/restore` makes an archived service
  selectable again.
* `PUT /appointments/services/{serviceId}/resources` replaces the complete
  eligible-resource set with an array of account-local UUIDs. An empty array
  means every active resource may provide the service.
* `POST /appointments/availability/rules` replaces one resource/weekday rule.
  `day_of_week` is 0–6 and start/end are minutes after local midnight.
* `POST /appointments/availability/rules/bulk` validates and atomically
  replaces up to seven resource/weekday rules, so a bad item leaves the
  existing schedule unchanged.
* `POST /appointments/availability/exceptions` creates a one-off `open` or
  `closed` RFC3339 interval. Omit `resource_id` to apply it account-wide.
* `DELETE /appointments/availability/exceptions/{exceptionId}` deletes that
  account-local exception and does not alter appointment history.

## Configure the scheduling model

### 1. Save account settings

The IANA timezone is used when an integration sends local `date` and `time`.
Enabling native booking disables superseded external booking configurations in
the same transaction.

```bash theme={null}
curl -X PUT "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/settings" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "native_enabled": true,
    "booking_mode": "native",
    "timezone": "Asia/Riyadh",
    "slot_interval_minutes": 15,
    "minimum_notice_minutes": 60,
    "maximum_advance_days": 90,
    "cancellation_notice_minutes": 120,
    "week_starts_on": 0,
    "default_view": "week",
    "resource_label": "Doctor",
    "confirmation_mode": "automatic"
  }'
```

### 2. Create resources and appointment types

Create a resource:

```bash theme={null}
curl -X POST "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/resources" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Dr. Sara",
    "resource_type": "Doctor",
    "description": "Dermatology consultant",
    "timezone": "Asia/Riyadh",
    "color": "#6C5CE7",
    "position": 1
  }'
```

Create a service, which is the appointment **type** selected by customers:

```bash theme={null}
curl -X POST "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/services" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Initial consultation",
    "description": "First 30-minute consultation",
    "duration_minutes": 30,
    "buffer_before_minutes": 5,
    "buffer_after_minutes": 10,
    "price": 250,
    "currency": "SAR",
    "color": "#5CB198",
    "position": 1
  }'
```

Assign the service to selected resources. The body is an array of resource
UUIDs. An empty array means every active resource is eligible.

```bash theme={null}
curl -X PUT "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/services/$SERVICE_ID/resources" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '["'$RESOURCE_ID'"]'
```

### 3. Set weekly hours and exceptions

`day_of_week` uses `0` for Sunday through `6` for Saturday. Start and end
minutes are measured from local midnight, so `540` is 09:00 and `1020` is
17:00.

```bash theme={null}
curl -X POST "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/availability/rules/bulk" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {"resource_id":"'$RESOURCE_ID'","day_of_week":0,"start_minute":540,"end_minute":1020,"is_active":true},
      {"resource_id":"'$RESOURCE_ID'","day_of_week":1,"start_minute":540,"end_minute":1020,"is_active":true}
    ]
  }'
```

Use an exception for a holiday, special opening or temporary closure. Omit
`resource_id` to apply it to every resource.

```bash theme={null}
curl -X POST "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/availability/exceptions" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "resource_id": "'$RESOURCE_ID'",
    "kind": "closed",
    "starts_at": "2026-09-23T00:00:00+03:00",
    "ends_at": "2026-09-24T00:00:00+03:00",
    "reason": "Public holiday"
  }'
```

The bulk weekly-rules request is validated before any rule changes. Settings
and status/history mutations are also transactional.

## Find a slot by name, type and date

An integration may use UUIDs for long-lived catalog references or exact names
for a human-friendly flow. Do not send both forms for the same selector.

```bash theme={null}
curl --get "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/slots" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  --data-urlencode "service_name=Initial consultation" \
  --data-urlencode "resource_name=Dr. Sara" \
  --data-urlencode "date=2026-09-15" \
  --data-urlencode "preferred_time=12:00" \
  --data-urlencode "limit=20"
```

`service_name` and `resource_name` use exact, account-local active names.
Replace them with `service_id` and `resource_id` when catalog names may change.
The resource is optional: omitting both resource selectors returns slots for
all eligible resources.

## Create by customer, date, time and appointment type

API-key creation requires `external_id`, the stable appointment identifier in
the calling system. It must be 1–128 ASCII characters, start with a letter or
digit, and otherwise use only letters, digits, `.`, `_`, `:` or `-`.

This example uses exact human-readable catalog names and local time. `date` and
`time` are interpreted in the account appointment timezone.

```bash theme={null}
curl -X POST "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "external_id": "erp-appointment-10492",
    "service_name": "Initial consultation",
    "resource_name": "Dr. Sara",
    "date": "2026-09-15",
    "time": "12:00",
    "customer_name": "Sara Alotaibi",
    "customer_phone": "+966500000000",
    "customer_email": "sara@example.com",
    "status": "booked",
    "notes": "Created from partner booking site"
  }'
```

You may instead send `service_id`, optional `resource_id`, and an RFC3339
`starts_at`. If the resource is omitted, HueChat selects an eligible resource
that is free at that time. The configured service duration and buffers are
authoritative; `ends_at` is optional and, when supplied, is validation input
rather than a duration override.

`contact_id` is optional. It must identify a contact in the same account and
requires `contacts:read`. You may also send customer name, phone and email
directly without creating a Contact first. Use the
[Contacts and Customer CDP API](/contacts) when the external system needs to
maintain the unified customer record.

`deal_id` is optional. It must be an account-local deal UUID whose branch
allows the selected resource and service. It requires `deals:write`; linked
deal metadata is returned only with `deals:read`.

## Retry without duplicate bookings

If a network timeout leaves the result uncertain, send the exact request again
with the same `external_id`. HueChat returns the existing appointment and:

```text theme={null}
X-Idempotent-Replayed: true
```

This also reconciles a missing optional deal link after partial downstream
failure. Reusing the identifier with different request data returns `409
Conflict`; it never silently changes the first appointment. A temporary `503`
is safe to retry with the identical request. When the appointment was stored
but its deal link still needs reconciliation, the response also includes
`Retry-After: 0`.

Unknown JSON fields, multiple JSON values and bodies larger than 1 MiB are
rejected. A `429` response is JSON and includes `Retry-After: 60` and
`X-RateLimit-*` headers.

## Update, reschedule and complete

Appointment responses include `public_id`, the internal UUID and `version`.
Use either ID in the detail and mutation routes, and send the latest `version`
with every change. A stale write returns `409`; reload and decide whether to
retry.

Change lifecycle state:

```bash theme={null}
curl -X PATCH "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/$APPOINTMENT_ID/status" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"confirmed","reason":"Confirmed by ERP","version":1}'
```

Creation accepts `tentative`, `booked` and `confirmed`. Later status changes
also accept `completed`, `cancelled` and `no_show`. Each successful status
change and its history entry commit together.

Reschedule an active appointment with resource and service UUIDs:

```bash theme={null}
curl -X PATCH "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/$APPOINTMENT_ID/schedule" \
  -H "Authorization: Bearer $HUECHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "resource_id": "'$RESOURCE_ID'",
    "service_id": "'$SERVICE_ID'",
    "starts_at": "2026-09-16T10:30:00+03:00",
    "version": 2
  }'
```

The general `PATCH /appointments/{id}` endpoint updates the full editable
customer details and can move an active appointment at the same time. Supply
the selected `resource_id`, `service_id`, `starts_at`, customer fields and
current `version`. Completed, cancelled and no-show appointments retain their
original schedule.

## Read history and reports

`GET /appointments/{id}` returns the appointment plus chronological status
history. `GET /appointments/reports?start=…&end=…` returns totals by lifecycle
state and by service. Overview, availability and reporting ranges use RFC3339,
require `end` after `start`, and cannot exceed 366 days.

## Security and intentional boundaries

* The bearer token is retained by HueChat only as a one-way hash.
* Account ownership, scope, expiry, optional IP allowlist, revocation and
  per-key rate limit are checked on every request.
* Catalog names and IDs are resolved only inside the account. A duplicate or
  missing exact name fails closed instead of selecting another account's row.
* Appointment scopes never imply contact, deal or AI-agent access.
* Archive and restore are public administration operations because they retain
  history. Permanent resource/service deletion is not part of the documented
  integration contract.
* Resource-to-AI-agent assignment remains an AI administration workflow, not
  an appointment integration operation.

See the [interactive API reference](/api-reference/overview) for every request
field, response schema and error status.
