Recurring Appointments

How Hint represents recurring appointments in the public API, and why occurrences of the same series can show different statuses - or more than one entry for the same date.

Hint stores a recurring appointment as a single record with a recurrence rule - the same concept defined by RFC 5545 (the iCalendar standard behind Google Calendar, Outlook, and most calendar systems) - rather than creating a database row for every past and future occurrence. When you call List All Appointments with a start_date/end_date range, Hint expands that one record into a separate appointment object for every occurrence that falls inside the requested window.

flowchart LR
    Base["Recurring appointment<br/>1 record + recurrence rule"] -->|list query expands| Occ1["Occurrence: Mon<br/>id: 100"]
    Base -->|list query expands| Occ2["Occurrence: Tue<br/>id: 100"]
    Base -->|list query expands| Occ3["Occurrence: Wed<br/>id: 100"]
    Occ1 -->|status changed e.g. checked in| Split["New appointment<br/>id: 501<br/>recurring_appointment_id: 100"]
    classDef node fill:#ffffff,stroke:#dc2626,stroke-width:1px,color:#0f172a,font-size:12px
    class Base,Occ1,Occ2,Occ3,Split node

One object per occurrence

A daily-recurring appointment queried over a 5-day window returns 5 separate appointment objects, not 1 - one per day the series occurs within your date range. Each occurrence has its own start/end, but until it's individually modified, it shares the same id as every other occurrence of that series. Don't assume id is unique per item in the response when a practice uses recurring appointments - treat id + start as the unique key.

Why the same series can show different statuses

status and workflow_status (for example, a patient checking in) are naturally per-occurrence: a patient can complete a visit today and still have an unconfirmed appointment next week from the same series. Hint represents this by splitting the series the moment an occurrence is individually modified - including a pure status change with no reschedule:

  • The modified occurrence becomes its own standalone appointment with a new id, carrying whatever status/workflow_status was set.
  • Every other occurrence of the series keeps coming from the original recurring record and keeps showing that record's status, so an untouched future occurrence won't inherit a check-in that happened on a past occurrence.

The split-off occurrence carries a recurring_appointment_id field pointing back to the id of the recurring appointment it split from, so you can trace it back to the rest of its series.

Editing a series after an occurrence has already split off

Once an occurrence has split off (from a status change, a reschedule, or any other individual edit), it becomes a fully independent appointment - editing the recurring series later does not reach back and touch it.

This matters most when someone edits the series with "this occurrence and all following" from a point at or before an already-split occurrence. The split occurrence is left exactly as it was, and the newly edited series doesn't know that date was already spoken for - so it generates its own occurrence for that same date too. In practice, this means you can see two appointment objects for the same date from the same original series: the untouched split-off one (old time, old details, whatever status it had) and a new one from the updated recurrence rule.

This is a known, permanent characteristic of how Hint's underlying calendar handles series edits, not a bug that's being worked - it comes up rarely enough that changing it hasn't been prioritized, and there's no clear better behavior to switch to. Build your integration to tolerate more than one appointment appearing for the same date within a single recurring series, rather than assuming exactly one occurrence per date.

Querying appointment history

start_date and end_date are required on every request, and the range can't exceed 31 days. There's no way to omit the date filters or fetch a wider range in one call, and limit/offset pagination doesn't change that - it paginates within a date window, not across a larger one. To backfill history or build a rolling timeline for a patient, loop across sequential 31-day (or narrower) windows rather than requesting the whole range at once.

Declined appointments are never returned by this endpoint, regardless of date range or status filter.


Did this page help you?