Get patient effective threshold (v2)
| Method | Path |
|---|---|
GET | /v2/slim/threshold/patient/:patientId |
Authentication · Access policies
Returns the thresholds in effect for one resident in the v2 shape: their own limits where they have them, and the home's limits everywhere else.
This route supersedes GET /v1/slim/threshold/patient/{patientId}. It adds baseline limits, ranges, the optional vitals and a signalsSync health verdict, and it checks that the resident exists.
Auth: Bearer token. The caller must be a practitioner, an admin, a super admin, or hold the "System Owner" access policy. The access policy must grant Goal:read (admins and super admins skip this check).
Scope: The resident must be in the caller's project (from the token). A resident in another project (a sub-project included) answers 404, the same as an unknown id.
Request
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
patientId | string (uuid) | Yes | The resident's Patient id. |
Behaviour
- Read-only; no threshold is created. The one side effect is the "limits not confirmed" flag described below.
- Every settings field carries a
mode:patient(the resident's own limit),organization(follows the home) or, for heart and respiratory rate,baseline(alerts relative to the resident's own baseline). A field inorganizationmode carries the home's concrete values, so clients never compute the fallback themselves. settings.heartRateandsettings.respiratoryRateare either the absolute shape (minandmax) or the baseline shape (deviationPercent,baselineAverage,effectiveBand).baselineAverageis the resident's baseline average (the device's latest 7-day mean, rounded to one decimal),nullwhen none is on record.effectiveBandis the band Signals is given: the average moved bydeviationPercenteither way,nullwithout an average.settings.outOfBedandsettings.bedTimePeriodindividualise independently: a resident can have their own bed-time window on the home's out-of-bed limit, or the other way round.settings.outOfBed.deviationPercent(ornull) is the relative band: alert once an exit runs that many percent past the resident's usual one.baselineAverageis that usual exit length in seconds: the median exit inside the resident's bed-time period over the last 14 nights of presence data,nullwith the band off or fewer than 7 nights in bed and 5 exits.effectiveMaxDurationSecondsis the limit the evaluator applies:maxDurationSeconds, or the usual exit plus the percentage when that is shorter, floored to the minute;nullwhen out-of-bed alerting is off.settings.bedTimePeriod.timezoneis server-resolved: the zone the out-of-bed check reads the window in, which is the home's (Europe/Berlin unless the home set one).startandendare wall-clock times in it. A window nobody stored reads as 19:00 to 09:00, and that is also the window the out-of-bed check applies. A storedendequal tostartis a deliberate 24-hour window.settings.oxygenSaturation,pulseRate,perfusionIndexandbodyTemperaturearenullwhen neither the home nor the resident watches the vital, else{ mode, enabled, min, max }. They are read from Signals first, since Signals evaluates them; Ovok's copy is only the fallback when Signals cannot answer, andsignalsSyncsays so.rangesis the home's range for each vital's limits, the same as on Get current org threshold (v2), so an editor can bound a resident's inputs.idisnull: a resident's own limits are not one stored document.updatedAtis when the home's thresholds were last saved, not when the resident's own limits last changed.signalsSyncsays whether Signals holds the limits Ovok last sent.nullmeans the status could not be read. Otherwisestatusis one of:ok: a comparison against what Signals holds ran and agreed.pending: a fault was found, andreasonnames it:limits-not-confirmed,not-found-in-signals,never-pushed,stale-config-push,signals-rule-missing, or a reason with the affected codes after a colon (metric-disarmed:,trigger-mismatch:,trigger-content-mismatch:,evaluator-band-mismatch:).unverified: the check could not run, andreasonnames the missing evidence (no-pushed-record,no-pushed-fingerprints,no-signals-fingerprints,signals-read-stale). It is not a fault report, and it is not a claim of health.
- When
signalsSyncispendingwithtrigger-mismatchortrigger-content-mismatch(Signals holds something other than the last push), this read also flags the resident as "limits not confirmed". It then appears onGET /signals/config/unconfirmed, wherePOST /signals/config/unconfirmed/repushcan send their limits again, and the next confirmed push clears the flag. - A failed read of the home's stored thresholds answers 502, never the home's empty template.
Example
curl -X GET 'https://api.sandbox.ovok.com/v2/slim/threshold/patient/3f1c2b7e-8d4a-4c1e-9b2f-6a7d5e4c3b21' \
-H "Authorization: Bearer ${OVOK_TOKEN}"
Successful response
200 — Patient v2 threshold retrieved successfully.
{
"id": null,
"patientId": "3f1c2b7e-8d4a-4c1e-9b2f-6a7d5e4c3b21",
"projectId": "3f1c2b7e-8d4a-4c1e-9b2f-6a7d5e4c3b11",
"updatedAt": "2026-10-09T08:30:00.000Z",
"settings": {
"heartRate": { "mode": "patient", "enabled": true, "min": 50, "max": 100 },
"respiratoryRate": {
"mode": "baseline",
"enabled": true,
"deviationPercent": 25,
"baselineAverage": 16,
"effectiveBand": { "min": 12, "max": 20 }
},
"outOfBed": {
"mode": "patient",
"enabled": true,
"maxDurationSeconds": 900,
"deviationPercent": 50,
"baselineAverage": 312,
"effectiveMaxDurationSeconds": 420
},
"bedTimePeriod": { "mode": "organization", "start": "19:00:00", "end": "09:00:00", "timezone": "Europe/Berlin" },
"oxygenSaturation": { "mode": "organization", "enabled": true, "min": 92, "max": null },
"pulseRate": null,
"perfusionIndex": null,
"bodyTemperature": null
},
"ranges": {
"heartRate": { "min": 40, "max": 120 },
"respiratoryRate": { "min": 4, "max": 60 },
"oxygenSaturation": { "min": 70, "max": 100 },
"pulseRate": { "min": 40, "max": 120 },
"perfusionIndex": { "min": 0, "max": 20 },
"bodyTemperature": { "min": 34, "max": 42 }
},
"signalsSync": { "status": "ok" }
}
| Field | Type | Description |
|---|---|---|
id | string | null | Always null today. |
patientId | string (uuid) | The resident. |
projectId | string | The caller's project. |
updatedAt | string (ISO 8601 date-time) | null | When the home's thresholds were last saved. |
settings | object | The limits in effect for the resident. |
settings.heartRate | object | Heart-rate limit. Either the absolute shape or the baseline shape below. |
settings.heartRate.mode | "organization" | "patient" | "baseline" | organization follows the home (absolute or, for a home that still holds one, baseline). patient is the resident's own absolute band. baseline is the resident's own baseline band. |
settings.heartRate.enabled | boolean | Whether the limit alerts. |
settings.heartRate.min | number | Lower bound in beats per minute. Absolute shape only. |
settings.heartRate.max | number | Upper bound in beats per minute. Absolute shape only. |
settings.heartRate.deviationPercent | number | Baseline shape only: the symmetric deviation from the resident's baseline, in percent. |
settings.heartRate.baselineAverage | number | null | Baseline shape only: the resident's baseline average, or null when none is on record. |
settings.heartRate.effectiveBand | object | null | Baseline shape only: the band in effect, or null without an average. |
settings.heartRate.effectiveBand.min | number | Lower bound of the band in effect. |
settings.heartRate.effectiveBand.max | number | Upper bound of the band in effect. |
settings.respiratoryRate | object | Respiratory-rate limit. Same fields as settings.heartRate, in breaths per minute. |
settings.outOfBed | object | Out-of-bed limit. |
settings.outOfBed.mode | "organization" | "patient" | Whether the limit follows the home or is the resident's own. |
settings.outOfBed.enabled | boolean | Whether out-of-bed alerting is on. |
settings.outOfBed.maxDurationSeconds | integer | The longest exit allowed, in seconds. |
settings.outOfBed.deviationPercent | integer | null | The relative band, in percent. null when off. |
settings.outOfBed.baselineAverage | number | null | The resident's usual exit length in seconds. null with the band off, on too little data, or when it could not be read. |
settings.outOfBed.effectiveMaxDurationSeconds | number | null | The limit the evaluator applies to this resident, in seconds. null when out-of-bed alerting is off. |
settings.bedTimePeriod | object | The window in which out-of-bed is checked. |
settings.bedTimePeriod.mode | "organization" | "patient" | Whether the window is the home's or the resident's own. |
settings.bedTimePeriod.start | string (HH:MM:SS) | Window start, wall-clock time in timezone. |
settings.bedTimePeriod.end | string (HH:MM:SS) | Window end. Equal to start means 24 hours; before start crosses midnight. |
settings.bedTimePeriod.timezone | string | null | IANA time zone the window is read in, resolved by the server. |
settings.oxygenSaturation | object | null | SpO₂ limit. null when neither the home nor the resident watches the vital. |
settings.oxygenSaturation.mode | "organization" | "patient" | Whether the limit follows the home or is the resident's own. |
settings.oxygenSaturation.enabled | boolean | Whether the limit alerts. |
settings.oxygenSaturation.min | number | null | Lower bound, or null for none. |
settings.oxygenSaturation.max | number | null | Upper bound, or null for none. |
settings.pulseRate | object | null | Pulse-rate limit. Same fields as settings.oxygenSaturation. |
settings.perfusionIndex | object | null | Perfusion-index limit. Same fields as settings.oxygenSaturation. |
settings.bodyTemperature | object | null | Body-temperature limit. Same fields as settings.oxygenSaturation. |
ranges | object | The home's range for each vital's limits. Always present. |
ranges.heartRate | object | { min, max }, both number. Same shape for ranges.respiratoryRate, ranges.oxygenSaturation, ranges.pulseRate, ranges.perfusionIndex and ranges.bodyTemperature. |
signalsSync | object | null | Whether Signals holds the limits Ovok last sent. null when the status could not be read. |
signalsSync.status | "ok" | "pending" | "unverified" | The verdict. See Behaviour. |
signalsSync.reason | string | Present when status is pending or unverified. Names the fault or the missing evidence. |
Errors
| Status | Meaning |
|---|---|
400 | Your session has no project. |
401 | Bearer token is missing, invalid or expired. |
403 | You are not a practitioner, admin or System Owner, or you lack Goal:read. |
404 | No patient with this id exists, or the patient is in another project. |
502 | The home's stored thresholds could not be read. |
503 | The access policy could not be read right now. Retry. |