Learn · RxPhoto
Guides & concepts — RxPhoto
The conventions that hold across every RxPhoto resource. Learn these once and the whole API becomes predictable.
RxPhoto has a different host, auth scheme, field casing, and pagination style from PNE and VISH. If you're on PNE or VISH, see Guides & concepts — PNE & VISH → instead.
Request basics
- Protocol: REST over HTTPS.
- Base URL:
https://api.rxphoto.com. - Paths: most endpoints sit under
/api/v3/and end in a trailing slash (e.g./api/v3/patient/); check each operation in the reference for its exact path. - Format: primarily JSON request and response bodies — send
Content-Type: application/jsononPOST,PUT, andPATCH. Some operations return files such asapplication/pdf. - Verbs:
GETreads,POSTcreates,PUT/PATCHupdate,DELETEremoves. RxPhoto prefersPATCHfor updates — send only the fields you want to change rather than the whole object. - Auth: a single
Authorization: Token YOUR_TOKENheader on every request — the token is prefixed withTokenand there is no gatewayapikeyparameter. See Authentication — RxPhoto. - Field naming: JSON properties are
snake_case(e.g.first_name,birth_date,last_visit). This differs from PNE/VISH (PascalCase) and PNP (camelCase).
Pagination
List endpoints are paginated, but the parameters vary by resource — always check the operation's parameter table in the reference. Two styles are in use:
| Style | Parameters | Example resources |
|---|---|---|
| Page-based | page (1-based) and often page_size | patient, image, gallery (addon exposes only page) |
| Offset-based | limit and offset | area, form |
Either way, each list response is an object with a total count,
absolute next/previous page URLs (or null at
the ends), and the rows in results:
{
"count": 1287,
"next": "https://api.rxphoto.com/api/v3/patient/?page=2",
"previous": null,
"results": [ { "id": 12345, "first_name": "Jane", ... }, ... ]
}The simplest way to walk a collection is to follow next until it is
null:
def iter_patients(session, base, page_size=50, **filters):
url = f"{base}/patient/"
params = {"page_size": page_size, **filters}
while url:
res = session.get(url, params=params)
res.raise_for_status()
body = res.json()
yield from body["results"]
url = body["next"] # absolute URL to the next page, or None
params = None # next already encodes the query stringasync function* iterPatients(base, headers, pageSize = 50, filters = {}) {
const qs = new URLSearchParams({ page_size: pageSize, ...filters });
let url = `${base}/patient/?${qs}`;
while (url) {
const res = await fetch(url, { headers });
const body = await res.json();
yield* body.results;
url = body.next; // absolute URL to the next page, or null
}
}RxPhoto list endpoints wrap rows in a
{ count, next, previous, results } envelope rather than returning a
bare array. Always read from .results, and use .next to
advance rather than guessing page counts from count.
Filtering & search
List endpoints expose rich, field-level filters using a
field__lookup convention, plus a general search and an
ordering parameter. Available filters vary by resource — the
reference lists each endpoint's query parameters.
| Parameter | Meaning | Example |
|---|---|---|
search | Free-text search across a resource's searchable fields. | ?search=smith |
ordering | Sort field; prefix with - for descending. | ?ordering=-last_visit |
field__icontains | Case-insensitive substring match. | ?middle_name__icontains=ann |
field__istartswith / __iexact | Prefix / exact (case-insensitive) match. | ?last_name__istartswith=sm |
field__gte / __lte / __gt / __lt | Range comparisons (dates, numbers). | ?birth_date__gte=1990-01-01 |
field__in | Match any value in a comma-separated list. | ?treatments_or__in=1,2,3 |
Shaping the response: fields, omit & expand
Beyond filtering and search, most RxPhoto endpoints accept three parameters that control the shape of each result object. They keep payloads small and save you follow-up requests:
| Parameter | Meaning | Example |
|---|---|---|
fields | Return only the listed fields in each result. | ?fields=id,first_name,last_name |
omit | Return everything except the listed fields. | ?omit=notes,history |
expand | Inline a foreign-key's full object instead of just its ID — e.g. author returns the doctor object rather than a bare id. | ?expand=author |
Pair expand with fields to pull a related object inline
while keeping the response lean — for example
?expand=author&fields=id,author. Each endpoint documents the
foreign keys it can expand in the reference.
To keep a local copy in sync, store the timestamp of your last run and filter on
a date field with __gte (for example
?last_visit__gte=2026-06-01) to pull only records changed since then.
Combine with pagination to page through the deltas.
Resource IDs
RxPhoto returns plain integer IDs for all resources — patients, images, bundles, forms, and so on. They appear directly in path parameters and response bodies:
// A patient response — IDs are integers:
{ "id": 12345, "first_name": "Jane", "last_name": "Smith", ... }
// Use the integer directly in the next call (note the trailing slash):
GET /api/v3/patient/12345/- Store them as integers in your system — no need to treat them as opaque strings.
- They're stable for a given record and safe to use as foreign keys.
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 RxPhoto IDs with encrypted PNE/VISH IDs.
Dates & times
- Date and date-time fields are ISO 8601 strings. Filter parameters that accept
dates (e.g.
birth_date,last_visit) acceptYYYY-MM-DDor a full datetime string, and support the__gte/__lte/__gt/__ltrange lookups. - There are also convenience lookups for date parts, such as
birth_date__month__gteandlast_visit__year__lte. - Nullable date fields may be
nullwhen unset — guard for that in your client. Pass UTC for consistent results across environments.
Errors & status codes
RxPhoto uses standard HTTP status codes. The status line is the primary signal; a
JSON body with a detail message may accompany errors.
| Code | Meaning | What to do |
|---|---|---|
200 OK | Successful read or update. | Parse the body. |
201 Created | Successful create. | Read the new record's id from the response body. |
400 Bad Request | Validation failed — missing or invalid fields. | Check the detail (or field errors) in the body; fix the payload. |
401 Unauthorized | Missing or invalid token, or bad sign-in credentials. | See 401/403 causes. |
403 Forbidden | Token valid but not permitted, or account inactive/blocked. | Confirm the account is active and has access to the resource. |
404 Not Found | No such record, or not visible to this token. | Re-check the ID and that the trailing slash is present. |
500 Server Error | Unexpected server-side failure. | Retry with backoff; if it persists, contact support. |
Always branch on the status code before parsing. A non-2xx response may carry a
{ "detail": "…" } body explaining the problem. Check for both
401 (not signed in / bad token) and 403 (signed in but
not allowed) — RxPhoto distinguishes them.