---
title: "How to Build Online Appointment Booking Across EHRs and Practice Management Systems with"
img: https://unified.to/images/logo.svg
date: 2026-10-24T01:33:00.000Z
updated: 2026-10-24T11:40:08.673Z
readingTime: 4
tag: Product
description: "Your product can show open appointment slots and book, reschedule and cancel appointments in a practice's own scheduling system through one connection. Slots..."
url: "https://unified.to/blog/how_to_build_online_appointment_booking_across_ehrs_and_practice_management_systems_with"
---

# How to Build Online Appointment Booking Across EHRs and Practice Management Systems with

Your product can show open appointment slots and book, reschedule and cancel appointments in a practice's own scheduling system through one connection. Slots are available from Canvas Medical, Cliniko, Dentally, Docplanner, DrChrono, EMIS, Gentu, Halaxy, Healthie, Medtech ALEX, ModMed, Open Dental, Oracle Health, Semble, SMART on FHIR and TELUS Health CHR, and appointments can be created on 19 integrations, including Cliniko, DrChrono, Elation Health, Healthie, Open Dental and Tebra (as of 24 October 2026).


`sdk.healthcare.listHealthcareSlots` and `sdk.healthcare.createHealthcareAppointment` work the same way on every one of them. Every request is executed directly against the practice's system, so a slot you show is open now and a booking is on the practice's calendar when the request returns.


## Why booking is the hard part of a healthcare integration


Patient-acquisition marketplaces, digital front doors, telehealth platforms, referral tools and AI receptionists all end in the same action: put a patient in a real time slot on a real clinician's calendar. A booking that lives only in your product, or reaches the practice as an email, is a booking someone has to re-enter, and sometimes double-book.


