# Healthcare appointment booking API

Source: https://developer.nylas.com/docs/cookbook/scheduler/healthcare-appointment-booking/

A patient taps "Book" on a Tuesday afternoon slot. So does someone else, half a second later. Behind both requests sits a provider whose calendar already holds two surgeries, a lunch block, and a personal appointment they marked private. Healthcare scheduling is where availability, concurrency, and patient trust collide. Get the availability math wrong and you overbook a clinician who is already in theatre. Get the reminder cadence wrong and missed appointments quietly drain revenue from the clinic every week.

This recipe covers the booking primitives a healthcare app needs: reading real provider Free/Busy across Google, Microsoft, and other calendars, computing bookable slots, preventing two patients from grabbing the same time, sending reminders, and the compliance lines you can't cross when patient data is involved.

## Which scheduling API is best for healthcare appointment booking?

For healthcare appointment booking, the strongest scheduling API connects to every provider calendar through one OAuth flow, computes availability across multiple clinicians at once, and exposes a booking endpoint that rejects an already-taken slot. The Nylas API does this through `POST /v3/calendars/availability` and `POST /v3/scheduling/bookings`, reaching Google, Microsoft, iCloud, and Exchange calendars with a single integration.

Most scheduling tools were built for sales demos, not clinics. A medical app has harder constraints: a provider's real calendar is the source of truth, not a separate booking database that drifts out of sync. The platform reads each clinician's live Free/Busy through their connected Google or Microsoft account, so a personal event blocked at 3:00 PM removes that slot automatically. One connector covers your whole roster, whether 5 providers or 500, instead of a per-provider integration you maintain by hand. That single source of truth is what keeps a patient from booking a doctor who is already busy.

## What is the best scheduling API for patient scheduling in a healthcare app?

The best fit for patient scheduling reads provider calendars in real time, supports collective and round-robin availability across a care team, and keeps protected health information out of calendar payloads. The scheduling API computes slots through `availability_method` set to `collective` or `max-fairness`, and the calendar API never requires you to store a patient's medical reason on the event itself.

Patient scheduling has two shapes. A specialist visit needs one named provider, so you query that clinician's calendar directly. A "next available nurse" flow needs the system to spread bookings across a pool, which is where round-robin matters. The availability endpoint accepts an `availability_rules` object with an `availability_method` field, so you switch between booking a single provider and load-balancing a team without rewriting your logic. Keep clinical detail off the calendar event: store the appointment reason in your own database keyed by booking ID, and let the calendar hold only a neutral title. This separation is the practical core of staying compliant, covered in more depth below.

## Read provider availability across calendars

Computing bookable slots starts with the availability endpoint. `POST /v3/calendars/availability` takes a time window and a list of participants, then returns only the slots where every listed provider is free. It honors `open_hours`, applies `buffer` time between appointments, and rounds slots to a clean boundary through `round_to`. Request a window that matches your booking horizon, such as the next two weeks of clinic hours.

The call below finds 30-minute openings for a single provider across one business day. Set `duration_minutes` to the appointment length, `interval_minutes` to how often a slot can start, and add a `buffer` so back-to-back patients don't leave the clinician zero turnaround time.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/calendars/availability' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "start_time": 1700000000,
    "end_time": 1700083200,
    "duration_minutes": 30,
    "interval_minutes": 30,
    "round_to": 15,
    "participants": [
      {
        "email": "dr.reyes@clinic.example.com",
        "calendar_ids": ["dr.reyes@clinic.example.com"],
        "open_hours": [
          {
            "days": [1, 2, 3, 4, 5],
            "timezone": "America/New_York",
            "start": "09:00",
            "end": "17:00",
            "exdates": []
          }
        ]
      }
    ],
    "availability_rules": {
      "availability_method": "collective",
      "buffer": { "before": 10, "after": 10 }
    }
  }'
```

For a care team where any available clinician will do, list several participants and set `availability_method` to `max-fairness` to spread load. The response returns a `time_slots` array your front end renders as bookable times.

## Check a single provider's Free/Busy

When you only need to know whether one clinician is busy in a window, skip slot computation and query `POST /v3/grants/{grant_id}/calendars/free-busy` directly. It returns busy blocks for the listed `emails` without exposing event titles or attendees, so it's the right call for a quick conflict check before you write anything. A single request accepts many email addresses in the `emails` array, so you can check an entire 12-clinician roster in 1 call instead of 12. One caveat: the Free/Busy endpoint isn't available for iCloud accounts, so use the availability endpoint for any iCloud clinician.

The request below asks whether a provider has any conflicts in a given window. It returns time blocks marked busy, not the underlying events, which keeps unrelated patient detail out of the response. Use this as a fast pre-write guard, not as your slot source.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/calendars/free-busy' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "start_time": 1700000000,
    "end_time": 1700083200,
    "emails": ["dr.reyes@clinic.example.com"]
  }'
```

