Signals API - Health

Liveness

  • Sandbox: available
  • Staging: available
  • Production: unknown
GET
/v1/signals/api/health

Unauthenticated, always 200: the HTTP status reports that the process is serving, not that its dependencies are well, because this route gates container liveness. healthy is false while the database does not answer (db.ok); page on it.

Through ovok

  • Who can call it: any caller with an ovok access token, or a client id and secret. It needs no capability.

Authorization

headerAuthorizationBearer <JWT>

Response Body

The service is up; db reports database reachability, version and commit the running build.

application/json
  1. response
healthy*boolean

False while the database does not answer, as db.ok; the status stays 200.

db*

Database reachability; ok is false on a stall.

version*string

The running release: the one the deploy workflow stamped, else <next>-dev+<commit>; null when neither is known.

commit*string

The commit the running build was made from; null when unknown.

Example Request
curl -X GET 'https://api.sandbox.ovok.com/v1/signals/api/health'
Example Response
{  "healthy": true,  "db": {    "ok": true,    "latencyMs": 0,    "error": "string"  },  "version": "string",  "commit": "string"}

Redeliver one event POST

Queues this delivery to be sent now, whatever its status, with a fresh retry ladder: the same `webhook-id` and a new `webhook-timestamp`. An alert is sent whatever its age. ### Through ovok - **Who can call it:** Manager apps, and users whose access policy grants the capabilities. - **Capabilities, all required:** `signals_webhooks:update`. Project admins have every capability; client applications get no admin bypass. - It can reach any patient of your project without naming one, so it is for callers that reach every patient: project admins, manager or submitter apps, and anyone whose Patient access has no criteria.

Submit a reading by patient refId POST

The patient is `patientRefId` in the body, else `subject.reference` (`Patient/<refId>`). The body is a FHIR R4 Observation: `code`, `value[x]` (any of FHIR R4's eleven) or `dataAbsentReason`, and a combined device sample's vitals as `component[]` (each `code`, `value[x]`, optional `dataAbsentReason`). The clinical time is `effectiveDateTime`, `effectiveInstant` or `effectivePeriod.start`, else `issued`, else the server's receipt; `device` is `{reference, display}`; the first `identifier`'s `value` is stored as v1's `refId`. Other FHIR elements (`meta`, `extension`, `performer`, `interpretation`, `referenceRange`, …) are accepted and ignored. v1's `observedAt` (it wins over `effective[x]`), `refId`, string `dataAbsentReason` and `device.id` still work. A node with `dataAbsentReason` and no value is judged as carrying no value, and the rules read the reason as `absent`. `valueSampledData` is judged by its latest sample and stored whole, and the rules read every sample as `samples`. A `valueDateTime`, on the reading or a component, is judged and aggregated as epoch ms (`valueNumber`) and listed as sent. A `valueBoolean` is judged as 1 or 0. A `valueTime` is judged as ms since midnight, a `valuePeriod` as its length in ms (none while open or without an offset), a `valueRatio` as its quotient, and each is also kept as text (`valueString`); a `valueRange` is judged as the text `low..high`. **History is never judged.** A reading whose `category` has a coding the tenant names as history (its `historyCategories`; the default pack's: `batch-data`, `statistics`, `presence-batch`, `derived`) is stored and deduplicated like any other, answered with no alerts, and never judged nor read by the rules. The caller must be one of the patient's submitters, admins included: a known patient it is not attached to is a 403, an unknown one a 404 with type `PATIENT_NOT_FOUND`. **Idempotent.** A reading is named by its first `identifier` (`system|value`), else by its clinical time, code, device and `refId`. A resend of one stored within the last hour is a 409 `DUPLICATE_READING` whose `data.observationId` is the stored reading, and is neither stored nor evaluated again. A reading with neither an identifier nor a clinical time is not deduplicated. Concurrent requests are batched server-side. With `Prefer: respond-sync` evaluation finishes first and the reply adds `alertIds`, `alerts` (`[{id, code}]`), `resolvedAlertIds` and `ruleCoverage`; without it `mode` is `async` and alerts are delivered by webhook. ### Through ovok - **Who can call it:** Submitter apps, and users whose access policy grants the capabilities. - **Capabilities, all required:** `signals_observations:create`. Project admins have every capability; client applications get no admin bypass. - If your access covers only some patients (anyone but project admins, manager or submitter apps, and anyone whose Patient access has no criteria), every patient the body names must be one you can update. A patient is named by its Signals id, or by its Medplum Patient id where Signals takes a `refId`; ovok asks Signals which patient a Signals id is. - Each reading counts its patient as monitored for billing.