# Measurements

Canonical page: https://docs.ovok.com/python-sdk/namespaces/measurements

`ovok.measurements` turns device and manual readings into FHIR Observations, saves them
safely, and reads the latest values back. Use it instead of hand-building Observations.

## Save a blood pressure reading [#save-a-blood-pressure-reading]

`save` builds the Observations for one reading and saves them in a transaction. Without
`patient_id`, the reading belongs to the signed-in user.

```python
from ovok_sdk import Ovok

ovok = Ovok("https://api.sandbox.ovok.com", "your-tenant")
ovok.auth.login(profile_type="Patient", email="patient@example.com", password="password")

result = ovok.measurements.save({
    "measurement": {
        "measurement_type_key": "blood-pressure",
        "systolic": 120,
        "diastolic": 80,
        "heart_rate": 64,
    },
})
```

`measurement_type_key` takes any `MeasurementTypeKey` value, such as `blood-glucose`,
`body-weight`, `ecg` or `urine-analysis`.

## Save device readings without duplicates [#save-device-readings-without-duplicates]

Pass `source_id` with the device's own reading ID. Saving the same reading again matches
the stored Observation instead of creating a second one, so retries are safe.

```python
ovok.measurements.save({
    "patient_id": "patient-id",
    "source_id": "monitor/reading-1",
    "effective_date_time": "2026-01-02T03:04:00Z",
    "measurement": {"measurement_type_key": "heart-rate", "heart_rate": 72},
})
```

To check the Observations before saving, call `build` with the same parameters, then
`save_observations`.

## Retry readings saved offline [#retry-readings-saved-offline]

When a signed-in save fails with a connection, rate-limit or server error, the result is
`{"status": "queued", ...}` and the reading stays in the client's storage. Flush the queue
once the network is back:

```python
summary = ovok.measurements.offline_queue.flush()
print(summary["saved"], summary["queued"])
```

Pass a persistent `storage` to `Ovok` to keep the queue across restarts.

## Read the latest values [#read-the-latest-values]

`latest` returns the newest Observation per code. `codes_for` turns measurement types into
the LOINC codes to filter on.

```python
from ovok_sdk import MeasurementTypeKey

codes = ovok.measurements.codes_for([MeasurementTypeKey.blood_pressure])
bundle = ovok.measurements.latest({"me": True, "codes": codes})
```

## API reference [#api-reference]

See [`ovok_sdk.resources.measurements`](/python-sdk/reference/resources/measurements)
and [`ovok_sdk.resources.measurement_builder`](/python-sdk/reference/resources/measurement_builder)
for every method, parameter and error.
