Create night report PDF
- Sandbox: available
- Staging: available
- Production: unknown
Creates a night report PDF for one resident and stores it. Optionally emails the PDF. Use it for the report download and email feature on the dashboard.
Auth: bearer token. The caller must be a practitioner, an admin or a System Owner, and needs search and read on Patient, Device and Observation.
Scope: the caller's project (from the token). The resident is read with your token, so Medplum's access policy limits which residents you can export.
Behaviour
codemust beTRENDS_PDF_EXPORT. Any other value is rejected with400.- The report layout comes from the export template content for
codeandlanguage. A template in your project wins over one in its parent project. The route returns400when no template exists. - The report period is
(period.start, period.end]in the project's time zone: for a range of more than one day the first day is left out, because its night belongs to the day before. A single-day range reports that day. A night counts for the day its sleep ends. - The report covers sleep statistics, heart rate and respiratory rate for each night. It holds only what ends inside one of the resident's use periods of its device, as
GET /v1/slim/sleep/statisticsdoes: the sleep table's recordings, and the readings behind the heart and respiratory rate rows and charts. A reading with no end time is then left out. So a previous resident's night that ended before the device was handed over, but reached Ovok after it, is not reported. A resident with no device use history has everything reported. - When a night has several sleep recordings left, the sleep table uses the one written last (latest
meta.lastUpdated), the ruleGET /v1/slim/sleep/statisticsuses. - Once a resident has any use period, the report also leaves out what a device with no period of theirs recorded, and what a device recorded before its earliest period. A device assigned before use periods were recorded gets its first one on its next edit in Ovok, starting at the Device's last write before that edit, so what it recorded before then is not reported. Each device whose readings in a report all drop is counted in the
sleep.device_use_device_droppedmetric and logged at most once a minute. - Report times use the project's time zone. The
timeZonefield in the body is not used. - The PDF is stored as a Binary, and a
DocumentReferencelinks it to the resident. Both are written in one transaction, so a failed store leaves neither. The response is thatDocumentReference. Itscontent[0].attachment.urlpoints to the Binary. - When
mailTohas addresses, the PDF is emailed to them as an attachment after the store succeeds. The email is sent in the language you set. With no addresses, nothing is emailed. - If the email cannot be sent, the route returns
500, but the report has already been stored. - Every call creates a new report. Nothing is deduplicated.
Example
curl -X POST 'https://api.sandbox.ovok.com/v1/slim/export/pdf' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NjcyNjg4MDAsImV4cCI6MTc2NzI3MjQwMH0.Ql3B_ztDvctlyZ2z0vp4sl3ExXRQGkzmxdmTAqxNzZk' \ -H 'Content-Type: application/json' \ -d '{ "code": "TRENDS_PDF_EXPORT", "patientId": "c3499c27-2973-0a7f-807e-fb8676a92dcb", "language": "en", "period": { "start": "2026-09-21T00:00:00Z", "end": "2026-09-28T00:00:00Z" }, "mailTo": ["max.mustermann@example.com"] }'bearerAuthorizationBearer <JWT>application/json- body
code*stringmailTo?array<>[]timeZone?stringIgnored; the project's time zone is used.
"Europe/Berlin"language*string"Cy-az-AZ""Cy-sr-SP""Cy-uz-UZ""Lt-az-AZ""Lt-sr-SP""Lt-uz-UZ""aa""ab""ae""af""af-ZA""ak""am""an""ar""ar-AE""ar-BH""ar-DZ""ar-EG""ar-IQ""ar-JO""ar-KW""ar-LB""ar-LY""ar-MA""ar-OM""ar-QA""ar-SA""ar-SY""ar-TN""ar-YE""as""av""ay""az""ba""be""be-BY""bg""bg-BG""bh""bi""bm""bn""bo""br""bs""ca""ca-ES""ce""ch""co""cr""cs""cs-CZ""cu""cv""cy""da""da-DK""de""de-AT""de-CH""de-DE""de-LI""de-LU""div-MV""dv""dz""ee""el""el-GR""en""en-AU""en-BZ""en-CA""en-CB""en-GB""en-IE""en-JM""en-NZ""en-PH""en-TT""en-US""en-ZA""en-ZW""eo""es""es-AR""es-BO""es-CL""es-CO""es-CR""es-DO""es-EC""es-ES""es-GT""es-HN""es-MX""es-NI""es-PA""es-PE""es-PR""es-PY""es-SV""es-UY""es-VE""et""et-EE""eu""eu-ES""fa""fa-IR""ff""fi""fi-FI""fj""fo""fo-FO""fr""fr-BE""fr-CA""fr-CH""fr-FR""fr-LU""fr-MC""fy""ga""gd""gl""gl-ES""gn""gu""gu-IN""gv""ha""he""he-IL""hi""hi-IN""ho""hr""hr-HR""ht""hu""hu-HU""hy""hy-AM""hz""ia""id""id-ID""ie""ig""ii""ik""io""is""is-IS""it""it-CH""it-IT""iu""ja""ja-JP""jv""ka""ka-GE""kg""ki""kj""kk""kk-KZ""kl""km""kn""kn-IN""ko""ko-KR""kr""ks""ku""kv""kw""ky""ky-KZ""la""lb""lg""li""ln""lo""lt""lt-LT""lu""lv""lv-LV""mg""mh""mi""mk""mk-MK""ml""mn""mn-MN""mr""mr-IN""ms""ms-BN""ms-MY""mt""my""na""nb""nb-NO""nd""ne""ng""nl""nl-BE""nl-NL""nn""nn-NO""no""nr""nv""ny""oc""oj""om""or""os""pa""pa-IN""pi""pl""pl-PL""ps""pt""pt-BR""pt-PT""qu""rm""rn""ro""ro-RO""ru""ru-RU""rw""sa""sa-IN""sc""sd""se""sg""si""sk""sk-SK""sl""sl-SI""sm""sn""so""sq""sq-AL""sr""ss""st""su""sv""sv-FI""sv-SE""sw""sw-KE""ta""ta-IN""te""te-IN""tg""th""th-TH""ti""tk""tl""tn""to""tr""tr-TR""ts""tt""tt-RU""tw""ty""ug""uk""uk-UA""ur""ur-PK""uz""ve""vi""vi-VN""vo""wa""wo""xh""yi""yo""za""zh""zh-CHS""zh-CHT""zh-CN""zh-HK""zh-MO""zh-SG""zh-TW""zu"patientId*stringuuidperiod*The stored DocumentReference that links the PDF to the resident.
application/json- response
resourceType*"DocumentReference""DocumentReference"id*stringDocumentReference id.
meta*status*"current""current"date*stringWhen the report was created.
date-timecategory*array<>subject*The resident the report is about.
author?array<>The caller who created the report. Left out when the session has no profile.
content*array<>[key: string]?anycurl -X POST 'https://api.sandbox.ovok.com/v1/slim/export/pdf' \ -H 'Content-Type: application/json' \ -d '{ "code": "string", "language": "Cy-az-AZ", "patientId": "460a6d87-689c-4661-a526-a52450bbe2d7", "period": { "start": "2019-08-24T14:15:22Z", "end": "2019-08-24T14:15:22Z" }}'{ "resourceType": "DocumentReference", "id": "string", "meta": { "project": "string" }, "status": "current", "date": "2019-08-24T14:15:22Z", "category": [ { "coding": [ { "system": "string", "code": "string" } ] } ], "subject": { "reference": "string", "display": "string" }, "author": [ { "reference": "string", "display": "string" } ], "content": [ { "attachment": { "contentType": "application/pdf", "url": "string", "title": "string" } } ]}Update device PUT
Updates a device's name and identifier, and assigns or unassigns its zone, location and resident. **Auth:** bearer token. The caller must be a practitioner, an admin or a System Owner, and needs `Device:update`. **Scope:** the device must belong to the caller's project (from the token). ## Behaviour - `name` is required and replaces the device's user-friendly name, trimmed. Renaming the device to a serial that a device of another customer already holds is refused with 409, in any spelling. - Renaming the device to a serial another device of your project holds is refused with 422, in any spelling: spaces around it or its `/`, other case, with or without the manufacturer prefix ingest gives the serial. A device may take another spelling of its own serial. - For `organizationId`, `locationId` and `patientId`: omit the field to leave it unchanged, send `null` to unassign, or send a UUID to assign. - A device in a room is in the room's zone. An `organizationId` that differs from the zone of the device's room (the room you send, or the one it is in) answers 422 with `path: ["organizationId"]` and changes nothing: move the room to that zone, or the device to a room in it. A device with no room, or in a room with no zone, takes any zone. A zone change re-zones only the device, never its room, the room's other devices or a resident. - Assigning a resident moves them: the resident is removed from every other device they hold. The resident who was on this device before loses it. Each resident who loses a device has their active out-of-bed episode closed in the same transaction. - Assigning a resident who is not active (`discharged`, `discharged-recent` or `archived`) is refused with 422 and changes nothing: reactivate them first. Unassigning one (`patientId: null`) is allowed. - All changes are written in one transaction. If any part fails, nothing is written. - Sending values the device already has is not an error, and writes nothing. - Resident assignment changes, renames, identifier changes and zone changes are recorded in the change history. - The response is the same as `GET /v1/slim/device/{id}` after the update. ## Example ```bash curl -X PUT 'https://api.sandbox.ovok.com/v1/slim/device/c3499c27-2973-0a7f-807e-fb8676a92dcb' \ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NjcyNjg4MDAsImV4cCI6MTc2NzI3MjQwMH0.Ql3B_ztDvctlyZ2z0vp4sl3ExXRQGkzmxdmTAqxNzZk' \ -H 'Content-Type: application/json' \ -d '{"name": "Sleepiz/3001000", "patientId": null}' ```
Get health status GET
Returns the health of the Slim API and the systems it depends on. Use it for uptime checks and status screens. **Auth:** none. ## Behaviour - `status` is `healthy` when both the FHIR store and Redis are up, `degraded` when one is down, and `unhealthy` when both are down. The route still answers `200` in every case, so read `status`, not the HTTP code. - `externalSystems.fhirStore` and `externalSystems.redis` hold each system's own status and, when available, its version, memory and connection figures. `responseTimeMs` is the time the FHIR store took to answer its health check. - `cache` holds hit, miss and error counts of the application cache since the process started. - `ovok`, `system` and the FHIR store `serverMetrics` come from the monitoring system, from the last 5 minutes. They are left out when monitoring is not configured or does not answer. - `uptimeSeconds` is the time since this process started. `version` is `null` when the deployment does not set one. ## Example ```bash curl -X GET 'https://api.sandbox.ovok.com/v1/slim/health' ```