Records & documents
One patient's record as a FHIR R4 Bundle, built by the same builders and under the same consent scope as the population export (the patient's sharing choices, your own records, 42 CFR Part 2 records only under a covering consent), size-capped with the bulk export for large records. The documents Norvya already produces about a patient, listed and downloaded as PDF (or HTML where that is the only form) in the patient's language where the document supports it: survivorship care plans, Good Faith Estimates, post-discharge summaries, the wellness visit's written prevention plan, the medical-travel repatriation summary, weekly nursing reports and nursing invoices, and the pharmacist's completed medication review. Each kind keeps its own gate and scope; kinds a patient's sharing withholds are named, and kinds Norvya does not serve are listed with the reason. Every download is audited as a disclosure before it is returned.
- Who calls it
- Every partner: common to all markets.
- Before production
- Treating practices (medical-travel desks included) and pharmacies; the record also needs a BAA on file (or a sandbox).
- Sandbox
- Build against synthetic members first. What each sandbox holds
- Standards
- FHIR R4 Bundle; 42 CFR Part 2 consent rules
Markets that use this family
- Specialty care (useful)
Scopes
| Scope | Allows |
|---|---|
clinical.record.read | Read one patient's record as a FHIR R4 Bundle (the same builders and the same consent scope as the population export: the patient's sharing choices, your practice's own records, 42 CFR Part 2 records only under a covering consent); size-capped, with the population export for large records (treating practices with a BAA on file, or a sandbox). |
documents.read | List and download the documents Norvya already produces about a patient (care plans, survivorship plans, reviews, summaries, estimates) as PDF, in the patient's language where the document supports it; each document kind keeps its own consent gate (treating practices, including medical-travel desks, and pharmacies). |
Endpoints
One patient's record as a FHIR R4 Bundle
A `collection` Bundle built by the same builders and the same consent scope as the population export (fhir_bulk.patient_export): the patient's sharing choices with your practice, your practice's own records under practice-of-record, member home data per their switches, 42 CFR Part 2 program records only under a covering consent (labelled). What consent left out is named in an OperationOutcome entry. A BAA on file is required (409 record_baa_required; a sandbox needs none). Capped at PARTNER_RECORD_MAX_RESOURCES resources / PARTNER_RECORD_MAX_BYTES bytes: beyond that, 413 record_too_large_use_population_export (narrow with types / since, or run POST /v1/population/exports). Audited as a PHI export before it is returned (503 when the audit log is down).
Parameters
Comma-separated FHIR resource types (default all the population export supports).
YYYY-MM-DD: only resources on or after.
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
Errors specific to this call
409record_baa_required413record_too_large_use_population_export503whenAll responses
200A FHIR R4 Bundle.401Unauthorized403Forbidden404Not Found409Conflict413Too large: use POST /v1/population/exports.422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/patients/$MEMBER_REF/record" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.get(
f"{BASE}/v1/patients/{member_ref}/record",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())// Node.js 18+ (ES module). Keep production credentials on your server.
const BASE = "https://norvya.fly.dev";
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/patients/${encodeURIComponent(member_ref)}/record`);
const res = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
The documents Norvya holds about a patient for your practice
Each kind maps to a document Norvya already produces for your staff (survivorship care plan, Good Faith Estimate when you also hold billing.read, post-discharge summary for hospitals, the wellness visit's written prevention plan; for medical-travel desks the bilingual repatriation summary, weekly nursing reports and, with travel.billing.read, nursing invoices; for pharmacies the completed medication review letter), under that kind's own gate. Kinds the patient's sharing withholds are named in `withheld`; kinds Norvya does not serve here are listed with the reason in `not_available`.
Parameters
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/patients/$MEMBER_REF/documents" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.get(
f"{BASE}/v1/patients/{member_ref}/documents",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())// Node.js 18+ (ES module). Keep production credentials on your server.
const BASE = "https://norvya.fly.dev";
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/patients/${encodeURIComponent(member_ref)}/documents`);
const res = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"member_ref": "string",
"items": [
{
"document_ref": "doc_scp_4c1d2e3f4a5b6c7d8e9f0a1b",
"kind": "survivorship_plan",
"title": "string",
"loinc": "string",
"media_type": "application/pdf",
"created_at": "string",
"issued_at": "string",
"version": 0,
"languages": [
"string"
],
"default_language": "string",
"see_also": "string",
"member_ref": "string"
}
],
"withheld": [
{
"kind": "string",
"reason": "string"
}
],
"not_available": [
{
"kind": "string",
"reason": "string"
}
],
"part2_program": false
}The response is the shape from the schema, not live data.
Try it in your sandbox
One document's metadata
404 document_not_found for another organisation's document, a member no longer linked, or a kind your token or the patient's sharing does not allow.
Parameters
Errors specific to this call
404document_not_foundAll responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/documents/$DOCUMENT_REF" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
document_ref = os.environ["DOCUMENT_REF"]
resp = requests.get(
f"{BASE}/v1/documents/{document_ref}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())// Node.js 18+ (ES module). Keep production credentials on your server.
const BASE = "https://norvya.fly.dev";
const document_ref = process.env.DOCUMENT_REF;
const url = new URL(`${BASE}/v1/documents/${encodeURIComponent(document_ref)}`);
const res = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"document_ref": "doc_scp_4c1d2e3f4a5b6c7d8e9f0a1b",
"kind": "survivorship_plan",
"title": "string",
"loinc": "string",
"media_type": "application/pdf",
"created_at": "string",
"issued_at": "string",
"version": 0,
"languages": [
"string"
],
"default_language": "string",
"see_also": "string",
"member_ref": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
Download a document, in the patient's language where the document supports it
Rendered by the same builder as Norvya's own copy. A disclosure: audited as a PHI export before it is returned and refused (503) when the audit log is down. 422 document_language_unsupported for a language the document cannot be rendered in. Content-Language names the language used (a builder falls back to English when the script's font is missing).
Parameters
An app language code from the document's `languages`; default its default_language.
Errors specific to this call
422document_language_unsupportedAll responses
200The document.401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/documents/$DOCUMENT_REF/content" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
document_ref = os.environ["DOCUMENT_REF"]
resp = requests.get(
f"{BASE}/v1/documents/{document_ref}/content",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())// Node.js 18+ (ES module). Keep production credentials on your server.
const BASE = "https://norvya.fly.dev";
const document_ref = process.env.DOCUMENT_REF;
const url = new URL(`${BASE}/v1/documents/${encodeURIComponent(document_ref)}/content`);
const res = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Generated from the Partner API router and developers_catalog.py. The router docstring is the source of each description.