Behavioral health
Measurement-based care: the therapy caseload with PHQ-9 / GAD-7 trends, homework assigned and ended (the patient's entries never leave), and the collaborative-care (CoCM / BHI) registry with enrolment, consent, discharge and month evidence as a candidate for the biller's review; signed therapy progress notes appear in Records & documents. Psychotherapy notes, safety plans and AI drafts never leave; a designated 42 CFR Part 2 programme is refused; substance-use data appears only when the patient shares it. Webhook: cocm.review_due.
- Who calls it
- Core for Behavioral health practices
- Before production
- Treating practices with a BAA; the patient must share mental health with you.
- Sandbox
- Build against synthetic members first. What each sandbox holds
- Standards
- PHQ-9 / GAD-7; CoCM / BHI registry; 42 CFR Part 2 programmes refused
Markets that use this family
- Behavioral health practices (core)
Scopes
| Scope | Allows |
|---|---|
behavioral.read | Read your measurement-based-care caseload (PHQ-9 / GAD-7 / PCL-5 totals and trend, what is due, the not-improving prompt, homework progress as counts), one patient's scores and homework, and your Collaborative Care / BHI registry with each episode's status and flags; with billing.read also an episode's month as a candidate for your biller. Only patients who share mental health with you; never psychotherapy notes, safety plans, homework entry text or 42 CFR Part 2 records (treating practices with a BAA on file; not a designated Part 2 program). |
behavioral.write | Assign and end between-session homework (Norvya's own generic notification), enrol a patient in Collaborative Care or general BHI, record the documented consent and discharge, each attributed to a named clinician of your practice (patients who share mental health with you only). |
Endpoints
Your measurement-based-care caseload (patients who share mental health with you)
The therapy practice's caseload exactly as Norvya's staff screen orders it: PHQ-9 / GAD-7 / PCL-5 totals with baseline, latest and trend, response and remission where a source defines them, what is due, the not-improving prompt and homework counts. A patient who does not share mental health with you is never listed (only counted in withheld_not_sharing). crisis.open means a questionnaire tripped the crisis gate: the patient already saw crisis resources and your staff were notified in Norvya; follow your crisis protocol (crisis.guidance). Not a 42 CFR Part 2 program; BAA on file.
Parameters
active | ended | 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/behavioral/caseload" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/behavioral/caseload",
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/behavioral/caseload`);
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());{
"items": [
{
"episode_ref": "bhe_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"status": "string",
"scales": [
"string"
],
"start_date": "string",
"end_date": "string",
"end_reason": "string",
"weeks_in_care": 0,
"scale_interval_days": 0,
"last_scale_at": "string",
"next_scale_due": "string",
"therapist": "string",
"scores": {},
"crisis": {
"open": false,
"latest_at": "string",
"reviewed_at": "string",
"guidance": "string"
},
"homework": {
"active": 0,
"done_in_period": 0,
"asked_in_period": 0
},
"flags": [
"string"
]
}
],
"withheld_not_sharing": 0,
"thresholds": {},
"sources": {},
"disclaimer": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
One patient's measurement-based care: scores, crisis state, episode and homework
409 member_not_sharing_mental_health unless the patient shares mental health with you. Homework is counts and dates: what the client wrote is never returned. Psychotherapy notes and the safety plan are never available here (`not_available` says why).
Parameters
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
Errors specific to this call
409member_not_sharing_mental_healthAll 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/behavioral" \
-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}/behavioral",
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)}/behavioral`);
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",
"scores": {},
"crisis": {
"open": false,
"latest_at": "string",
"reviewed_at": "string",
"guidance": "string"
},
"therapy_episode": {
"episode_ref": "bhe_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"status": "string",
"scales": [
"string"
],
"start_date": "string",
"end_date": "string",
"end_reason": "string",
"weeks_in_care": 0,
"scale_interval_days": 0,
"last_scale_at": "string",
"next_scale_due": "string",
"therapist": "string",
"scores": {},
"crisis": {
"open": false,
"latest_at": "string",
"reviewed_at": "string",
"guidance": "string"
},
"homework": {
"active": 0,
"done_in_period": 0,
"asked_in_period": 0
},
"flags": [
"string"
]
},
"homework": [
{
"homework_ref": "bhw_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"kind": "string",
"practice_kind": "string",
"instructions": "string",
"cadence": "string",
"times_per_week": 0,
"start_date": "string",
"end_date": "string",
"status": "string",
"assigned_by": "string",
"progress": {
"period_start": "string",
"done_in_period": 0,
"asked_in_period": 0,
"done_total": 0,
"last_done_at": "string"
},
"completed_on": [
"string"
]
}
],
"cocm_episode_ref": "string",
"cocm_status": "string",
"not_available": [
{
"item": "string",
"reason": "string"
}
],
"disclaimer": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
Assign between-session homework
Through the therapy engine's own assignment (therapy_practice. assign_homework): the client completes it in Norvya's self-help tools and is told with Norvya's generic notification (never your text on the lock screen). Attributed to the clinician you name. Patients who share mental health with you and accept your messages only.
Parameters
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
Request body
Content type: application/json (required)
staff_ref of the clinician assigning it (GET /v1/panel/clinicians).
thought_record | behavioral_activation | practice | checkin
once | daily | weekly
practice only: breathing | gratitude | mindfulness | cognitive | gym | social | purpose
YYYY-MM-DD; default today.
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/patients/$MEMBER_REF/behavioral/homework" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clinician": "string",
"kind": "behavioral_activation",
"cadence": "string",
"times_per_week": 0,
"practice_kind": "string",
"instructions": "string",
"start_date": "string",
"end_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/patients/{member_ref}/behavioral/homework",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"clinician": "string",
"kind": "behavioral_activation",
"cadence": "string",
"times_per_week": 0,
"practice_kind": "string",
"instructions": "string",
"start_date": "string",
"end_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/patients/${encodeURIComponent(member_ref)}/behavioral/homework`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"clinician": "string",
"kind": "behavioral_activation",
"cadence": "string",
"times_per_week": 0,
"practice_kind": "string",
"instructions": "string",
"start_date": "string",
"end_date": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"homework_ref": "bhw_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"kind": "string",
"practice_kind": "string",
"instructions": "string",
"cadence": "string",
"times_per_week": 0,
"start_date": "string",
"end_date": "string",
"status": "string",
"assigned_by": "string",
"progress": {
"period_start": "string",
"done_in_period": 0,
"asked_in_period": 0,
"done_total": 0,
"last_done_at": "string"
},
"completed_on": [
"string"
]
}The response is the shape from the schema, not live data.
Try it in your sandbox
End an assignment
404 homework_not_found for another practice's assignment, a member no longer linked or not sharing mental health with you.
Parameters
Request body
Content type: application/json (required)
staff_ref of the clinician acting.
Errors specific to this call
404homework_not_foundAll 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/behavioral/homework/$HOMEWORK_REF/end" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clinician": "string"
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
homework_ref = os.environ["HOMEWORK_REF"]
resp = requests.post(
f"{BASE}/v1/behavioral/homework/{homework_ref}/end",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"clinician": "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 homework_ref = process.env.HOMEWORK_REF;
const url = new URL(`${BASE}/v1/behavioral/homework/${encodeURIComponent(homework_ref)}/end`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"clinician": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"homework_ref": "bhw_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"kind": "string",
"practice_kind": "string",
"instructions": "string",
"cadence": "string",
"times_per_week": 0,
"start_date": "string",
"end_date": "string",
"status": "string",
"assigned_by": "string",
"progress": {
"period_start": "string",
"done_in_period": 0,
"asked_in_period": 0,
"done_total": 0,
"last_done_at": "string"
},
"completed_on": [
"string"
]
}The response is the shape from the schema, not live data.
Try it in your sandbox
Your Collaborative Care / BHI registry with each episode's status and flags
The registry Norvya's staff screen shows, in its priority order, with the flags it computes (crisis_open, not_improving, recommendation_pending, scale_overdue, no_recent_contact, consent_missing, consent_renewal_needed, team_incomplete). Patients who do not share mental health with you are counted, never shown; a substance-use target appears only when the patient shares substance-use information with you. Minutes: GET .../months/{month} (with billing.read) or GET /v1/billing/care-management?program=cocm.
Parameters
active | discharged | consent_withdrawn | 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/behavioral/cocm/registry" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.get(
BASE + "/v1/behavioral/cocm/registry",
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/behavioral/cocm/registry`);
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());{
"items": [
{
"episode_ref": "bhc_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"model": "string",
"status": "string",
"target_conditions": [
"string"
],
"start_date": "string",
"end_date": "string",
"weeks_in_treatment": 0,
"scale_interval_days": 0,
"next_scale_due": "string",
"phq9": {
"scale": "phq9",
"baseline": {},
"latest": {},
"trend": [],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"gad7": {
"scale": "phq9",
"baseline": {},
"latest": {},
"trend": [],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"consent": "string",
"team": {},
"flags": [
"string"
],
"crisis_guidance": "string",
"consent_detail": {},
"initiating_visit": {},
"discharge": {},
"reviews": {},
"see_also": "string"
}
],
"withheld_not_sharing": 0,
"reference_minutes": {},
"sources": {},
"disclaimer": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
Enrol a patient in Collaborative Care or general BHI
The registry's own enrolment (cocm_registry.enroll): one active episode per patient (409 already_enrolled), the care team named by staff_ref (each an active clinician of your practice). Consent is recorded separately (POST .../consent). Norvya keeps the registry; it does not decide eligibility or billing.
EMR vendors also pass vendor (the practice) with a vendor-issued token. EMR vendor tokens
Request body
Content type: application/json (required)
staff_ref of the clinician enrolling the patient.
cocm | general_bhi
depression | anxiety | ptsd | other (substance_use is not set through the API).
Errors specific to this call
409already_enrolledAll 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/behavioral/cocm/episodes" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member_ref": "string",
"clinician": "string",
"model": "cocm",
"target_conditions": [
"string"
],
"target_note": "string",
"start_date": "string",
"team": {
"treating_provider": "string",
"care_manager": "string",
"psychiatric_consultant": "string"
},
"scale_interval_days": 0
}'import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
resp = requests.post(
BASE + "/v1/behavioral/cocm/episodes",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"member_ref": "string",
"clinician": "string",
"model": "cocm",
"target_conditions": [
"string",
],
"target_note": "string",
"start_date": "string",
"team": {
"treating_provider": "string",
"care_manager": "string",
"psychiatric_consultant": "string",
},
"scale_interval_days": 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/behavioral/cocm/episodes`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"member_ref": "string",
"clinician": "string",
"model": "cocm",
"target_conditions": [
"string"
],
"target_note": "string",
"start_date": "string",
"team": {
"treating_provider": "string",
"care_manager": "string",
"psychiatric_consultant": "string"
},
"scale_interval_days": 0
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"episode_ref": "bhc_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"model": "string",
"status": "string",
"target_conditions": [
"string"
],
"start_date": "string",
"end_date": "string",
"weeks_in_treatment": 0,
"scale_interval_days": 0,
"next_scale_due": "string",
"phq9": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"gad7": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"consent": "string",
"team": {},
"flags": [
"string"
],
"crisis_guidance": "string",
"consent_detail": {},
"initiating_visit": {},
"discharge": {},
"reviews": {},
"see_also": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
One Collaborative Care / BHI episode: status, consent, reviews
Status and flags, the consent state and how it was documented, the initiating visit, discharge, and how often the episode was reviewed with the psychiatric consultant (never the recommendation or relapse-plan text).
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/behavioral/cocm/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/behavioral/cocm/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/behavioral/cocm/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());{
"episode_ref": "bhc_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"model": "string",
"status": "string",
"target_conditions": [
"string"
],
"start_date": "string",
"end_date": "string",
"weeks_in_treatment": 0,
"scale_interval_days": 0,
"next_scale_due": "string",
"phq9": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"gad7": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"consent": "string",
"team": {},
"flags": [
"string"
],
"crisis_guidance": "string",
"consent_detail": {},
"initiating_visit": {},
"discharge": {},
"reviews": {},
"see_also": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
Record the patient's documented CoCM consent
Verbal or written consent your clinician documented, with both elements CMS describes (permission to consult specialists; told cost sharing applies) — 422 consent_elements_required otherwise. In-app consent is the patient's own act in Norvya and cannot be recorded here.
Parameters
Request body
Content type: application/json (required)
staff_ref of the clinician who documented the consent.
verbal | written
Permission to consult the psychiatric consultant / specialists.
The patient was told cost sharing applies.
Errors specific to this call
422consent_elements_requiredAll 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/behavioral/cocm/episodes/$EPISODE_REF/consent" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clinician": "string",
"method": "string",
"consent_date": "string",
"specialist_consult": false,
"cost_sharing_informed": 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/behavioral/cocm/episodes/{episode_ref}/consent",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"clinician": "string",
"method": "string",
"consent_date": "string",
"specialist_consult": False,
"cost_sharing_informed": 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/behavioral/cocm/episodes/${encodeURIComponent(episode_ref)}/consent`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"clinician": "string",
"method": "string",
"consent_date": "string",
"specialist_consult": false,
"cost_sharing_informed": false
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"episode_ref": "bhc_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"model": "string",
"status": "string",
"target_conditions": [
"string"
],
"start_date": "string",
"end_date": "string",
"weeks_in_treatment": 0,
"scale_interval_days": 0,
"next_scale_due": "string",
"phq9": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"gad7": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"consent": "string",
"team": {},
"flags": [
"string"
],
"crisis_guidance": "string",
"consent_detail": {},
"initiating_visit": {},
"discharge": {},
"reviews": {},
"see_also": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
Discharge a Collaborative Care / BHI episode
goals_met needs the relapse-prevention plan your clinician wrote (422 relapse_plan_required); 409 episode_closed for an episode already ended.
Parameters
Request body
Content type: application/json (required)
staff_ref of the clinician discharging.
goals_met | referred_specialty_care | six_month_break | patient_declined | moved_or_transferred | other
Required for goals_met.
Errors specific to this call
409episode_closedAll 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/behavioral/cocm/episodes/$EPISODE_REF/discharge" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clinician": "string",
"reason": "string",
"end_date": "string",
"relapse_prevention_plan": "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/behavioral/cocm/episodes/{episode_ref}/discharge",
headers={"Authorization": f"Bearer {TOKEN}"},
json={
"clinician": "string",
"reason": "string",
"end_date": "string",
"relapse_prevention_plan": "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/behavioral/cocm/episodes/${encodeURIComponent(episode_ref)}/discharge`);
const res = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"clinician": "string",
"reason": "string",
"end_date": "string",
"relapse_prevention_plan": "string"
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());{
"episode_ref": "bhc_4c1d2e3f4a5b6c7d8e9f0a1b",
"member_ref": "string",
"model": "string",
"status": "string",
"target_conditions": [
"string"
],
"start_date": "string",
"end_date": "string",
"weeks_in_treatment": 0,
"scale_interval_days": 0,
"next_scale_due": "string",
"phq9": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"gad7": {
"scale": "phq9",
"baseline": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"latest": {
"score": 0.0,
"band": "string",
"completed_at": "string"
},
"trend": [
{
"score": 0.0,
"band": "string",
"completed_at": "string"
}
],
"change": 0.0,
"change_pct": 0.0,
"response": false,
"remission": false,
"target": 0.0,
"target_source": "string",
"target_met": false
},
"consent": "string",
"team": {},
"flags": [
"string"
],
"crisis_guidance": "string",
"consent_detail": {},
"initiating_visit": {},
"discharge": {},
"reviews": {},
"see_also": "string"
}The response is the shape from the schema, not live data.
Try it in your sandbox
An episode's month as a candidate for your biller's review
Care-manager minutes (and other staff's, apart), consent in force, a psychiatric review and a rating scale in the month, the initiating visit and the six-month-break note, against the reference minutes CMS MLN909432 describes. status candidate_for_biller_review: never a charge, an eligibility determination or a code attached to the patient. Needs billing.read as well.
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/behavioral/cocm/episodes/$EPISODE_REF/months/$MONTH" \
-H "Authorization: Bearer $TOKEN"import os
import requests
BASE = "https://norvya.fly.dev"
TOKEN = os.environ["TOKEN"]
episode_ref = os.environ["EPISODE_REF"]
month = os.environ["MONTH"]
resp = requests.get(
f"{BASE}/v1/behavioral/cocm/episodes/{episode_ref}/months/{month}",
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 month = process.env.MONTH;
const url = new URL(`${BASE}/v1/behavioral/cocm/episodes/${encodeURIComponent(episode_ref)}/months/${encodeURIComponent(month)}`);
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());{
"episode_ref": "string",
"member_ref": "string",
"status": "candidate_for_biller_review",
"notice": "string",
"program": "string",
"service_month": "string",
"enrolled": false,
"model": "string",
"consent_recorded": false,
"initial_month": false,
"minutes": 0,
"other_staff_minutes": 0,
"psychiatric_review_in_month": false,
"rating_scale_in_month": false,
"care_manager_assigned": false,
"initiating_visit_recorded": false,
"reference_minutes": {},
"notes": [
"string"
],
"disclaimer": "string",
"sources": [
"string"
],
"see_also": "string"
}The response is the shape from the schema, not live data.
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 |
|---|---|---|
cocm.review_due | behavioral.read | The practice's weekly Collaborative Care caseload review is due (about the practice, not a patient: no member_ref). |
Generated from the Partner API router and developers_catalog.py. The router docstring is the source of each description.