> ## 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.

# Scheduling system connections

> Keep HueChat's calendar in sync with a clinic or hospital system of record, such as Oracle Health (Cerner), Epic, InterSystems TrakCare or a practice-management system, over REST or HL7 FHIR R4.

Clinics and hospitals usually book patients in their own system of record.
A scheduling system connection copies every booking from that system into
HueChat, so WhatsApp reminders, forms and follow-ups reach every patient,
including walk-ins and visits booked minutes before they start.

The connection works the same way for a small clinic's practice software and
for a hospital's Oracle Health (Cerner), Epic or InterSystems TrakCare
integration engine. Send JSON over REST, or send HL7 FHIR R4 `Appointment`
resources.

## How a connection is set up

<Steps>
  <Step title="HueChat approves the account">
    Scheduling system connections are available to accounts HueChat has
    approved during onboarding. Until then, sync requests return `403`.
  </Step>

  <Step title="The account admin creates a key for the system">
    In **HueChat → Account → Developer API**, choose the **Scheduling system**
    preset. It grants `appointments:sync`, `appointments:read` and
    `contacts:read`. Create one key per system and give it to that system's
    support team.
  </Step>

  <Step title="The system sends its bookings">
    Every booking the system sends is stored exactly as the system has it.
    **Appointments → Booking settings → Scheduling system connection** shows
    the last booking received and any booking HueChat could not store.
  </Step>
</Steps>

<Warning>
  Only a REST API key with `appointments:sync` on an approved account is treated
  as a scheduling system. Staff sign-ins and personal access tokens are refused,
  so a sync never runs with a person's full account access, never stops when that
  person signs in elsewhere, and never shows a staff member as the creator of
  every booking.
</Warning>

## What HueChat keeps

A booking from the connection is stored as the system has it, with
`source: "sync"`:

* past, same-day and walk-in visits, and times off HueChat's slot grid or
  outside its opening hours
* archived doctors, rooms or services
* any lifecycle status
* deliberate double bookings, when a doctor sees two patients at once

HueChat's own booking channels (AI agents, forms and staff) still never
overlap each other, and they avoid slots that synced bookings fill. A synced
booking can only be moved by the system that owns it; in HueChat it cannot be
dragged to a new time. Doctors and rooms a system created are not offered to
HueChat's booking channels, because HueChat cannot write a booking back to that
system.

## Send a booking

`PUT /appointments/external/{externalId}` creates the booking or updates it to
the version you send. Use your system's own booking id as `externalId`.

```bash theme={null}
curl -X PUT "https://app.huechat.ai/api/v2/accounts/$ACCOUNT_ID/appointments/external/his-main:A-10492" \
  -H "Authorization: Bearer $HUECHAT_SYNC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source_updated_at": "2026-09-22T09:58:00Z",
    "status": "booked",
    "starts_at": "2026-09-22T13:00:00+03:00",
    "ends_at": "2026-09-22T13:20:00+03:00",
    "resource_code": "Practitioner/482",
    "resource_name": "Dr. Sara Ali",
    "service_code": "DENT-CONSULT",
    "service_name": "Dental consultation",
    "patient_identifier": "MRN-000205",
    "customer_name": "Example Patient",
    "customer_phone": "+966500000000"
  }'
```

The first request returns `201`. Later requests return `200`, and the
`X-HueChat-Sync-Result` header says what happened:

| Result      | Meaning                                                      |
| ----------- | ------------------------------------------------------------ |
| `created`   | The booking is new                                           |
| `updated`   | HueChat now holds the version you sent                       |
| `unchanged` | The version you sent is the one HueChat holds                |
| `stale`     | You sent an older version than HueChat holds; it was ignored |

### Order of updates

Send `source_updated_at`: the time your system last changed the booking
(FHIR `meta.lastUpdated`, HL7 `MSH-7`). When messages arrive out of order,
HueChat ignores an update older than the one it holds, so a late message never
rolls a booking back. An identical resend with a newer time only records that
time.

### Doctors, rooms and services

HueChat matches the resource and the service in this order:

1. The HueChat id (`resource_id`, `service_id`).
2. Your own code (`resource_code`, `service_code`), such as a practitioner,
   location or procedure id.
3. The name (`resource_name`, `service_name`). Case, spaces and punctuation are
   ignored, so `Dr.Sara Ali` matches `Dr. Sara Ali`.

When a code HueChat has not seen arrives, HueChat adds the doctor, room or
service to the catalog, so a hospital with hundreds of doctors needs no manual
setup. When a code arrives with a name HueChat already knows, HueChat
remembers the code for that record. A name that matches nothing, sent without
a code, is rejected.

### Patients

