Patient-authorized EHR integration
Read and paginate
Import a category by following its cursor until hasMore is false, then keep it current with the change feed.
Page through a category
curl "https://api.finchnode.com/api/v1/users/$SUBJECT/records/labs?limit=100" \
-H "Authorization: Bearer $FINCHNODE_API_KEY"
Each page has data, hasMore, nextCursor, and meta. Send nextCursor back as cursor until hasMore is false. Keep the first page's meta.changeCursor: you'll need it for the change feed.
async function importCategory(subject, category) {
const records = [];
let cursor = null;
let first;
for (;;) {
const url = new URL(`https://api.finchnode.com/api/v1/users/${subject}/records/${category}`);
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.FINCHNODE_API_KEY}` } });
if (!res.ok) throw new Error(`FinchNode returned ${res.status}`);
const page = await res.json();
first ??= page;
records.push(...page.data);
if (!page.hasMore) break;
cursor = page.nextCursor;
}
return { records, changeCursor: first.meta.changeCursor, meta: first.meta };
}import os
import requests
def import_category(subject, category):
records, cursor, first = [], None, None
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
res = requests.get(
f"https://api.finchnode.com/api/v1/users/{subject}/records/{category}",
headers={"Authorization": f"Bearer {os.environ['FINCHNODE_API_KEY']}"},
params=params,
)
if not res.ok:
raise RuntimeError(f"FinchNode returned {res.status_code}")
page = res.json()
first = first or page
records.extend(page["data"])
if not page["hasMore"]:
return {"records": records, "change_cursor": first["meta"]["changeCursor"], "meta": first["meta"]}
cursor = page["nextCursor"]The Python example raises its own error instead of raise_for_status(), because that message includes the URL, and the URL includes the subject.
Check the import is complete
Before you mark a category imported, read meta:
syncStatusiscomplete, notpartialornot_started.- The category is in
availableCategoriesand not inmissingCategories.
If either fails, store what you got, mark it partial, and read again later. See Freshness, partial and stale records.
Limits
limitis 1 to 100. It defaults to 25.- Use a cursor only with the endpoint, subject, and category that returned it. FinchNode doesn't always catch a mismatch, and a reused cursor can skip records.
- Don't build or edit cursors. They're opaque.
Delegated credentials
A delegated agent credential gets meta.changeCursor: null on snapshots. Use meta.changeCursors[category], or the changeCursor from a category page.
List your patients
GET /users returns a page of subjects who currently share with your app, with the same limit and cursor. Use it for admin views and reconciliation, not to find the patient behind a session you just completed. Use cursor; offset remains only for older integrations.