Pharmacy
For pharmacies: the patient roster with dose-log adherence (an unrecorded dose is not a missed dose, and never a PDC), medication reviews to completion, discharge follow-up episodes with day-3 and day-30 checks, packing verification, deliveries, the medication sync plan (estimates from fills, never an order), monitoring and refills due. Webhooks for refills due and discharge episodes. Pharmacies only; a patient must share their medicines with the pharmacy. The assisted-living, group-home and nursing-home sites a pharmacy runs are in Care sites.
- Who calls it
- Core for Pharmacies
- Before production
- Pharmacies with a BAA on file (or a sandbox).
- Sandbox
- Build against synthetic members first. What each sandbox holds
Markets that use this family
- Pharmacies (core)
Scopes
| Scope | Allows |
|---|---|
pharmacy.adherence.read | Read a patient's dose log and adherence summary: taken, skipped and unrecorded kept apart (an unrecorded dose is never counted as missed) and never a proportion of days covered (pharmacies only; the patient must share medications with you). |
pharmacy.delivery.write | Record a verified pack (the four-item checklist, all confirmed) and a delivery confirmed at the door (pharmacies only). |
pharmacy.episodes.write | Open a discharge follow-up episode and record the day-3 / day-30 contacts, how each medication difference was resolved, the 30-day outcome and closing (pharmacies only). |
pharmacy.patients.read | Read your pharmacy's patients (medicines-sharing status, pack cycle, open discharge follow-up), discharge follow-up episodes, medication reviews, the packing queue and deliveries, the monitoring-due list (a consensus schedule, not an order) and refills due (pharmacies only, BAA on file). |
pharmacy.reviews.write | Start a medication review, add the pharmacist's recommendations and the prescriber's answer, and complete it (pharmacies only). |
Endpoints
Your pharmacy's patients
Every active member: whether they share medications with you and, when they do, the pack cycle, the open discharge follow-up episode with its next due contact, and the care site they live at (one of yours). With pharmacy.adherence.read also the last 7 days' dose counts (taken, skipped and unrecorded kept apart; an unrecorded dose is never missed). A member who has not shared medications is listed with every field withheld.
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/pharmacy/patients",
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 url = new URL(`${BASE}/v1/pharmacy/patients`);
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
A patient's dose log and adherence summary
rx_doses.adherence_summary: confirmed_rate = taken / all due slots (a floor), recorded_rate = taken / (taken + skipped), an estimate over the recorded doses only; unrecorded doses are counted apart and never as missed. Not a proportion of days covered (that needs fill claims). Plus every dose recorded in the window, with who recorded it (patient, caregiver or staff).
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/adherence" \
-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/pharmacy/patients/{member_ref}/adherence",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/adherence`);
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
A patient's medication reviews and whether one is due
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/medication-reviews" \
-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/pharmacy/patients/{member_ref}/medication-reviews",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/medication-reviews`);
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
Start a medication review (or return the open draft)
med_review.start_review: the patient's current medicines and the automatic flags (prompts for the pharmacist, not orders). One draft per patient: an open draft is refreshed and returned.
Parameters
All responses
201Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/medication-reviews" \
-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.post(
f"{BASE}/v1/pharmacy/patients/{member_ref}/medication-reviews",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/medication-reviews`);
const res = await fetch(url, {
method: "POST",
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
One medication review
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/medication-reviews/$REVIEW_REF" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
review_ref = os.environ["REVIEW_REF"]
resp = requests.get(
f"{BASE}/v1/pharmacy/medication-reviews/{review_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 review_ref = process.env.REVIEW_REF;
const url = new URL(`${BASE}/v1/pharmacy/medication-reviews/${encodeURIComponent(review_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());Try it in your sandbox
Add a recommendation to a draft review
med_review.add_recommendation (409 review_completed; 404 finding_not_found; 422 invalid_intervention_kind / description_required / invalid_prescriber_response).
Parameters
Request body
Content type: application/json (required)
discrepancy_resolved | prescriber_contacted | dose_change_recommended | therapy_change_recommended | education | adherence_packaging | refill_sync | prior_authorization | cost_saving | other
A finding of this review the recommendation addresses.
pending | accepted | declined | not_applicable
Errors specific to this call
409review_completed422invalid_intervention_kindAll 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/pharmacy/medication-reviews/$REVIEW_REF/recommendations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"kind": "string",
"description": "string",
"finding_key": "string",
"prescriber_response": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
review_ref = os.environ["REVIEW_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/medication-reviews/{review_ref}/recommendations",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"kind": "string",
"description": "string",
"finding_key": "string",
"prescriber_response": "string",
},
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 review_ref = process.env.REVIEW_REF;
const url = new URL(`${BASE}/v1/pharmacy/medication-reviews/${encodeURIComponent(review_ref)}/recommendations`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"kind": "string",
"description": "string",
"finding_key": "string",
"prescriber_response": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Complete a medication review
Parameters
Request body
Content type: application/json
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/pharmacy/medication-reviews/$REVIEW_REF/complete" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"summary": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
review_ref = os.environ["REVIEW_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/medication-reviews/{review_ref}/complete",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"summary": "string",
},
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 review_ref = process.env.REVIEW_REF;
const url = new URL(`${BASE}/v1/pharmacy/medication-reviews/${encodeURIComponent(review_ref)}/complete`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"summary": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Your discharge follow-up episodes
The day-3 and day-30 contacts (due / overdue / done), the medication comparison counts and the 30-day outcome. An outcome that is null is "not known", never "no". Patients no longer linked or no longer sharing medications drop out.
Parameters
open | closed
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/discharge-episodes" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/pharmacy/discharge-episodes",
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 url = new URL(`${BASE}/v1/pharmacy/discharge-episodes`);
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
Open a discharge follow-up episode
pharmacy_care.create_episode: the medication comparison is computed by med_reconcile.compare; pre_admission_meds defaults to the patient's list on file (422 invalid_discharged_from, date_out_of_range, medication_list_invalid).
Request body
Content type: application/json (required)
YYYY-MM-DD, not in the future.
snf | hospital | rehab | other
Medication list on discharge: strings or {name, dosage, frequency} objects.
Default: the patient's medication list on file in Norvya.
Errors specific to this call
422invalid_discharged_fromAll responses
201Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/pharmacy/discharge-episodes" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member_ref": "mr_3f9c1a0b7d2e4c6a8b1d0e2f",
"discharge_date": "2026-10-12",
"discharged_from": "string",
"facility_label": "string",
"discharge_meds": [
null
],
"pre_admission_meds": [
null
]
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.post(
BASE + "/v1/pharmacy/discharge-episodes",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"member_ref": "mr_3f9c1a0b7d2e4c6a8b1d0e2f",
"discharge_date": "2026-10-12",
"discharged_from": "string",
"facility_label": "string",
"discharge_meds": [
None,
],
"pre_admission_meds": [
None,
],
},
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/pharmacy/discharge-episodes`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"member_ref": "mr_3f9c1a0b7d2e4c6a8b1d0e2f",
"discharge_date": "2026-10-12",
"discharged_from": "string",
"facility_label": "string",
"discharge_meds": [
null
],
"pre_admission_meds": [
null
]
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
One discharge follow-up episode
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/discharge-episodes/$EPISODE_REF" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
resp = requests.get(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_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 episode_ref = process.env.EPISODE_REF;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_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());Try it in your sandbox
Replace the episode's medication lists (the comparison is recomputed)
Parameters
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 PUT "https://norvya.fly.dev/v1/pharmacy/discharge-episodes/$EPISODE_REF/medications" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"discharge_meds": [
null
],
"pre_admission_meds": [
null
]
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
resp = requests.put(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_ref}/medications",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"discharge_meds": [
None,
],
"pre_admission_meds": [
None,
],
},
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 episode_ref = process.env.EPISODE_REF;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_ref)}/medications`);
const res = await fetch(url, {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"discharge_meds": [
null
],
"pre_admission_meds": [
null
]
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Record how one medication difference was resolved
Parameters
Request body
Content type: application/json (required)
One of the episode's reconciliation.review_keys.
confirmed_intentional | prescriber_contacted | corrected | not_applicable
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/pharmacy/discharge-episodes/$EPISODE_REF/resolutions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"item_key": "string",
"status": "string",
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_ref}/resolutions",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"item_key": "string",
"status": "string",
"note": "string",
},
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 episode_ref = process.env.EPISODE_REF;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_ref)}/resolutions`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"item_key": "string",
"status": "string",
"note": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Record a day-3 or day-30 contact attempt
reached or declined completes the check with the items you confirmed; any other result is recorded as an attempt (422 invalid_check / invalid_contact_result).
Parameters
Request body
Content type: application/json (required)
reached | no_answer | left_message | declined | wrong_number
The check's item_keys you confirmed (reached / declined complete the check).
Errors specific to this call
422invalid_checkAll 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/pharmacy/discharge-episodes/$EPISODE_REF/checks/$WHICH" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"contact_result": "string",
"items": {},
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
which = os.environ["WHICH"]
resp = requests.post(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_ref}/checks/{which}",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"contact_result": "string",
"items": {},
"note": "string",
},
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 episode_ref = process.env.EPISODE_REF;
const which = process.env.WHICH;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_ref)}/checks/${encodeURIComponent(which)}`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"contact_result": "string",
"items": {},
"note": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Record the 30-day outcome
A readmission or ED visit needs its date inside the 30-day window (422 event_date_required / outside_30_day_window / invalid_outcome_source); a recorded event is mirrored once into the care events every consumer reads.
Parameters
Request body
Content type: application/json (required)
null = not known (never read as no).
patient_call | caregiver_call | prescriber | facility | hospital_notification | other
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/pharmacy/discharge-episodes/$EPISODE_REF/outcome" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"readmitted": false,
"readmit_date": "string",
"ed_visit": false,
"ed_date": "string",
"source": "string",
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_ref}/outcome",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"readmitted": False,
"readmit_date": "string",
"ed_visit": False,
"ed_date": "string",
"source": "string",
"note": "string",
},
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 episode_ref = process.env.EPISODE_REF;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_ref)}/outcome`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"readmitted": false,
"readmit_date": "string",
"ed_visit": false,
"ed_date": "string",
"source": "string",
"note": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Close (or reopen) an episode
Parameters
Request body
Content type: application/json
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/pharmacy/discharge-episodes/$EPISODE_REF/close" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reopen": false
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/discharge-episodes/{episode_ref}/close",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"reopen": False,
},
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 episode_ref = process.env.EPISODE_REF;
const url = new URL(`${BASE}/v1/pharmacy/discharge-episodes/${encodeURIComponent(episode_ref)}/close`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"reopen": false
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
The packing queue
pharmacy_ops.packing_queue: active pack cycles due within `days` (overdue first), each with the change count against the last verified pack (the first pack has no baseline and says so).
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/packing" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/pharmacy/packing",
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 url = new URL(`${BASE}/v1/pharmacy/packing`);
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
A patient's pack change report
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/packing" \
-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/pharmacy/patients/{member_ref}/packing",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/packing`);
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
Record a verified pack
pharmacy_ops.verify_pack: every checklist item must be true (422 checklist_incomplete); the current list becomes the next baseline; mark_filled moves the pack cycle (404 cycle_not_found without one).
Parameters
Request body
Content type: application/json (required)
All four must be true: changes_reviewed, packed_to_current_list, labels_checked, second_check_done.
YYYY-MM-DD (default today) when mark_filled.
Errors specific to this call
404cycle_not_foundAll responses
201Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/packing/verify" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"checklist": {},
"note": "string",
"mark_filled": false,
"fill_date": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/patients/{member_ref}/packing/verify",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"checklist": {},
"note": "string",
"mark_filled": False,
"fill_date": "string",
},
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/pharmacy/patients/${encodeURIComponent(member_ref)}/packing/verify`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"checklist": {},
"note": "string",
"mark_filled": false,
"fill_date": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A patient's confirmed deliveries
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/deliveries" \
-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/pharmacy/patients/{member_ref}/deliveries",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/deliveries`);
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
Confirm a delivery at the door
pharmacy_ops.record_delivery without a photo (422 recipient_required; 404 cycle_not_found when mark_filled and no cycle).
Parameters
Request body
Content type: application/json (required)
Norvya's generic notice to family members the patient chose to share medications with.
Errors specific to this call
422recipient_required404cycle_not_foundAll responses
201Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X POST "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/deliveries" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"recipient_name": "string",
"note": "string",
"mark_filled": false,
"notify_family": false
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/pharmacy/patients/{member_ref}/deliveries",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"recipient_name": "string",
"note": "string",
"mark_filled": False,
"notify_family": False,
},
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/pharmacy/patients/${encodeURIComponent(member_ref)}/deliveries`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"recipient_name": "string",
"note": "string",
"mark_filled": false,
"notify_family": false
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A refill-sync plan from your own fill records
pharmacy_ops.sync_plan: when each medicine runs out and the short fill that reaches one sync date. Quantities assume steady use; estimates for the pharmacist, never an order.
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/patients/$MEMBER_REF/sync-plan" \
-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/pharmacy/patients/{member_ref}/sync-plan",
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/pharmacy/patients/${encodeURIComponent(member_ref)}/sync-plan`);
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
Monitoring due across your patients
care_sites.monitoring_due for every patient who shares medications: a consensus monitoring schedule (antipsychotics, lithium, valproate, carbamazepine, clozapine ANC, oral terbinafine) overridden per check by an active prescriber order you recorded. It lists what has not been RECORDED in Norvya, never that something was not done; the prescriber's orders win.
Parameters
Comma list of overdue | never_recorded | due_soon | ok | not_needed.
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/monitoring-due" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/pharmacy/monitoring-due",
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 url = new URL(`${BASE}/v1/pharmacy/monitoring-due`);
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
Pack refills due soon or overdue
Your active pack cycles whose next fill is within `days` (overdue included), from rx_doses.pack_cycle_dict: next fill = last fill + cycle days; an overdue cycle is reported overdue, never rolled forward.
Parameters
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/pharmacy/refills-due" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/pharmacy/refills-due",
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 url = new URL(`${BASE}/v1/pharmacy/refills-due`);
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
Webhook events
Payloads carry no health data, only a reference to fetch with your token. Each event needs its scope as well as webhooks.manage. Signing and retries
| Event | Scope | When |
|---|---|---|
pharmacy.discharge_episode_opened | pharmacy.patients.read | A discharge follow-up episode opened. |
pharmacy.refill_due | pharmacy.patients.read | A pack cycle of the pharmacy became due soon or overdue. |
Generated from the Partner API router and developers_catalog.py. The router docstring is the source of each description.