The Free/Busy response shows when a provider is unavailable without revealing why, which matters when the blocking event is the clinician's own private appointment.

## How do I prevent double-booking two patients in the same slot?

Prevent double-booking by routing patient bookings through `POST /v3/scheduling/bookings`, which re-validates the slot against the live calendar at write time and rejects a second claim on the same window. Two requests for one slot resolve to a single success and one error, so you never persist two patients against the same provider minute, even under a simultaneous tap.

Double-booking in a clinic is a concurrency bug, not an availability bug. Availability tells you a slot was open a moment ago; it says nothing about who is mid-checkout right now. The managed booking flow closes that gap: it claims the slot for you in a single request and returns a non-200 status when the slot is already gone. If you build a fully custom flow on the calendar API instead, the guard becomes your job, an app-side lock or a database unique constraint on `(provider_id, start_time)`. The full concurrency walkthrough lives in [prevent double-booking](/docs/cookbook/scheduler/prevent-double-booking/). The booking request below confirms a slot a patient selected.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/scheduling/bookings?configuration_id=<SCHEDULER_CONFIG_ID>' \
  --header 'Content-Type: application/json' \
  --data '{
    "start_time": 1700000000,
    "end_time": 1700001800,
    "participants": [],
    "guest": {
      "name": "Jane Doe",
      "email": "jane.doe@example.com"
    }
  }'
```

Catch the rejection, refresh the slot list, and ask the patient to pick again. Never silently fail a booking, a patient who thinks they're confirmed but isn't is worse than no booking at all.

## Send appointment reminders to cut no-shows

Reminders are where a booking API earns its keep, because missed appointments are the single largest source of lost clinic revenue. After a booking confirms, subscribe to `POST /v3/webhooks` and trigger your reminder pipeline from the `booking.created` trigger; the `event.created` trigger fires on the underlying calendar event the booking writes if you prefer to key off that. Nylas also emits a dedicated `booking.reminder` trigger you can hook directly, so your service stays in sync without polling.

Pair the webhook with a scheduled job that sends a reminder 24 hours out and again 1 hour before the visit. Unreminded appointments are a leading source of clinic no-shows, and a two-touch reminder cadence reliably pulls the miss rate down. Send the reminder through your own messaging stack, and keep clinical detail out of it: "You have an appointment Tuesday at 2:00 PM" is enough. Don't name the procedure or the department in an SMS or email a third party could intercept. For a reminder pipeline built on calendar events, see [schedule event reminders](/docs/cookbook/use-cases/act/schedule-event-reminders/).

## What compliance rules apply to healthcare booking data?

Healthcare booking data becomes protected health information the moment it ties a patient identity to a provider or appointment reason, so it falls under HIPAA in the United States. Keep clinical detail out of calendar events, store the medical reason in your own controlled database, and execute a Business Associate Agreement with every vendor that touches that data.

The practical pattern is data minimization. The calendar event carries a neutral title like "Appointment" and the booking ID; your database holds the link between that ID, the patient, and the visit reason behind your own access controls. This keeps the appointment's clinical meaning out of any third-party calendar payload while still letting you reconcile bookings. Confirm vendor obligations against the official HHS guidance at [HHS.gov on Business Associates](https://www.hhs.gov/hipaa/for-professionals/privacy/guidance/business-associates/index.html), and treat reminder content, logs, and analytics as in-scope, not just the booking record itself. Compliance here is mostly about what you choose not to put in the event.

## When is a single-provider scheduling tool the better choice?

A purpose-built single-vendor scheduling widget can be the better choice for a solo practice or a clinic standardized entirely on 1 calendar provider. If every clinician lives in Google Workspace and you'll never add a Microsoft or iCloud account, a narrow tool tied to that one ecosystem has less to integrate, and a hosted page may ship faster.

Be honest about the tradeoff. That convenience holds only while your roster stays on a single provider and your booking flow stays generic. The moment you add a hospital group on Microsoft 365, a specialist on iCloud, or need custom availability rules across a care team, you're maintaining multiple integrations or fighting a closed widget. A unified layer fronts every supported calendar provider through one OAuth connector and one slot computation, so adding a provider later costs no new integration. For a custom patient-facing form, [customize the booking flow](/docs/cookbook/scheduler/customize-booking-flow/) covers buffers, notice windows, and field configuration.

## What's next

- [Prevent double-booking](/docs/cookbook/scheduler/prevent-double-booking/) for the full concurrency walkthrough and app-side locking
- [Customize the booking flow](/docs/cookbook/scheduler/customize-booking-flow/) to configure the patient form, buffers, and notice windows
- [Schedule event reminders](/docs/cookbook/use-cases/act/schedule-event-reminders/) for the webhook-driven reminder pipeline
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connector, and your first grant