HueChat links the booking to an existing contact by `contact_id`, then by
`patient_identifier` (the contact's identifier, such as the MRN), then by phone.
Details missing from the request come from that contact. The sync never
creates contacts; create patients through the [Contacts API](/contacts) with
their record number as the `identifier` when form invitations must reach them.

### Statuses

HueChat accepts its own statuses, HL7 FHIR R4 `Appointment.status` and HL7 v2
SIU filler status codes:

| Sent                                            | Stored as                                       |
| ----------------------------------------------- | ----------------------------------------------- |
| `booked`, `Overbook`                            | `booked`                                        |
| `tentative`, `proposed`, `pending`, `waitlist`  | `tentative`                                     |
| `confirmed`, `arrived`, `checked-in`, `Started` | `confirmed`                                     |
| `completed`, `fulfilled`, `Complete`            | `completed`                                     |
| `cancelled`, `Canceled`, `DC`                   | `cancelled`                                     |
| `no_show`, `noshow`                             | `no_show`                                       |
| `entered-in-error`, `Deleted`                   | `cancelled`, with the reason "Entered in error" |

Add `cancellation_reason` to a cancelled booking to keep your system's
reason.

### Remove a booking

`DELETE /appointments/external/{externalId}?reason=…` keeps the booking in
HueChat as cancelled, with its history. An unknown id returns `204`.

## Send many bookings

`POST /appointments/sync` accepts up to 200 bookings. Each item follows the
same rules as the single request and must carry `external_id`. Each booking is
stored on its own, so one rejected booking does not hold back the rest.

```json theme={null}
{
  "appointments": [
    { "external_id": "his-main:A-10492", "status": "booked", "starts_at": "2026-09-22T13:00:00+03:00", "resource_code": "Practitioner/482", "service_code": "DENT-CONSULT", "patient_identifier": "MRN-000205" },
    { "external_id": "his-main:A-10493", "status": "fulfilled", "starts_at": "2026-09-22T11:40:00+03:00", "ends_at": "2026-09-22T12:05:00+03:00", "resource_code": "Practitioner/482", "service_code": "DENT-CONSULT", "customer_name": "Walk-in patient" }
  ]
}
```

The response lists one result per booking in request order, with `created`,
`updated`, `unchanged`, `stale` and `failed` totals.

## Reconcile

`GET /appointments/sync?start=…&end=…` lists every booking with an external id
that starts in the window, up to 31 days, ordered by start time. Follow
`next_cursor` for the next page. Compare it with your own schedule and resend
anything that differs.

## Monitor the connection

`GET /appointments/sync/status` returns:

* the account's scheduling-system keys and when each was last used
* when a synced booking last changed, and how many changed in the last 24 hours
* bookings HueChat rejected, until a later version of each succeeds

The same information appears in **Appointments → Booking settings**. The
failure list keeps only the external id and the error, never patient details.

## HL7 FHIR R4

Integration engines that already produce FHIR R4 can send `Appointment`
resources as they are:

| Request                            | Purpose                                           |
| ---------------------------------- | ------------------------------------------------- |
| `GET /fhir/R4/metadata`            | Capability statement                              |
| `PUT /fhir/R4/Appointment/{id}`    | Create or update a booking                        |
| `GET /fhir/R4/Appointment/{id}`    | Read the booking HueChat holds                    |
| `DELETE /fhir/R4/Appointment/{id}` | Cancel the booking; HueChat keeps it              |
| `POST /fhir/R4`                    | A `batch` Bundle of up to 200 Appointment entries |

The base URL is `https://app.huechat.ai/api/v2/accounts/{accountId}/fhir/R4`.
Add `?source=` with a short name for the sending system, such as
`?source=oracle-main`, so two FHIR systems on one account never share ids. The
booking's external id becomes `<source>:Appointment:<id>`.

```json theme={null}
{
  "resourceType": "Appointment",
  "id": "A-10492",
  "meta": { "lastUpdated": "2026-09-22T09:58:00Z" },
  "status": "booked",
  "serviceType": [{ "coding": [{ "code": "DENT-CONSULT", "display": "Dental consultation" }] }],
  "start": "2026-09-22T10:00:00Z",
  "end": "2026-09-22T10:20:00Z",
  "contained": [
    { "resourceType": "Patient", "id": "patient", "identifier": [{ "value": "MRN-000205" }], "name": [{ "text": "Example Patient" }], "telecom": [{ "system": "phone", "value": "+966500000000", "use": "mobile" }] },
    { "resourceType": "Practitioner", "id": "doctor", "identifier": [{ "value": "Practitioner/482" }], "name": [{ "text": "Dr. Sara Ali" }] }
  ],
  "participant": [
    { "actor": { "reference": "#patient" } },
    { "actor": { "reference": "#doctor" } }
  ]
}
```

| FHIR                                                                                         | HueChat                                                                                              |
| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `Practitioner` or `PractitionerRole` participant (else `Location`, then `HealthcareService`) | Resource: its identifier is the code, its name or display is the name                                |
| `serviceType`, else `appointmentType`                                                        | Service code and name                                                                                |
| `Patient` participant                                                                        | Patient: identifier, name, mobile phone and email from a contained Patient, or the reference display |
| `start`, `end`, `minutesDuration`                                                            | Time and length                                                                                      |
| `meta.lastUpdated`                                                                           | `source_updated_at`                                                                                  |
| `comment`, else `description`                                                                | Notes                                                                                                |
| `cancelationReason`                                                                          | Cancellation reason                                                                                  |

Errors come back as `OperationOutcome` resources. The endpoint is a
write-oriented subset of FHIR, not a general FHIR server.

## HL7 v2 SIU

Route SIU messages through your integration engine, such as Rhapsody, Mirth,
InterSystems or Cloverleaf, to the REST or FHIR endpoint:

| SIU event                                         | Request                                  |
| ------------------------------------------------- | ---------------------------------------- |
| S12 new booking, S13 reschedule, S14 modification | `PUT` with the booking's current details |
| S15 cancellation                                  | `PUT` with `status: "cancelled"`         |
| S17 deletion                                      | `DELETE`                                 |
| S26 no-show                                       | `PUT` with `status: "noshow"`            |

Use `MSH-7` as `source_updated_at` and the SCH filler status as `status`.

## Security checklist

* Give each system its own key and restrict it to the system's IP addresses
  in Developer API.
* Grant only `appointments:sync`, `appointments:read` and `contacts:read`.
* Rotate the key from Developer API without downtime, and revoke it when the
  system is retired.
* Send only what reminders and forms need; keep clinical detail out of
  `notes`.
