Creating Appointments Programmatically
To create appointments programmatically, you can use an M2M. Once you have created an M2M, give it the following access policy:
{
"rule": [
{
"action": [
"Zambda:InvokeFunction"
],
"effect": "Allow",
"resource": [
"Zambda:Function:create-appointment",
"Zambda:Function:get-appointments",
"Zambda:Function:search-patients"
]
}
]
}Now let's go through the steps to create an appointment.
Search patients
First we will search patients. You can search by name, date of birth, phone, and email.
curl -X POST https://project-api.zapehr.com/v1/zambda/search-patients/execute \
-H 'Authorization: Bearer your_access_token' \
-H "x-oystehr-project-id: your_project_id" \
-H "Content-Type: application/json" \
--data '{"name":"example"}'This will return a list of patients, for example:
{
"patients": [
{
"id":"b5a6496b-0bcc-49f0-8f77-95cbec5d1b5e",
"name":"Example, Example",
"firstName":"Example",
"lastName":"Example",
"dateOfBirth":"1990-01-01",
"gender":"male"
},
{
"id":"d8032f9e-da77-4cc1-9a9f-9d2a3a94ec37",
"name":"Example, Example",
"firstName":"Example",
"lastName":"Example",
"dateOfBirth":"1990-01-01",
"gender":"male"
},
{
"id":"9afe85fd-4e73-426b-86ac-d872fc528f71",
"name":"Example, Example",
"firstName":"Example",
"lastName":"Example",
"dateOfBirth":"1990-01-01",
"gender":"male",
"email":"[email protected]"
}
],
"total":3,
"offset":0
}Get a list of locations
Next we will call the list-bookables zambda to get a list of locations.
curl -X POST https://project-api.zapehr.com/v1/zambda/list-bookables/execute-public \
-H "x-oystehr-project-id: your_project_id" \
-H "Content-Type: application/json" \
--data '{"serviceMode":"in-person"}'This will return a list, for example:
{
"items": [
{
"label": "example",
"slug": "example",
"resourceType": "Location",
"resourceId": "2691f646-e16a-42e6-953a-47f7b254a77c",
"secondaryLabel": [],
"category": "example"
}
]
}Get a schedule
Next we will call the get-schedule zambda to get the schedule.
curl -X POST https://project-api.zapehr.com/v1/zambda/get-schedule/execute-public \
-H "x-oystehr-project-id: your_project_id" \
-H "Content-Type: application/json" \
--data '{"slug":"example","scheduleType":"location","serviceCategoryCode":"urgent-care"}'This will return a list of available appointments, for example:
{
"message": "Successfully retrieved all available slot times",
"available": [
{
"slot": {
"resourceType": "Slot",
"id": "48e40c33-4bd3-4e5d-92fa-7b8c3c6ebef6|2026-08-14T11:30:00.000-05:00",
"start": "2026-08-14T11:30:00.000-05:00",
"serviceCategory": [
{
"coding": [
{
"system": "https://fhir.ottehr.com/slot-service-category",
"code": "in-person-service-mode"
},
{
"system": "https://fhir.ottehr.com/CodeSystem/service-mode-service-category",
"code": "in-person-service-mode"
}
]
},
{
"coding": [
{
"system": "https://fhir.ottehr.com/CodeSystem/service-category",
"code": "urgent-care"
}
]
}
],
"end": "2026-08-14T16:45:00.000+00:00",
"schedule": {
"reference": "Schedule/48e40c33-4bd3-4e5d-92fa-7b8c3c6ebef6"
},
"status": "free"
},
"owner": {
"resourceType": "Location",
"id": "2691f646-e16a-42e6-953a-47f7b254a77c",
"name": "example"
},
"timezone": "America/New_York"
}
],
"location": {
"id": "2691f646-e16a-42e6-953a-47f7b254a77c",
"slug": "example",
"name": "example",
"telecom": [
{
"system": "phone",
"use": "work",
"value": "1234567890"
}
],
"timezone": "America/New_York",
"otherOffices": [],
"scheduleOwnerType": "location",
"scheduleExtension": {
"schedule": {
"monday": {
"open": 8,
"close": 20,
"openingBuffer": 0,
"closingBuffer": 0,
"workingDay": true,
"hours": [
{
"hour": 0,
"capacity": 4
},
{
"hour": 1,
"capacity": 4
},
{
"hour": 2,
"capacity": 4
}
]
}
},
"scheduleOverrides": {}
}
},
"displayTomorrowSlotsAtHour": 9,
"waitingMinutes": 0,
"timezone": "America/New_York"
}Create a slot
Next we will the create-slot zambda to create a slot.
curl -X POST https://project-api.zapehr.com/v1/zambda/create-slot/execute-public \
-H "x-oystehr-project-id: your_project_id" \
-H "Content-Type: application/json" \
--data '{"scheduleId":"e4dbd91f-084b-4ce7-a809-4ef2dc231307","startISO":"2026-08-14T13:30:00.000-05:00","lengthInMinutes":15,"serviceModality":"in-person","walkin":false,"postTelemedLabOnly":false,"serviceCategoryCode":"urgent-care"}'This will return a slot, for example:
{
"resourceType": "Slot",
"status": "busy",
"start": "2026-08-14T13:30:00.000-05:00",
"end": "2026-08-14T13:45:00.000-05:00",
"serviceCategory": [
{
"coding": [
{
"system": "https://fhir.ottehr.com/slot-service-category",
"code": "in-person-service-mode"
},
{
"system": "https://fhir.ottehr.com/CodeSystem/service-mode-service-category",
"code": "in-person-service-mode"
}
]
},
{
"coding": [
{
"display": "Urgent Care",
"code": "urgent-care",
"system": "https://fhir.ottehr.com/CodeSystem/service-category"
}
]
}
],
"schedule": {
"reference": "Schedule/48e40c33-4bd3-4e5d-92fa-7b8c3c6ebef6"
},
"id": "f056a186-d3fd-4139-afa8-f620c23c0aaf"
}Create an appointment
Next we will call the create-appointment zambda to create an appointment. If it is a new patient, do not include the patient ID.
curl -X POST https://project-api.zapehr.com/v1/zambda/create-appointment/execute \
-H "x-oystehr-project-id: your_project_id" \
-H 'Authorization: Bearer your_access_token' \
-H "Content-Type: application/json" \
--data '{"patient":{"id":"15bf1b59-6944-485b-97d8-0ea2404df614","newPatient":false,"dateOfBirth":"1990-01-01","phoneNumber":"1234567890","firstName":"Example","lastName":"Example","sex":"male","reasonForVisit":"Allergies or Allergic reaction"},"slotId":"f056a186-d3fd-4139-afa8-f620c23c0aaf"}'This will return details about the appointment, for example:
{
"message": "Successfully created an appointment and encounter",
"appointmentId": "7fe3d73a-f1a2-4f8c-98e2-6a15c6688060",
"fhirPatientId": "76900ad8-de80-4d64-af8e-aae524913296",
"questionnaireResponseId": "d0105049-046e-47b9-9b1b-961c67fec396",
"encounterId": "9af10a1b-10d3-4ed2-b7a2-c52f20575da3",
"resources": {
"appointment": {
"resourceType": "Appointment",
"meta": {
"tag": [
{
"code": "OTTEHR-IP"
},
{
"system": "created-by",
"display": "Staff [email protected]"
},
{
"system": "appointment-preprocessing-status",
"code": "APPOINTMENT_READY_FOR_PREPROCESSING"
}
]
},
"participant": [
{
"actor": {
"reference": "Patient/76900ad8-de80-4d64-af8e-aae524913296"
},
"status": "accepted"
},
{
"actor": {
"reference": "Location/2691f646-e16a-42e6-953a-47f7b254a77c"
},
"status": "accepted"
}
],
"start": "2026-08-14T17:30:00.000Z",
"end": "2026-08-14T17:45:00.000Z",
"slot": [
{
"reference": "Slot/e3d6d982-607a-4e49-83a5-654c4750e0c4"
}
],
"appointmentType": {
"text": "walkin"
},
"serviceCategory": [
{
"coding": [
{
"system": "https://fhir.ottehr.com/slot-service-category",
"code": "in-person-service-mode"
},
{
"system": "https://fhir.ottehr.com/CodeSystem/service-mode-service-category",
"code": "in-person-service-mode"
}
]
},
{
"coding": [
{
"display": "Urgent Care",
"code": "urgent-care",
"system": "https://fhir.ottehr.com/CodeSystem/service-category"
}
]
}
],
"description": "Allergies or Allergic reaction",
"status": "arrived",
"created": "2026-08-14T17:00:00.000Z",
"extension": [],
"id": "7fe3d73a-f1a2-4f8c-98e2-6a15c6688060"
},
"encounter": {
"resourceType": "Encounter",
"status": "arrived",
"statusHistory": [
{
"status": "arrived",
"period": {
"start": "2026-08-14T17:00:00.000Z"
}
}
],
"class": {
"system": "http://hl7.org/fhir/R4/v3/ActEncounterCode/vs.html",
"code": "ACUTE",
"display": "inpatient acute"
},
"subject": {
"reference": "Patient/76900ad8-de80-4d64-af8e-aae524913296"
},
"appointment": [
{
"reference": "Appointment/7fe3d73a-f1a2-4f8c-98e2-6a15c6688060"
}
],
"location": [
{
"location": {
"reference": "Location/2691f646-e16a-42e6-953a-47f7b254a77c"
}
}
],
"id": "9af10a1b-10d3-4ed2-b7a2-c52f20575da3",
},
"questionnaire": {
"resourceType": "QuestionnaireResponse",
"questionnaire": "https://ottehr.com/FHIR/Questionnaire/intake-paperwork-inperson|1.2.7",
"status": "in-progress",
"meta": {
"tag": [
{
"system": "https://fhir.ottehr.com/CodeSystem/questionnaire-response-type",
"code": "intake-paperwork"
}
],
"versionId": "51e17d40-9edd-493e-a963-4797ce1e4258",
"lastUpdated": "2026-08-14T17:10:54.129Z"
},
"subject": {
"reference": "Patient/76900ad8-de80-4d64-af8e-aae524913296"
},
"encounter": {
"reference": "Encounter/9af10a1b-10d3-4ed2-b7a2-c52f20575da3"
},
"item": [
{
"linkId": "contact-information-page",
"item": [
{
"linkId": "photo-id-front"
},
{
"linkId": "photo-id-back"
},
{
"linkId": "patient-street-address"
},
{
"linkId": "patient-street-address-2"
},
{
"linkId": "patient-city"
},
{
"linkId": "patient-state"
},
{
"linkId": "patient-zip"
},
{
"linkId": "patient-email"
},
{
"linkId": "patient-number",
"answer": [
{
"valueString": "(123) 456-7890"
}
]
},
{
"linkId": "patient-preferred-communication-method"
},
{
"linkId": "mobile-opt-in"
},
{
"linkId": "is-new-qrs-patient",
"answer": [
{
"valueBoolean": false
}
]
},
{
"linkId": "patient-first-name",
"answer": [
{
"valueString": "Example"
}
]
},
{
"linkId": "patient-last-name",
"answer": [
{
"valueString": "Example"
}
]
},
{
"linkId": "patient-birthdate",
"answer": [
{
"valueString": "1990-01-01"
}
]
},
{
"linkId": "patient-birth-sex",
"answer": [
{
"valueString": "Male"
}
]
},
{
"linkId": "appointment-service-category",
"answer": [
{
"valueString": "urgent-care"
}
]
},
{
"linkId": "reason-for-visit",
"answer": [
{
"valueString": "Allergies or Allergic reaction"
}
]
}
]
}
],
"id": "d0105049-046e-47b9-9b1b-961c67fec396"
},
"patient": {
"id": "76900ad8-de80-4d64-af8e-aae524913296",
"name": [
{
"use": "official",
"given": [
"Example"
],
"family": "Example"
}
],
"active": true,
"gender": "male",
"birthDate": "1990-01-01",
"resourceType": "Patient",
}
}
}Get a list of appointments
Next we will call the get-appointments zambda to get a list appointments.
curl -X POST https://project-api.zapehr.com/v1/zambda/get-appointments/execute \
-H "x-oystehr-project-id: your_project_id" \
-H 'Authorization: Bearer your_access_token' \
-H "Content-Type: application/json" \
--data '{"searchDateFrom":"2026-08-14","searchDateTo":"2026-08-14","timezone":"America/New_York","locationIds":["2691f646-e16a-42e6-953a-47f7b254a77c"],"providerIds":[],"serviceCategories":[],"visitType":["in-person-walk-in","in-person-pre-booked","in-person-post-telemed","virtual-walk-in","virtual-pre-booked"],"supervisorApprovalEnabled":false}'This will return a list of appointments, for example:
{
"message": "Successfully retrieved all appointments",
"preBooked": [
{
"id": "7fe3d73a-f1a2-4f8c-98e2-6a15c6688060",
"encounter": {
"resourceType": "Encounter",
"status": "planned",
"class": {
"system": "http://hl7.org/fhir/R4/v3/ActEncounterCode/vs.html",
"code": "ACUTE",
"display": "inpatient acute"
},
"id": "9af10a1b-10d3-4ed2-b7a2-c52f20575da3",
"appointment": [
{
"reference": "Appointment/7fe3d73a-f1a2-4f8c-98e2-6a15c6688060"
}
],
"statusHistory": [
{
"status": "planned",
"period": {
"start": "2026-08-14T15:45:13.169Z"
}
}
],
"location": [
{
"location": {
"reference": "Location/2691f646-e16a-42e6-953a-47f7b254a77c"
}
}
]
},
"encounterId": "9af10a1b-10d3-4ed2-b7a2-c52f20575da3",
"start": "2026-08-14T13:30:00.000-05:00",
"patient": {
"id": "76900ad8-de80-4d64-af8e-aae524913296",
"firstName": "Example",
"lastName": "Example",
"sex": "male",
"dateOfBirth": "1990-01-01"
},
"reasonForVisit": "Cough and/or congestion",
"appointmentType": "pre-booked",
"appointmentAttendanceType": "in-person",
"appointmentStatus": "booked",
"status": "pending",
"provider": "",
"paperwork": {
"demographics": false,
"photoID": false,
"insuranceCard": false,
"consent": false,
"ovrpInterest": false
},
"participants": {},
"next": false,
"visitStatusHistory": [
{
"status": "pending",
"period": {
"start": "2026-08-14T15:45:13.169Z"
}
}
],
"serviceCategory": "Urgent Care",
"location": {
"resourceType": "Location",
"id": "ba60ab0e-28cd-489d-82fa-f43a293398a0",
"name": "Castroville",
"telecom": [
{
"system": "phone",
"use": "work",
"value": "1234567890"
}
]
}
}
],
"inOffice": [],
"completed": [],
"cancelled": []
}