Developers

Learn · PatientNow Pro

Guides & concepts — PatientNow Pro

The conventions that hold across every PNP resource. Learn these once and the whole API becomes predictable.

ℹ️ PNP is a separate platform

PatientNow Pro has a different host, auth scheme, field casing, and ID format from PNE and VISH. If you're on PNE or VISH, see Guides & concepts — PNE & VISH → instead.

Request basics

Pagination

All list endpoints use two query parameters:

ParameterTypeDefaultMeaning
Pageinteger11-based page number.
LimitintegervariesRecords per page.

Walk a collection by incrementing Page until a page returns fewer records than Limit (or an empty data array):

def iter_patients(session, base, practice_id, limit=50, **filters):
    page = 1
    while True:
        res = session.get(
            f"{base}/practices/{practice_id}/patients",
            params={"Page": page, "Limit": limit, **filters},
        )
        res.raise_for_status()
        batch = res.json().get("data", [])
        if not batch:
            return
        yield from batch
        if len(batch) < limit:
            return
        page += 1
async function* iterPatients(base, headers, practiceId, limit = 50, filters = {}) {
  let page = 1;
  for (;;) {
    const qs = new URLSearchParams({ Page: page, Limit: limit, ...filters });
    const res = await fetch(`${base}/practices/${practiceId}/patients?${qs}`, { headers });
    const { data = [] } = await res.json();
    if (!data.length) return;
    yield* data;
    if (data.length < limit) return;
    page++;
  }
}
📎 Response envelope

PNP list endpoints wrap results in a { "data": [...] } envelope rather than returning a bare array. Always read from .data, and guard for an empty or missing array when no records match.

Filtering & search

Common filter parameters available on list endpoints:

ParameterApplies toExample
LastName, FirstName, DOB, CellPhonePatients?LastName=Smith
MatchExactNamePatients?MatchExactName=true — exact match instead of prefix
LastModifiedPatientsISO datetime — incremental sync
ApptDateAppointments?ApptDate=2026-08-01
IncludeCancelled, IncludeNoShow, IncludeDeletedAppointmentsBoolean flags to widen results
ℹ️ Incremental sync with LastModified

To keep a local copy of patients in sync, store the timestamp of your last run and pass it as LastModified to pull only records changed since then. Combine with pagination to page through the deltas.

Resource IDs

PNP returns plain integer IDs for all resources — patients, appointments, providers, event types, and so on. They appear directly in path parameters and response bodies:

// A patient response — IDs are integers:
{ "patientId": 12345, "firstName": "Jane", "lastName": "Smith", ... }

// Use the integer directly in the next call:
GET /practices/YOUR_PRACTICE_ID/patients/12345/appointments
📎 Different from PNE/VISH

PNE and VISH return opaque encrypted strings for IDs. If you're building an integration that touches both platforms, keep the ID types separate — don't mix integer PNP IDs with encrypted PNE/VISH IDs.

Dates & times

Practice scoping

Every PNP endpoint is rooted under a practice:

https://backend-production.patientnow.net/backend/patientnowpro/practices/{practiceId}/...

Your practiceId is a fixed integer assigned to your practice. All data — patients, appointments, providers, event types — is scoped to it. There is no cross-practice access from a single token.

ResourcePath pattern
Patients/practices/{practiceId}/patients
Appointments/practices/{practiceId}/appointments
Providers/practices/{practiceId}/providers
Event types/practices/{practiceId}/event-types
Availability slots/practices/{practiceId}/scheduling/availability/slots
Waitlist/practices/{practiceId}/waitlist

Errors & status codes

PNP uses standard HTTP status codes. The status line is the primary signal; a JSON problem-details body may accompany errors.

CodeMeaningWhat to do
200 OKSuccessful read or update.Parse the body.
201 CreatedSuccessful create.Read the new record's ID from the response body.
400 Bad RequestValidation failed — missing or invalid fields.Check the error body for field-level detail; fix the payload.
401 UnauthorizedMissing or invalid token.See 401/403 causes.
403 ForbiddenToken valid but no access to this practice or resource.Confirm your token is scoped to the correct practice ID.
404 Not FoundNo such record, or not visible to this token.Re-check the ID and practice scope.
500 Server ErrorUnexpected server-side failure.Retry with backoff; if it persists, contact support.
📎 Build defensively

Always branch on the status code before parsing. A non-2xx response may have an empty or non-JSON body. Check for both 401 and 403 — PNP distinguishes unauthenticated (401) from unauthorized (403) more consistently than PNE/VISH does.