Get started · RxPhoto
RxPhoto quickstart
Make your first authenticated RxPhoto API call in under ten minutes — no SDK required.
The RxPhoto (RxP) API lets you build on RxPhoto's clinical photography platform —
working with patients, images and before/after image pairs, bundles, galleries,
forms, and consultations. Most endpoints sit under the
/api/v3/ path and exchange JSON. Authentication is a single
token in the Authorization header — no gateway
apikey parameter. If you're integrating with PatientNow Essentials,
see the PNE quickstart → instead.
Before you start
You need one thing to begin:
- A set of RxPhoto credentials (username and password) that you
can exchange for an authorization token. That token is sent as
an
Authorizationheader on every request.
Anyone with your token has the same API access you do. Keep it out of source control, browser code shipped to end users, and logs. Use a dedicated service account rather than a person's credentials where possible.
The examples below use the base URL https://api.rxphoto.com.
Write operations affect real records immediately, so test with records you can
clean up.
1 · Get a token
Exchange your username and password for a token by posting to
/api/v3/authenticate/user/. The response includes a
token field — send it as your Authorization header,
prefixed with Token (Authorization: Token YOUR_TOKEN),
and reuse it on every call.
# Sign in, then copy the "token" from the response:
curl -X POST "https://api.rxphoto.com/api/v3/authenticate/user/" \
-H "Content-Type: application/json" \
-d '{"username": "user@example.com", "password": "YOUR_PASSWORD"}'
# Reuse it on every request (note the "Token " prefix):
# -H "Authorization: Token YOUR_TOKEN"const base = "https://api.rxphoto.com/api/v3";
const auth = await fetch(`${base}/authenticate/user/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: "user@example.com", password: "YOUR_PASSWORD" }),
});
const { token } = await auth.json();
const authHeader = { Authorization: `Token ${token}` };import requests
base = "https://api.rxphoto.com/api/v3"
auth = requests.post(f"{base}/authenticate/user/", json={
"username": "user@example.com",
"password": "YOUR_PASSWORD",
})
token = auth.json()["token"]
# A session with the token as a default header keeps every call clean:
s = requests.Session()
s.headers.update({"Authorization": f"Token {token}"})using System;
using System.Net.Http;
using System.Net.Http.Json;
var http = new HttpClient { BaseAddress = new Uri("https://api.rxphoto.com/api/v3/") };
var auth = await http.PostAsJsonAsync("authenticate/user/", new {
username = "user@example.com",
password = "YOUR_PASSWORD",
});
var body = await auth.Content.ReadFromJsonAsync<Dictionary<string, object>>();
http.DefaultRequestHeaders.Add("Authorization", $"Token {body["token"]}");2 · Confirm connectivity
The cleanest first call is GET /api/v3/doctor/me/ — it returns the
signed-in doctor, requires valid auth, and confirms your token is correct. It's
also cheaper than listing patients, which can be slow without pagination. A
200 OK means you're in. (There's also GET /api/v3/ping/,
which does nothing but extend your token's expiry.)
curl "https://api.rxphoto.com/api/v3/doctor/me/" \
-H "Authorization: Token YOUR_TOKEN"const res = await fetch(`${base}/doctor/me/`, { headers: authHeader });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
console.log(await res.json());res = s.get(f"{base}/doctor/me/")
res.raise_for_status()
print(res.json())var res = await http.GetAsync("doctor/me/");
res.EnsureSuccessStatusCode();
Console.WriteLine(await res.Content.ReadAsStringAsync());A 401 Unauthorized means your token is missing or invalid. A
403 Forbidden means your account isn't permitted for that resource.
3 · Read real data
List patients. Results are paginated with page and
page_size parameters, and each list response wraps the rows in a
{count, next, previous, results} envelope. You can narrow results with
filters like search or field lookups such as
last_name__istartswith:
curl "https://api.rxphoto.com/api/v3/patient/?page=1&page_size=5&last_name__istartswith=sm" \
-H "Authorization: Token YOUR_TOKEN"const params = new URLSearchParams({ page: "1", page_size: "5", last_name__istartswith: "sm" });
const res = await fetch(`${base}/patient/?${params}`, { headers: authHeader });
const { count, results } = await res.json();
console.log(`${count} total; showing ${results.length}`);# s (from step 1) already sends the Authorization header on every call:
res = s.get(f"{base}/patient/", params={
"page": 1, "page_size": 5, "last_name__istartswith": "sm",
})
body = res.json()
print(body["count"], "total;", len(body["results"]), "shown")RxPhoto endpoints end in a trailing slash (/api/v3/patient/,
/api/v3/patient/{id}/). Record IDs are integers — use them as
returned, not as opaque strings like in PNE/VISH.
4 · Create a record
Write operations POST a JSON body. On success the API returns the new
object, including its assigned integer id that you use for subsequent
reads and updates. Check the reference for the
exact required fields of the resource you're creating.
curl -X POST "https://api.rxphoto.com/api/v3/patient/" \
-H "Authorization: Token YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Smith",
"birth_date": "1985-03-15",
"email": "jane.smith@example.com"
}'const res = await fetch(`${base}/patient/`, {
method: "POST",
headers: { ...authHeader, "Content-Type": "application/json" },
body: JSON.stringify({
first_name: "Jane",
last_name: "Smith",
birth_date: "1985-03-15",
email: "jane.smith@example.com",
}),
});
console.log(res.status, await res.json());res = s.post( # s carries the Authorization header from step 1
f"{base}/patient/",
json={
"first_name": "Jane",
"last_name": "Smith",
"birth_date": "1985-03-15",
"email": "jane.smith@example.com",
},
)
print(res.status_code, res.json())The exact fields a resource accepts come from its schema in the reference. The names above are examples — confirm required vs. optional fields there before you build against them.