Specialty care
For specialty practices and the EMR vendors that serve them: a patient's specialty hub results through one {hub} path parameter (the hubs are listed on the call), each section under the patient's sharing switches with the domains they have not shared listed in withheld; the four direct specialty checks (eGFR as a number with its trend and never a KDIGO stage, the GLP-1 MTC/MEN2 check, the colonoscopy interval, the heart-failure symptom check); and stateless spirometry, lung-cancer screening and GI alarm checks that take your values and store nothing. Treating practices only. Questionnaires stay in Clinical intelligence (one instrument registry).
- Who calls it
- Core for EMR vendors, Specialty care; useful for Concierge doctors, Independent practices, Hospitals and health systems
- Before production
- No gate of its own; your market's “Before production” applies.
- Sandbox
- Build against synthetic members first. What each sandbox holds
- Standards
- GOLD spirometry criteria; race-free CKD-EPI 2021 eGFR
Markets that use this family
- Concierge doctors (useful)
- Independent practices (useful)
- EMR vendors (core)
- Hospitals and health systems (useful)
- Specialty care (core)
Scopes
| Scope | Allows |
|---|---|
clinical.specialty.read | Read a patient's specialty hub results (cardio, nephro, endo, neuro, pulmo, rheum, GI and questionnaires) under their sharing switches, and run the stateless spirometry, lung-cancer screening and GI alarm checks (treating practices only). |
Endpoints
A patient's specialty hub results
The results the patient's condition hubs produced (home blood pressure, the heart-failure symptom check, eGFR as a number with its trend, the GLP-1 MTC/MEN2 check, neuropathy, asthma control, PEST, RAPID3-style, the colonoscopy interval, reminder plans, questionnaire scores), each section under the patient's sharing switches for you with the domains they have NOT shared listed in `withheld`. Never a KDIGO stage, never a risk score from the left-out list, never item-level answers; 42 CFR Part 2 questionnaires never appear. 404 unknown_specialty.
Parameters
all | cardio | nephro | endo | neuro | pulmo | rheum | gi | other
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
Errors specific to this call
404unknown_specialtyAll 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/specialty/$HUB" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
member_ref = os.environ["MEMBER_REF"]
hub = os.environ["HUB"]
resp = requests.get(
f"{BASE}/v1/patients/{member_ref}/specialty/{hub}",
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 hub = process.env.HUB;
const url = new URL(`${BASE}/v1/patients/${encodeURIComponent(member_ref)}/specialty/${encodeURIComponent(hub)}`);
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
eGFR, the GLP-1 thyroid check, the colonoscopy interval and the heart-failure check
The four direct reads from the specialty hubs, each null when there is no result (or the data behind it is not shared: `withheld` lists the domains). egfr: race-free CKD-EPI 2021 as a number with its trend, never a stage (ckd_stage is always null with the reason). glp1_thyroid_check: the medullary thyroid cancer / MEN2 contraindication check on the problem list. colonoscopy_interval: the stored surveillance recommendation. hf_symptom: the stored heart-failure symptom check.
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/specialty-checks" \
-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}/specialty-checks",
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)}/specialty-checks`);
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
Interpret spirometry values (GOLD criteria; stateless)
FEV1/FVC (+ FEV1 and FVC % predicted from your own report) to obstruction and GOLD grade, the hub's own rule. No patient, nothing stored. A COPD diagnosis needs a post-bronchodilator test.
Request body
Content type: application/json (required)
Ratio as 0.65 or percent 65.
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/clinical/checks/spirometry" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fev1_fvc": 0.0,
"fev1_pct_pred": 0.0,
"fvc_pct_pred": 0.0
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.post(
BASE + "/v1/clinical/checks/spirometry",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"fev1_fvc": 0.0,
"fev1_pct_pred": 0.0,
"fvc_pct_pred": 0.0,
},
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 url = new URL(`${BASE}/v1/clinical/checks/spirometry`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"fev1_fvc": 0.0,
"fev1_pct_pred": 0.0,
"fvc_pct_pred": 0.0
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"check": "string",
"educational": false,
"stored": false
}The response is the shape from the schema, not live data.
Try it in your sandbox
Lung-cancer screening eligibility (USPSTF 2021; stateless)
Adults 50-80 with at least 20 pack-years who smoke now or quit within 15 years. Smoking history is not stored by Norvya, so this is not a care gap: send the values from your record. Nothing stored.
Request body
Content type: application/json (required)
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/clinical/checks/lung-cancer-screening" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"age": 0,
"pack_years": 0.0,
"current_smoker": false,
"years_since_quit": 0.0
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.post(
BASE + "/v1/clinical/checks/lung-cancer-screening",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"age": 0,
"pack_years": 0.0,
"current_smoker": False,
"years_since_quit": 0.0,
},
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 url = new URL(`${BASE}/v1/clinical/checks/lung-cancer-screening`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"age": 0,
"pack_years": 0.0,
"current_smoker": false,
"years_since_quit": 0.0
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"check": "string",
"educational": false,
"stored": false
}The response is the shape from the schema, not live data.
Try it in your sandbox
GI alarm-feature triage lane (stateless)
The red-flag lane (emergency | urgent | soon | self_manage) for the alarm features present; it only ever escalates. Unknown keys are refused (422 unknown_alarm_item). Not a diagnosis and not an emergency service.
Request body
Content type: application/json (required)
Alarm item keys (gi_alarm.ALARM_ITEMS) set true when present.
Errors specific to this call
422unknown_alarm_itemAll responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/clinical/checks/gi-alarm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"answers": {
"blood_in_stool": true
}
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.post(
BASE + "/v1/clinical/checks/gi-alarm",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"answers": {
"blood_in_stool": True,
},
},
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 url = new URL(`${BASE}/v1/clinical/checks/gi-alarm`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"answers": {
"blood_in_stool": true
}
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"check": "string",
"educational": false,
"stored": false
}The response is the shape from the schema, not live data.
Try it in your sandbox
Generated from the Partner API router and developers_catalog.py. The router docstring is the source of each description.