Scheduling
Patient Self-Scheduling
Client self-scheduling is a common use case for our API. With the API, you can build a self-scheduling experience with a much more customized UI than Healthie’s built-in embeds allow for.
Our example repo is an example (built with React) on how to implement self-scheduling with the API. Let’s break down the API calls we make in that widget.
query appointmentTypes($clients_can_book: Boolean, $provider_id: String) { appointmentTypes(provider_id: $provider_id, clients_can_book: $clients_can_book) { id name length available_contact_types is_group }}
1) Get Potential Appointment and Contact Types
All self-scheduled appointments in Healthie require an appointment type and a contact type. In this appointmentTypes
query, we grab all appointment types that are bookable by clients, and the contact type options for each appointment type. We will use these in subsequent queries to receive accurate availability, and ultimately book the appointment. If you already know what appointment type and contact type you want the user to book, you can skip this step, and proceed to step 2.
query daysAvailableForRange( $provider_id: String $date_from_month: String $org_level: Boolean $timezone: String $provider_ids: [String] $appt_type_id: String) { daysAvailableForRange( provider_id: $provider_id date_from_month: $date_from_month org_level: $org_level timezone: $timezone provider_ids: $provider_ids appt_type_id: $appt_type_id )}
2) Get Available Days
A very common self-scheduling UI component is to present the client with days that have open time. The client then selects a day to see the specific available time slots. This interface is used in Healthie’s hosted widgets, in the open source example, and in other popular tools like Calendly. To power this, we can call the availableDaysForRange
query.
This query example shows six arguments, but only three are required, provider_id
, date_from_month
, and appt_type_id
.
appt_type_id
is the ID of the appointment type you grabbed in step 1. provider_id
is the ID of the provider (or just a provider in the organization in the case of searching availability across multiple providers), and date_from_month
is a date (e.g “2021-10-10”) in the month that you want to search available days in.
To briefly go over some of the other potential arguments, org_level
determines if you want availability just for the given provider_id
, or for multiple providers in the given provider’s organization. It defaults to false.
If you send in org_level
as true, you can also send in an array of provider_ids
. This argument lets you search against a given subset of providers in the organization. For example, my organization has 10 providers, I can send in an array with five ids, and the query will only return availabilities for those five providers.
Finally, the timezone
argument determines what timezone to calculate the availability in. It takes in a TZ database name. If you don’t send this in, the query will use the provider’s timezone.
This query will return an array of days with availability from the given month. e.g [“2021-10-10”, “2021-10-15”, “2021-10-20”]. We then have the user select a day, and move to step 3. If we already knew the appointment type, contact type, and date the user wanted, we could have skipped the first two steps.
query availableSlotsForRange( $provider_id: String $start_date: String $end_date: String $org_level: Boolean $timezone: String $provider_ids: [String] $appt_type_id: String) { availableSlotsForRange( provider_id: $provider_id start_date: $start_date end_date: $end_date timezone: $timezone org_level: $org_level provider_ids: $provider_ids appt_type_id: $appt_type_id ) { user_id date }}
3) Get Available Slots
Now that we have the day, the next step is to get specific available time slots on that day. To do so, we use the availableSlotsForRange
query. Six of the above arguments match daysAvailableForRange
. In all cases, those arguments do the same thing, so let’s focus on one, start_date
and end_date
.
start_date
and end_date
are both required and are used to set up the range of time that we check availability for. For example, if I send in a start_date
of “2021-10-10”, an end_date
of “2021-10-12”, and a timezone of America/New_York
, the query will check availability starting at “2021-10-10 00:00:00 EDT -04:00” to “2021-10-12 23:59:59 EDT -04:00”.
In our case, we are just checking availability on one day, so we would send in an identical start_date
and end_date
.
Input | Info |
---|---|
provider_id | Required. The ID of the provider to search available slots for. |
start_date | Required. Date in the YYYY-MM-DD format indicating the lower date range boundary to return available slots for. |
end_date | Required. Date in the YYYY-MM-DD format indicating the upper date range boundary to return available slots for. |
timezone | Timezone used for the start_date and end_date arguments. Defaults to the patient’s timezone. Timezone value must be on this list of timezone identifiers. |
start_date_boundary | Date in the YYYY-MM-DD format indicating. If provided, the query will not return any slots before this date even if start_date is before this date. |
end_date_boundary | Date in the YYYY-MM-DD format. If provided, the query will not return any slots after this date even if end_date is after this date. |
The query returns an array of PotentialAppointmentSlots
. We have the user select one of those slots, and use the user_id
and date
from the slot in the next (and final) step. Please note the date
here is a full datetime string (e.g “2021-10-10 10:00:00 EDT -04:00”) and user_id
is the ID of the available provider.
mutation completeCheckout( $appointment_type_id: String $contact_type: String $date: String $first_name: String $last_name: String $email: String $phone_number: String $provider_id: String $timezone: String) { completeCheckout( input: { appointment_type_id: $appointment_type_id contact_type: $contact_type date: $date timezone: $timezone first_name: $first_name last_name: $last_name email: $email phone_number: $phone_number provider_id: $provider_id } ) { appointment { provider { id full_name } id date contact_type appointment_type { id name length } } messages { field message } }}
4) Book the Appointment
Now, we have the desired appointment type, contact type, appointment date/time, and provider. That means we have everything we need to schedule the appointment. To do so, we use the completeCheckout
mutation.
The contact_type
, date
, timezone
, appointment_type_id
, and provider_id
should match what we collected in the prior steps.
If the client is authenticated, then those are the only fields you need. However, in our example, the client is unauthenticated, so we need to send in some info about them as well. That extra info (email
, first_name
, last_name
, and phone_number
) are used to either match the appointment to an existing client in the provider’s account, or create a client record on the fly.
Patient Rescheduling
In addition to scheduling new appointments, The Healthie API can also be used to allow patients to reschedule already booked ones. A patient’s ability to reschedule is controlled by your appointment settings. You can find more info on adjusting those here.
The rescheduling workflow is similar to self-scheduling, but has some key differences. Here are the API steps we use for patient rescheduling. All of the below steps are meant to be taken from an authenticated patient account.
query appointments( $filter: String # "upcoming" $should_paginate: Boolean # true $is_active: Boolean # true) { appointmentsCount(filter: $filter, is_active: $is_active) appointments(is_active: $is_active, filter: $filter, should_paginate: $should_paginate) { id date other_party_id appointment_type_id }}
1) Get The Appointment ID
To check availability and reschedule an appointment, you will need the ID for the appointment, the provider (other_party_id
), and appointment type. Here’s a query to get paginated upcoming active appointments for a patient. These IDs will be used in the subsequent steps.
query daysAvailableForRange( $provider_id: String # Should be the other_party_id from Step 1 $date_from_month: String $timezone: String $appt_type_id: String # should be the appointment_type_id from Step 1 $appointment_to_reschedule_id: ID # should be the ID of the appointment from Step 1) { daysAvailableForRange( provider_id: $provider_id date_from_month: $date_from_month timezone: $timezone appt_type_id: $appt_type_id appointment_to_reschedule_id: $appointment_to_reschedule_id )}
2) Get Available Days
In our rescheduling UI, we present the patient with days that have open time. The patient then selects a day to see the specific available time slots. To power this, we can call the availableDaysForRange
query.
Input | Info |
---|---|
provider_id | Required. The provider whose availability should be checked. Needs to match the other_party_id of the appointment that is being rescheduled. |
appt_type_id | Required. The ID of the appointment’s appointment type. Needs to match the appointment_type_id of the appointment that is being rescheduled. |
date_from_month | Required. A date (e.g “2021-11-20”) from the month that you want to check available days in. |
appointment_to_reschedule_id | Required. Needs to match the id of the appointment that is being rescheduled. |
timezone | Optional. Determines what timezone to calculate the availability in. Defaults to the patient account’s timezone. Timezone value must be on this list of timezone identifiers. |
This query will return an array of days with availability from the given month. e.g [“2021-11-20”, “2021-11-28”, “2021-11-29”]. We then have the patient select a day, and move to step 3.
query availableSlotsForRange( $provider_id: String $start_date: String $end_date: String $timezone: String $appt_type_id: String $appointment_to_reschedule_id: ID) { availableSlotsForRange( provider_id: $provider_id start_date: $start_date end_date: $end_date timezone: $timezone appt_type_id: $appt_type_id appointment_to_reschedule_id: $appointment_to_reschedule_id ) { user_id date }}
3) Get Available Slots
Now that we have the day, the next step is to get specific available time slots on that day. To do so, we use the availableSlotsForRange
query. The arguments are very similar to the daysAvailableForRange
. In all cases, those arguments do the same thing, so let’s focus on the one difference, start_date
and end_date
.
start_date
and end_date
are both required and are used to set up the range of time that we check availability for. For example, if I send in a start_date
of “2021-10-10”, an end_date
of “2021-10-12”, and a timezone of America/New_York
, the query will check availability starting at “2021-10-10 00:00:00 EDT -04:00” to “2021-10-12 23:59:59 EDT -04:00”.
In our case, we are just checking availability on one day, so we would send in an identical start_date
and end_date
.
Input | Info |
---|---|
provider_id | Required. The ID of the provider to search available slots for. |
start_date | Required. Date in the YYYY-MM-DD format indicating the lower date range boundary to return available slots for. |
end_date | Required. Date in the YYYY-MM-DD format indicating the upper date range boundary to return available slots for. |
timezone | Timezone used for the start_date and end_date arguments. Defaults to the patient’s timezone. |
start_date_boundary | Date in the YYYY-MM-DD format indicating. If provided, the query will not return any slots before this date even if start_date is before this date. |
end_date_boundary | Date in the YYYY-MM-DD format. If provided, the query will not return any slots after this date even if end_date is after this date. |
The query returns an array of PotentialAppointmentSlots
. We have the user select one of those slots, and use the user_id
and date
from the slot in the next (and final) step. Please note the date
here is a full datetime string (e.g “2021-10-10 10:00:00 EDT -04:00”) and user_id
is the ID of the available provider.
mutation updateAppointment( $client_updating: Boolean, # true $datetime: String, $id: ID, ) { updateAppointment( input: { $client_updating: Boolean, $datetime: String, $id: ID, } ) { appointment { id date } messages { field message } } }
4) Update the Appointment
Finally, we can use the updateAppointment
mutation to move the appointment to the new available slot.
Input | Info |
---|---|
id | Required. The ID of the appointment to update. |
datetime | Required. This should be the date from the slot that was selected in the previous step. |
client_updating | Required. Needs to be true. |
In the case that the slot is no longer available (e.g another patient simultaneously booked an appointment for the same slot), an error will be returned in the messages
of the response.