StandaloneAPI referenceObservations

Submit a reading by patient refId

Submit a reading by patient refId, through Ovok's Signals gateway.

Submit a reading by patient refId

MethodPath
POST/v1/signals/api/observation
  • Sandbox: available
  • Staging: available
  • Production: unknown

The patient is patientRefId in the body, else subject.reference (Patient/<refId>).

The body is a FHIR R4 Observation: code, value[x] (valueQuantity, valueInteger, valueString, valueBoolean, valueDateTime, valueCodeableConcept) 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. valueSampledData is judged by its latest sample and stored whole. A valueDateTime, on the reading or a component, is judged and aggregated as epoch ms (valueNumber) and listed as sent.

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.

Request

Body

Required. Schema V1ObservationByRefDto.

FieldTypeRequiredDescription
patientRefIdstringNo—
resourceTypestringNo—
identifierarray of objectNo—
identifier[].systemstringNo—
identifier[].valuestringNo—
refIdstringNo—
statusstringNo—
categoryarray of objectNoIts codings' codes are stored; a code the tenant names in historyCategories makes the reading history: stored, never judged.
noteobjectNoAccepted as a plain string or as FHIR's [{text, time}] Annotations, which the mapper flattens to newline-joined text. Deliberately untyped: typing it as a string would reject real readings ovok sends today.
codeobjectYes—
code.codingarray of objectNo—
code.textstringNo—
subjectobjectNo—
subject.referencestringNo—
subject.displaystringNo—
componentarray of objectNo—
component[].codeobjectYes—
component[].dataAbsentReasonobjectNo—
component[].valueQuantityobjectNo—
component[].valueSampledDataobjectNo—
component[].valueStringstringNo—
component[].valueIntegernumberNo—
component[].valueBooleanbooleanNo—
component[].valueDateTimestringNo—
component[].valueCodeableConceptobjectNo—
deviceobjectNoid (v1) or reference (FHIR) names the device.
dataAbsentReasonobjectNov1's string or FHIR's CodeableConcept; untyped so that neither is refused.
observedAtstringNo—
effectiveDateTimestringNo—
effectiveInstantstringNo—
effectivePeriodobjectNoOnly .start and .end are read, as in v1.
issuedstringNo—
valueQuantityobjectNo—
valueQuantity.valuenumberNo—
valueQuantity.unitstringNo—
valueQuantity.systemstringNo—
valueQuantity.codestringNo—
valueSampledDataobjectNo—
valueSampledData.originobjectNo—
valueSampledData.periodnumberNo—
valueSampledData.factornumberNo—
valueSampledData.lowerLimitnumberNo—
valueSampledData.upperLimitnumberNo—
valueSampledData.dimensionsnumberNo—
valueSampledData.datastringNoSpace-separated samples, oldest first; E, L and U are no sample.
valueStringstringNo—
valueIntegernumberNo—
valueBooleanbooleanNo—
valueDateTimestringNo—
valueCodeableConceptobjectNo—
valueCodeableConcept.codingarray of objectNo—
valueCodeableConcept.textstringNo—

Responses

StatusMeaning
200The reading as stored, plus the ingest outcome.
400The query carries a raw #, or more than 200 parameters.
401Your ovok access token, or your client id and secret, are missing or invalid.
403ovok refused the call: you lack a capability this route needs, or your session has no project, or your access covers only some patients and the call names none, or you can read a patient the call names but not update it. From Signals: Authenticated, but the client's role does not permit this, or it is not attached to the patient.
404A patient the call names is not one you can read. From Signals: No patient with that refId in this tenant.
409Your project has no Signals tenant of its own (SIGNALS_TENANT_NOT_OWN), or it is moving to another one. From Signals: A resend of a reading already stored (DUPLICATE_READING, data.observationId); nothing was stored or evaluated.
415The body is not JSON.
422A patient id is not 1 to 64 letters, digits, ., _, ~ or -. More than 100 patients are named. A patient is named by something other than a string. From Signals: The payload failed validation, or named no patient.
429Too many requests. Retry after the seconds in Retry-After.
500ovok hit an unexpected fault, such as your project having no Signals submitter.
502Signals answered with something ovok couldn't use, or refused ovok's own credential.
503Signals is unavailable. Retry after the seconds in Retry-After. From Signals: The evaluation backlog is full, or the readings could not be stored and judged (no database connection free in time, a lock timeout, a stalled database). Nothing was stored; resend after Retry-After (2 s).
504Signals did not answer in time.

Example

curl --request POST 'https://api.sandbox.ovok.com/v1/signals/api/observation' \
  --user "${OVOK_CLIENT_ID}:${OVOK_CLIENT_SECRET}" \
  --header 'Content-Type: application/json' \
  --data @body.json

Last updated on

On this page