Each scheduling system models availability differently: some publish slots, some publish working hours you have to subtract appointments from, and each has its own rules about which fields a booking needs. [Unified.to](http://unified.to/)'s [Healthcare API](/healthcare) returns availability as a [Slot object](https://docs.unified.to/healthcare/slot/model) and bookings as an [Appointment object](https://docs.unified.to/healthcare/appointment/model), so you build the flow once.


## What you are building

1. Authorize the practice's system and store one connection ID
2. Let the patient choose a clinician and location
3. Show open slots for a date range
4. Book the appointment, then reschedule or cancel it on request
5. Keep your view of the calendar current

## Connect once


```typescript
import { UnifiedTo } from '@unified-api/typescript-sdk';
import * as errors from '@unified-api/typescript-sdk/sdk/models/errors';

const sdk = new UnifiedTo({
  security: { jwt: process.env.UNIFIED_API_KEY },
});
```


Each practice authorizes their own system through [Unified.to](http://unified.to/)'s authorization component, which returns a connection ID. Store one per practice. List clinicians with `listHealthcarePractitioners` and locations with `listHealthcareLocations` to build the choices (see _How to Build a Provider Directory_).


## Show open slots


```typescript
const slots = await sdk.healthcare.listHealthcareSlots({
  connectionId,
  practitionerId,
  locationId,
  startGte: '2026-11-02T00:00:00Z',
  endLt: '2026-11-09T00:00:00Z',
});

const open = slots.filter((slot) => slot.status === 'FREE');
```


`status` is `FREE`, `BUSY`, `BUSY_UNAVAILABLE`, `BUSY_TENTATIVE` or `ENTERED_IN_ERROR`; offer only `FREE` slots. `start_at` and `end_at` are the slot's time, `service_types` the kinds of visit it can be booked for, and `is_overbooked` marks a slot that's already been double-booked.


Always pass a date range. Docplanner requires `locationId`, `startGte` and `endLt`; DrChrono requires `startGte`; Gentu requires `startGte` and `endLt` (as of 24 October 2026). DrChrono, Halaxy, ModMed, Oracle Health and Semble filter slots by practitioner and location; Gentu by practitioner only and Docplanner by location only; elsewhere, filter the returned slots on `practitioner_id` and `location_id` in your own code. The [Supported Integrations page](https://docs.unified.to/healthcare/integrations) lists filters per integration.


## Book the appointment


```typescript
const appointment = await sdk.healthcare.createHealthcareAppointment({
  connectionId,
  healthcareAppointment: {
    patient_id: patientId,
    practitioner_ids: [slot.practitioner_id!],
    location_id: slot.location_id,
    slot_ids: [slot.id!],
    start_at: slot.start_at,
    end_at: slot.end_at,
    status: 'BOOKED',
    service_types: slot.service_types,
    description: 'New patient visit',
  },
});
```


Systems differ in what a booking needs. For example, Elation Health requires `patient_id`, `practitioner_ids` and `start_at`; IntakeQ also requires `location_id` and `service_types`; EMIS books into a slot and requires `slot_ids` and `reasons`. Send everything you have from the slot, and read the required fields per integration from the capability matrix before you design your booking form.


`patient_id` must already exist in the practice's system. Look the patient up first, and register them if they're new (see _How to Find and Register Patients_).


## Reschedule and cancel


Reschedule by updating the time:


```typescript
await sdk.healthcare.updateHealthcareAppointment({
  connectionId,
  id: appointment.id!,
  healthcareAppointment: { start_at: newSlot.start_at, end_at: newSlot.end_at },
});
```


Cancel by setting `status: 'CANCELLED'` with an update (and a `cancellation_reason` where the system keeps one), or by removing the appointment where the system supports delete. Cliniko, Dentally, Docplanner, DrChrono, Elation Health, Healthie, IntakeQ, Medtech ALEX, Semble and Tebra accept deletes (as of 24 October 2026); on the others, cancel by status.


## Read the calendar


```typescript
const upcoming = await sdk.healthcare.listHealthcareAppointments({
  connectionId,
  patientId,
  startGte: new Date().toISOString(),
});
```


Appointment lists filter by `patientId`, `practitionerId`, `locationId`, `status` and a `startGte`/`endLt` window; which filters each system honours is in the capability matrix. Epic, Oracle Health, Jane and several others return appointments read-only, which is enough for reminders and visit preparation.


## Handling coverage that varies by system


**Treat 501 as information, not failure.** A system that doesn't publish slots returns 501 Not Implemented for slots; fall back to a request-a-time form for those practices instead of showing an empty calendar.


```typescript
try {
  return renderSlots(await sdk.healthcare.listHealthcareSlots({ connectionId, startGte, endLt }));
} catch (error) {
  if (error instanceof errors.UnifiedToError && error.statusCode === 501) {
    return renderRequestForm();
  }
  throw error;
}
```


**Expect the slot to be gone.** Another patient can book between your read and your write. Treat a failed create as "slot taken" and re-read availability.


## Stay current when the calendar changes


Halaxy pushes appointment changes as native [webhooks](/blog/replacing_polling_with_event_driven_integrations_using_virtual_webhooks). On Canvas Medical, Cliniko, Dentally, DrChrono, IntakeQ, Open Dental, Semble, SMART on FHIR and TietoEVRY Lifecare, [virtual webhooks](/blog/what_are_virtual_webhooks_how_they_differ_from_sync_based_webhooks) for `healthcare_appointment` detect changes for you, and `updatedGte` returns only appointments changed since a timestamp (as of 24 October 2026). On the others, read on a schedule.


→ [Start your 30-day free trial](https://app.unified.to/login)
→ [Book a demo](https://calendly.com/d/cph9-g8n-jzg/connect-with-unified)


## Frequently asked questions


**Can I book on a system that doesn't return slots?**


Where appointments can be created, yes: send `start_at`, `end_at` and the clinician, and the system applies its own rules. Without slots you can't show availability, so confirm the time with the practice's own response.


**Does** [**Unified.to**](http://unified.to/) **hold the booking?**


No. The appointment is written to the practice's system in real time, and [Unified.to](http://unified.to/) keeps no patient records at rest. [Unified.to](http://unified.to/) is HIPAA compliant.