Care sites
For the organisations that run assisted-living, group-home and nursing-home sites: pharmacies AND care-facility operators, each reaching only the sites it owns (a pharmacy named as a facility site's dispenser does not reach that site here). The census, the MAR (scheduled and PRN administrations with follow-up), rounds, medication incidents, change-of-condition reports, the resident care plan and emergency preparedness. A nursing home is the same site with site_type nursing_home, the operator's recorded licence kind and bed count, and each resident's short or long stay; Norvya does no MDS assessment, PDPM coding or CMS submission. The MAR and medication incidents need the resident's medicines shared with the organisation (at a pharmacy's site, everything does). Webhooks for changes of condition, incidents and MAR exceptions go to the site's owner. Admitting a resident (an existing patient, or one without a Norvya login by your own resident ID) and issuing, listing and revoking family read-only access, each attested by a named staff member under the app's consent rules.
- Who calls it
- Core for Pharmacies, Nursing homes & assisted living
- Before production
- Pharmacies and care-facility operators with their own BAA on file (or a sandbox); every admission and family invitation names the staff member who attests consent; discharging a resident and reviewing incidents stay in Norvya.
- Sandbox
- Build against synthetic members first. What each sandbox holds
Markets that use this family
- Pharmacies (core)
- Nursing homes & assisted living (core)
Scopes
| Scope | Allows |
|---|---|
care_sites.events.write | Record a round check, report a medication incident, and report an incident or a change in a resident's condition (Norvya alerts the site's nurses with its own generic wording) (pharmacies and care-facility operators). |
care_sites.family.write | Issue a family member read-only access to a resident (a one-time code by email; a named staff member attests the resident's or guardian's consent), list it and revoke it at once (pharmacies and care-facility operators, BAA on file). |
care_sites.mar.write | Record a scheduled dose as given, held or refused, and an as-needed dose with its reason and follow-up, on a resident's medication administration record; only doses on the resident's schedule (pharmacies and care-facility operators). |
care_sites.read | Read the assisted living, group home and nursing home sites your organisation runs: the census, each resident's medication administration record, rounds, medication incidents, incident and change-of-condition reports, care plans and emergency-preparedness attestations (pharmacies and care-facility operators, their own sites only, BAA on file). |
care_sites.residents.write | Admit a resident to one of the assisted living, group home or nursing home sites your organisation runs: an existing patient by member_ref, or a resident without a Norvya login by your own resident ID; a named staff member attests the consent basis (the resident, a guardian or the facility's admission agreement) (pharmacies and care-facility operators, BAA on file). |
Endpoints
Your assisted living, group home and nursing home sites
Every active site your organisation (a pharmacy or a care-facility operator) owns; never a site you only dispense to. site_type is assisted_living, group_home or nursing_home (site_types lists them). A nursing home also carries licensure_kind (snf | nf | snf_nf: skilled nursing facility, nursing facility, or both) and licensed_beds as the operator recorded them (null when not recorded, and always null at other site types); Norvya verifies neither.
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/care-sites" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/care-sites",
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/care-sites`);
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 site's census
care_site_living.site_census: residents per wing with today's due-but-unrecorded doses (never "missed"), as-needed follow-ups waiting, events in 24 hours, falls in 30 days, no vitals in the site's N days (a Norvya convention the site sets), open condition reports, rounds not recorded. At a nursing home each resident's stay_type (short_stay | long_stay, or null when not recorded) is included.
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/care-sites/$SITE_REF/census" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/census",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/census`);
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 resident's medication administration record for today
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/care-sites/$SITE_REF/residents/$MEMBER_REF/mar" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/mar",
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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/mar`);
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 scheduled dose as given, held or refused
care_sites.record_staff_dose, the MAR function the site's staff use: the slot must be on the resident's schedule today (422 slot_not_scheduled / invalid_time / invalid_outcome; an as-needed medicine goes through /mar/prn). Recording the same slot again replaces it. held and refused are kept apart from given, with the reason, and raise care_site.mar_exception.
Parameters
Request body
Content type: application/json (required)
HH:MM, a dose time on today's schedule (the resident's local day).
given | held | refused
The reason, for held or refused.
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/care-sites/$SITE_REF/residents/$MEMBER_REF/mar/administrations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"schedule_ref": "rxs_8a1f0c3e5b7d9a2c4e6f8b0d",
"slot_time": "08:00",
"outcome": "string",
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/mar/administrations",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"schedule_ref": "rxs_8a1f0c3e5b7d9a2c4e6f8b0d",
"slot_time": "08:00",
"outcome": "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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/mar/administrations`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"schedule_ref": "rxs_8a1f0c3e5b7d9a2c4e6f8b0d",
"slot_time": "08:00",
"outcome": "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 an as-needed dose with its reason
care_sites.record_prn: only an as-needed medicine on the resident's schedule (422 not_as_needed / invalid_details); a follow-up is due in 60 minutes.
Parameters
Request body
Content type: application/json (required)
Errors specific to this call
422not_as_neededAll 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/care-sites/$SITE_REF/residents/$MEMBER_REF/mar/prn" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"schedule_ref": "string",
"reason": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/mar/prn",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"schedule_ref": "string",
"reason": "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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/mar/prn`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"schedule_ref": "string",
"reason": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Record whether an as-needed dose worked
Parameters
Request body
Content type: application/json (required)
effective | partial | not_effective
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/care-sites/$SITE_REF/residents/$MEMBER_REF/mar/prn/$EVENT_REF/follow-up" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"effect": "string",
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
event_ref = os.environ["EVENT_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/mar/prn/{event_ref}/follow-up",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"effect": "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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const event_ref = process.env.EVENT_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/mar/prn/${encodeURIComponent(event_ref)}/follow-up`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"effect": "string",
"note": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A site's rounds board
care_site_living.rounds_board: each facility-configured plan's slots (recorded / due / not_recorded / upcoming) and the shift lead's escalation list. A slot with no check is NOT RECORDED, never "missed".
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/care-sites/$SITE_REF/rounds" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/rounds",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/rounds`);
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 round check
care_site_living.record_check (409 already_recorded / no_round_due; 422 invalid_round_outcome / invalid_slot / note_required for concern).
Parameters
Request body
Content type: application/json (required)
seen_ok | asleep | assisted | not_in_room | declined | concern (concern needs a note)
ISO time of the slot (default: the latest due slot).
Errors specific to this call
409already_recorded422invalid_round_outcomeAll 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/care-sites/$SITE_REF/round-plans/$PLAN_REF/checks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"outcome": "string",
"slot_at": "string",
"note": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
plan_ref = os.environ["PLAN_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/round-plans/{plan_ref}/checks",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"outcome": "string",
"slot_at": "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 site_ref = process.env.SITE_REF;
const plan_ref = process.env.PLAN_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/round-plans/${encodeURIComponent(plan_ref)}/checks`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"outcome": "string",
"slot_at": "string",
"note": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A site's medication incidents
Parameters
open | reviewed | all
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/care-sites/$SITE_REF/medication-incidents" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/medication-incidents",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/medication-incidents`);
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
Report a medication incident
care_site_safety.report_incident: the site owner's reviewers (the pharmacy, or at a facility site the facility and its linked pharmacy) get Norvya's generic alert and review it in the app (422 invalid_incident_type / invalid_severity / description_required / invalid_date).
Parameters
Request body
Content type: application/json (required)
missed_dose | wrong_dose | wrong_medication | wrong_time | wrong_resident | documentation | count_discrepancy | other
no_harm | monitoring_needed | harm
ISO time within the last 30 days (default now).
Errors specific to this call
422invalid_incident_typeAll 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/care-sites/$SITE_REF/residents/$MEMBER_REF/medication-incidents" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"incident_type": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"occurred_at": "string",
"schedule_ref": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/medication-incidents",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"incident_type": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"occurred_at": "string",
"schedule_ref": "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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/medication-incidents`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"incident_type": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"occurred_at": "string",
"schedule_ref": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A site's incident and change-of-condition reports
Parameters
active | open | acknowledged | closed | all
incident | change_of_condition
All responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s "https://norvya.fly.dev/v1/care-sites/$SITE_REF/condition-reports" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/condition-reports",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/condition-reports`);
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
Report an incident or a change in a resident's condition
care_site_living.report_condition, the engine's escalation path unchanged: Norvya sends its generic alert to the site's nurses (or, with none on staff, its managers and the pharmacy's staff) and the report waits for a nurse, manager or the pharmacy to acknowledge it in the app. Not INTERACT and nobody's SBAR form (422 invalid_report_kind / invalid_report_category / invalid_severity / invalid_report_request / description_required / invalid_date).
Parameters
Request body
Content type: application/json (required)
incident | change_of_condition
incident: fall_injury | skin | behavior | elopement | resident_to_resident | injury_unknown_origin | other; change_of_condition: mental_status | mobility | eating_drinking | breathing | skin | pain | toileting | mood_behavior | sleep | vital_signs | other
no_harm | monitoring_needed | harm
review_now | review_today | information_only (change of condition defaults to review_today)
Errors specific to this call
422invalid_report_kindAll 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/care-sites/$SITE_REF/residents/$MEMBER_REF/condition-reports" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"kind": "string",
"category": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"request": "string",
"noticed_since": "string",
"occurred_at": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/condition-reports",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"kind": "string",
"category": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"request": "string",
"noticed_since": "string",
"occurred_at": "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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/condition-reports`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"kind": "string",
"category": "string",
"severity": "string",
"description": "string",
"action_taken": "string",
"request": "string",
"noticed_since": "string",
"occurred_at": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
A resident's functional needs and service plan
care_site_living.plan_view: a Norvya list of everyday-support categories with the support level staff entered (NOT a validated instrument: validated is false), goals and review dates.
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/care-sites/$SITE_REF/residents/$MEMBER_REF/care-plan" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/care-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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/care-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
A site's emergency-preparedness attestations
preparedness.overview: what the SITE attested for each element, its hazards and the exercises it recorded. Never a statement that the site is covered by or compliant with any rule (applicability says why). The identified emergency roster is not exposed here.
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/care-sites/$SITE_REF/emergency-preparedness" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/emergency-preparedness",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/emergency-preparedness`);
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 staff who may attest an admission or a family invitation at a site
The active staff the app lets admit residents and issue family access at this site (care_sites.require_manage: at a pharmacy's site its admin, provider or pharmacist; at a facility's site its admin or provider and the site's managers), as staff_ref values with role and display name to map your own user list to. Staff names are not patient data. Needs care_sites.residents.write or care_sites.family.write.
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/care-sites/$SITE_REF/attesting-staff" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/attesting-staff",
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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/attesting-staff`);
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
Admit a resident (an existing patient, or one without a Norvya login)
care_sites.add_resident, the app's admission engine. The named staff member (attested_by_staff_ref, 422 attesting_staff_not_found) attests the consent basis; consent_attested must be true (422 consent_attestation_required; invalid_consent_basis). With member_ref the patient must be your member, and at a pharmacy's site share medicines with it (403 medications_not_shared). Without it, full_name (422 name_required) and your resident_id (422 resident_id_required) create a resident with no Norvya login, linked to your organisation with medicines shared. 409 already_resident (at this site) / already_resident_id (another person holds that ID with you; that answer carries the existing resident's member_ref, so a retried admission reconciles - only ever for a member of YOUR organisation). The census lists each resident's resident_id. Audited as a consent acceptance naming the attesting staff member.
Parameters
Request body
Content type: application/json (required)
An existing patient of your organisation (at a pharmacy's site they must share medicines with you). Omit to admit a resident without a login.
A resident without a login: their name.
Your own ID for the resident (required without member_ref). One person per ID.
YYYY-MM-DD (a resident without a login).
Nursing home sites only: short_stay (post-acute) | long_stay. 422 not_a_nursing_home at any other site type; 422 invalid_stay_type.
self | guardian | facility_policy (the facility's admission agreement)
Must be true: the named staff member attests that consent on this basis is on file.
The staff member who attests (GET /v1/care-sites/{site_ref}/attesting-staff).
Errors specific to this call
422attesting_staff_not_found403medications_not_shared422name_required422resident_id_requiredAll 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/care-sites/$SITE_REF/residents" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member_ref": "string",
"full_name": "string",
"resident_id": "string",
"date_of_birth": "string",
"room_label": "string",
"wing": "string",
"stay_type": "string",
"consent_basis": "string",
"consent_attested": false,
"attested_by_staff_ref": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"member_ref": "string",
"full_name": "string",
"resident_id": "string",
"date_of_birth": "string",
"room_label": "string",
"wing": "string",
"stay_type": "string",
"consent_basis": "string",
"consent_attested": False,
"attested_by_staff_ref": "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 site_ref = process.env.SITE_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"member_ref": "string",
"full_name": "string",
"resident_id": "string",
"date_of_birth": "string",
"room_label": "string",
"wing": "string",
"stay_type": "string",
"consent_basis": "string",
"consent_attested": false,
"attested_by_staff_ref": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Family access issued for a resident
care_site_living.family_list: every invitation for the resident at this site with its status (invited, expired, active, revoked), basis and what it shares. The family member's name is never returned.
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/care-sites/$SITE_REF/residents/$MEMBER_REF/family" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.get(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/family",
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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/family`);
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
Issue a family member read-only access to a resident
care_site_living.issue_family_access, the app's engine: basis resident or guardian (422 invalid_consent_basis), attested by the named staff member (422 consent_attestation_required / attesting_staff_not_found), something shared (422 nothing_shared), a valid address that is not the resident's (422 invalid_email), one open invitation per address (409 already_invited). `code` is returned ONCE; Norvya also emails it with its generic wording (no resident, no facility, nothing about health; a sandbox sends nothing). The family member sees counts and dated event types, never notes or medicine names. 409 invite_declined_by_person when the address declined your organisation's invitations; 429 invite_daily_cap_reached past the daily invitation cap.
Parameters
Request body
Content type: application/json (required)
The family member's address; they claim the code signed in with it.
resident | guardian
Must be true: the named staff member attests the resident's or guardian's consent.
Counts and dates of falls, hospital trips and reports (never notes).
Today's dose counts (never medicine names).
Errors specific to this call
422invalid_consent_basis422consent_attestation_required422nothing_shared422invalid_email409invite_declined_by_personAll 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/care-sites/$SITE_REF/residents/$MEMBER_REF/family" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "string",
"relationship": "string",
"consent_basis": "string",
"consent_attested": false,
"attested_by_staff_ref": "string",
"share_events": false,
"share_medications": false
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
member_ref = os.environ["MEMBER_REF"]
resp = requests.post(
f"{BASE}/v1/care-sites/{site_ref}/residents/{member_ref}/family",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"email": "string",
"relationship": "string",
"consent_basis": "string",
"consent_attested": False,
"attested_by_staff_ref": "string",
"share_events": False,
"share_medications": 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 site_ref = process.env.SITE_REF;
const member_ref = process.env.MEMBER_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/residents/${encodeURIComponent(member_ref)}/family`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"email": "string",
"relationship": "string",
"consent_basis": "string",
"consent_attested": false,
"attested_by_staff_ref": "string",
"share_events": false,
"share_medications": false
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());Try it in your sandbox
Revoke a family member's access (takes effect at once)
care_site_living.revoke_family_access: an unclaimed code stops working and a claimed access's caregiver grant is retracted, so the family member's next read is refused. 404 family_access_not_found; 409 already_revoked.
Parameters
Errors specific to this call
404family_access_not_found409already_revokedAll responses
200Successful Response401Unauthorized403Forbidden404Not Found409Conflict422Unprocessable Entity429Too Many Requests503Service UnavailableCodes every call can return are in Errors & limits.
curl -s -X DELETE "https://norvya.fly.dev/v1/care-sites/$SITE_REF/family/$FAMILY_ACCESS_REF" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
site_ref = os.environ["SITE_REF"]
family_access_ref = os.environ["FAMILY_ACCESS_REF"]
resp = requests.delete(
f"{BASE}/v1/care-sites/{site_ref}/family/{family_access_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 site_ref = process.env.SITE_REF;
const family_access_ref = process.env.FAMILY_ACCESS_REF;
const url = new URL(`${BASE}/v1/care-sites/${encodeURIComponent(site_ref)}/family/${encodeURIComponent(family_access_ref)}`);
const res = await fetch(url, {
method: "DELETE",
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 |
|---|---|---|
care_site.change_of_condition | care_sites.read | A change-of-condition report at one of your sites (a pharmacy's or a care facility's own). |
care_site.incident_recorded | care_sites.read | An incident report or a medication incident at one of your sites. |
care_site.mar_exception | care_sites.read | A scheduled dose recorded held or refused at one of your sites. |
Generated from the Partner API router and developers_catalog.py. The router docstring is the source of each description.