Learn · PatientNow Pro
Recipes — PatientNow Pro
The reference documents one endpoint at a time. Real features chain several together. Here are three end-to-end workflows for the PatientNow Pro API — showing how one call's output feeds the next.
These recipes use the PNP base URL
(https://backend-production.patientnow.net/backend/patientnowpro),
token auth (Authorization: YOUR_TOKEN), practice-scoped paths
(/practices/{practiceId}/…), and integer IDs. If you're on PNE or
VISH, see the PNE & VISH recipes → instead.
The setup these recipes share
Every snippet below assumes an authenticated client from the
PNP quickstart — a session with the
Authorization header baked in and the practice ID stored, so we
don't repeat auth on every call:
# Each curl below omits these for brevity — add them to every request:
# -H "Authorization: YOUR_TOKEN"
# And substitute YOUR_PRACTICE_ID throughout.const base = "https://backend-production.patientnow.net/backend/patientnowpro";
const practiceId = "YOUR_PRACTICE_ID";
const authHeader = { Authorization: "YOUR_TOKEN" };import requests
base = "https://backend-production.patientnow.net/backend/patientnowpro"
practice_id = "YOUR_PRACTICE_ID"
s = requests.Session()
s.headers["Authorization"] = "YOUR_TOKEN" # sent on every requestusing System.Net.Http;
var http = new HttpClient {
BaseAddress = new Uri("https://backend-production.patientnow.net/backend/patientnowpro/")
};
http.DefaultRequestHeaders.Add("Authorization", "YOUR_TOKEN");
var practiceId = "YOUR_PRACTICE_ID";Creating appointments and waitlist entries changes real practice data immediately — there's no sandbox. Run writes against records you can clean up afterward.
Look up a patient and read their appointments
Find a patient by name, then pull their upcoming appointments using the patient's integer ID as the thread between calls.
- Search for the patient — GET
/practices/{practiceId}/patients - Read their appointments — GET
/practices/{practiceId}/patients/{patientId}/appointments
1 · Search for the patient
Filter by LastName, FirstName, DOB, or
CellPhone. The response includes a patientId integer
you carry into subsequent calls.
curl "https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/patients?LastName=Smith&FirstName=Jane&Limit=5" \
-H "Authorization: YOUR_TOKEN"
# → { "data": [ { "patientId": 12345, "firstName": "Jane", "lastName": "Smith", ... } ], ... }const res = await fetch(`${base}/practices/${practiceId}/patients?LastName=Smith&FirstName=Jane&Limit=5`, { headers: authHeader });
const { data } = await res.json();
const patientId = data[0].patientId;result = s.get(
f"{base}/practices/{practice_id}/patients",
params={"LastName": "Smith", "FirstName": "Jane", "Limit": 5},
).json()
patient = result["data"][0]
patient_id = patient["patientId"] # integer, e.g. 12345var res = await http.GetAsync($"practices/{practiceId}/patients?LastName=Smith&FirstName=Jane&Limit=5");
var body = await res.Content.ReadFromJsonAsync<JsonElement>();
var patientId = body.GetProperty("data").EnumerateArray().First().GetProperty("patientId").GetInt32();2 · Read their appointments
Pass the patientId in the path. Narrow the window with
Page and Limit as needed.
curl "https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/patients/12345/appointments?Limit=10" \
-H "Authorization: YOUR_TOKEN"const res = await fetch(`${base}/practices/${practiceId}/patients/${patientId}/appointments?Limit=10`, { headers: authHeader });
const { data: appts } = await res.json();
appts.forEach(a => console.log(a.appointmentId, a.apptDate));appts = s.get(
f"{base}/practices/{practice_id}/patients/{patient_id}/appointments",
params={"Limit": 10},
).json()
for a in appts["data"]:
print(a["appointmentId"], a["apptDate"])var res = await http.GetAsync($"practices/{practiceId}/patients/{patientId}/appointments?Limit=10");
var body = await res.Content.ReadFromJsonAsync<JsonElement>();
foreach (var a in body.GetProperty("data").EnumerateArray())
Console.WriteLine($"{a.GetProperty("appointmentId")} {a.GetProperty("apptDate")}");Full field lists: PNP API reference →
Book from an availability slot
Turn "this patient wants this event type with this provider" into a confirmed appointment. You query the scheduling availability endpoints to find open slots, then write the appointment into one.
- Find providers for an event type — GET
/practices/{practiceId}/scheduling/availability/providers - Get open slots — GET
/practices/{practiceId}/scheduling/availability/slots - Book the appointment — POST
/practices/{practiceId}/appointments
1 · Find available providers for an event type
You need an eventTypeId (from
GET /practices/{practiceId}/event-types) and optionally a
serviceFacilityId to scope to a location. The response lists providers
who offer that event type.
curl "https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/scheduling/availability/providers?EventTypeId=EVENT_TYPE_ID" \
-H "Authorization: YOUR_TOKEN"const etRes = await fetch(`${base}/practices/${practiceId}/event-types`, { headers: authHeader });
const { data: eventTypes } = await etRes.json();
const eventTypeId = eventTypes[0].eventTypeId;
const pvRes = await fetch(`${base}/practices/${practiceId}/scheduling/availability/providers?EventTypeId=${eventTypeId}`, { headers: authHeader });
const { data: providers } = await pvRes.json();
const providerId = providers[0].provider.providerId;# First, pick an event type:
event_types = s.get(f"{base}/practices/{practice_id}/event-types").json()
event_type_id = event_types["data"][0]["eventTypeId"]
# Then find providers who offer it:
providers = s.get(
f"{base}/practices/{practice_id}/scheduling/availability/providers",
params={"EventTypeId": event_type_id},
).json()
provider_id = providers["data"][0]["provider"]["providerId"]var etRes = await http.GetAsync($"practices/{practiceId}/event-types");
var etBody = await etRes.Content.ReadFromJsonAsync<JsonElement>();
var eventTypeId = etBody.GetProperty("data").EnumerateArray().First().GetProperty("eventTypeId").GetInt32();
var pvRes = await http.GetAsync($"practices/{practiceId}/scheduling/availability/providers?EventTypeId={eventTypeId}");
var pvBody = await pvRes.Content.ReadFromJsonAsync<JsonElement>();
var providerId = pvBody.GetProperty("data").EnumerateArray().First().GetProperty("provider").GetProperty("providerId").GetInt32();2 · Query open slots
Pass EventTypeId, ProviderId, and a Start/
End date range. The response groups open slots by provider.
curl "https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/scheduling/availability/slots?EventTypeId=EVENT_TYPE_ID&ProviderId=PROVIDER_ID&Start=2026-08-01&End=2026-08-07" \
-H "Authorization: YOUR_TOKEN"const qs = new URLSearchParams({ EventTypeId: eventTypeId, ProviderId: providerId, Start: "2026-08-01", End: "2026-08-07" });
const res = await fetch(`${base}/practices/${practiceId}/scheduling/availability/slots?${qs}`, { headers: authHeader });
const { data: slotsData } = await res.json();
const firstSlot = slotsData[0].slots[0];slots_result = s.get(
f"{base}/practices/{practice_id}/scheduling/availability/slots",
params={
"EventTypeId": event_type_id,
"ProviderId": provider_id,
"Start": "2026-08-01",
"End": "2026-08-07",
},
).json()
first_slot = slots_result["data"][0]["slots"][0] # a datetime stringvar res = await http.GetAsync($"practices/{practiceId}/scheduling/availability/slots?EventTypeId={eventTypeId}&ProviderId={providerId}&Start=2026-08-01&End=2026-08-07");
var body = await res.Content.ReadFromJsonAsync<JsonElement>();
var firstSlot = body.GetProperty("data").EnumerateArray().First().GetProperty("slots").EnumerateArray().First().GetString();3 · Create the appointment
POST /practices/{practiceId}/appointments with the patient, event type,
provider, and the chosen slot datetime. A 201 Created returns the new
appointmentId.
curl -X POST \
"https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/appointments" \
-H "Authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"patientId": 12345,
"eventTypeId": EVENT_TYPE_ID,
"providerId": PROVIDER_ID,
"apptDate": "2026-08-04T10:00:00"
}'const res = await fetch(`${base}/practices/${practiceId}/appointments`, {
method: "POST",
headers: { ...authHeader, "Content-Type": "application/json" },
body: JSON.stringify({
patientId: patientId, eventTypeId: eventTypeId,
providerId: providerId, apptDate: firstSlot,
}),
});
const { appointmentId } = await res.json();
console.log("new appointment:", appointmentId);booked = s.post(
f"{base}/practices/{practice_id}/appointments",
json={
"patientId": patient_id,
"eventTypeId": event_type_id,
"providerId": provider_id,
"apptDate": first_slot,
},
).json()
print("new appointment:", booked["appointmentId"])var body = JsonSerializer.Serialize(new {
patientId, eventTypeId, providerId, apptDate = firstSlot
});
var res = await http.PostAsync(
$"practices/{practiceId}/appointments",
new StringContent(body, Encoding.UTF8, "application/json"));
var result = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"new appointment: {result.GetProperty("appointmentId")}");Add a patient to the waitlist
When no slot is available right now, add the patient to the waitlist with their preferred days, times, and event type. If a matching slot opens, the practice can offer it to waitlisted patients.
- Create the waitlist entry — POST
/practices/{practiceId}/waitlist - Confirm it landed — GET
/practices/{practiceId}/waitlist/{waitlistId}
1 · Create the waitlist entry
Specify the patient, event type, preferred days/times, and an optional date
range. daysOfWeek and timesOfDay are enum strings —
see the PNP reference for
valid values.
curl -X POST \
"https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/waitlist" \
-H "Authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"patientId": 12345,
"eventTypeId": EVENT_TYPE_ID,
"providerIds": [PROVIDER_ID],
"daysOfWeek": "Monday,Wednesday,Friday",
"timesOfDay": "Morning",
"dateRangeStart": "2026-08-01",
"dateRangeEnd": "2026-09-30",
"comments": "Prefers mornings, any provider"
}'const res = await fetch(`${base}/practices/${practiceId}/waitlist`, {
method: "POST",
headers: { ...authHeader, "Content-Type": "application/json" },
body: JSON.stringify({
patientId: patientId, eventTypeId: eventTypeId,
providerIds: [providerId],
daysOfWeek: "Monday,Wednesday,Friday", timesOfDay: "Morning",
dateRangeStart: "2026-08-01", dateRangeEnd: "2026-09-30",
comments: "Prefers mornings, any provider",
}),
});
const { waitlistId } = await res.json();
console.log("waitlist entry:", waitlistId);entry = s.post(
f"{base}/practices/{practice_id}/waitlist",
json={
"patientId": patient_id,
"eventTypeId": event_type_id,
"providerIds": [provider_id],
"daysOfWeek": "Monday,Wednesday,Friday",
"timesOfDay": "Morning",
"dateRangeStart": "2026-08-01",
"dateRangeEnd": "2026-09-30",
"comments": "Prefers mornings, any provider",
},
).json()
waitlist_id = entry["waitlistId"]
print("waitlist entry:", waitlist_id)var body = JsonSerializer.Serialize(new {
patientId, eventTypeId,
providerIds = new[] { providerId },
daysOfWeek = "Monday,Wednesday,Friday", timesOfDay = "Morning",
dateRangeStart = "2026-08-01", dateRangeEnd = "2026-09-30",
comments = "Prefers mornings, any provider",
});
var res = await http.PostAsync(
$"practices/{practiceId}/waitlist",
new StringContent(body, Encoding.UTF8, "application/json"));
var result = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"waitlist entry: {result.GetProperty("waitlistId")}");2 · Confirm the entry
Read it back by waitlistId to confirm the details landed correctly.
curl "https://backend-production.patientnow.net/backend/patientnowpro/practices/YOUR_PRACTICE_ID/waitlist/WAITLIST_ID" \
-H "Authorization: YOUR_TOKEN"const res = await fetch(`${base}/practices/${practiceId}/waitlist/${waitlistId}`, { headers: authHeader });
const entry = await res.json();
console.log(entry.patient.firstName, "→", entry.eventType.name);entry = s.get(f"{base}/practices/{practice_id}/waitlist/{waitlist_id}").json()
print(entry["patient"]["firstName"], "→", entry["eventType"]["name"],
entry["dateFrom"], "–", entry["dateTo"])var res = await http.GetAsync($"practices/{practiceId}/waitlist/{waitlistId}");
var entry = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"{entry.GetProperty("patient").GetProperty("firstName")} → {entry.GetProperty("eventType").GetProperty("name")}");The PNP API distinguishes between a waitlist entry
(/waitlist — the patient's standing request) and
waitlist slots (/waitlist-slots — specific openings
matched against waitlisted patients). Use
GET /practices/{practiceId}/waitlist-slots to see slots that have
been offered, and PUT …/close to mark one as filled or declined.
All three use the same conventions: integer IDs passed verbatim,
Page/Limit pagination on list calls, and
status-code-first error handling.
See Guides & concepts for the full picture, and
the PNP auth page for token setup.