WearMetrics is the single shape every adapter writes into. Downstream
layers (synheart-session, synheart-core, the runtime ingest queue)
read this shape; they do not consume vendor-specific JSON.
WearMetrics
Top-level fields
| Field | Type | Notes |
|---|---|---|
timestamp | ISO-8601 UTC string | Time the measurement applies to (sample time, not emit time). Always UTC. |
device_id | string | Stable identifier for this physical device. Format is vendor-shaped (e.g. "applewatch_1234", "whoop_<uuid>", BLE MAC for HRM). |
source | string | Lowercase snake_case adapter id. Stable across versions of the same adapter. |
metrics | object | Keyed by metric short-name (see below). Values may be null when the adapter knows the metric is not available; missing keys mean “not produced by this sample”. |
meta | object | Free-form per-sample metadata. Stable keys are documented below; adapters may add vendor-specific keys. |
rr_ms | array of doubles | absent | Inter-beat intervals in milliseconds when the source provides them. Absent when not available. |
metrics keys
Maps from the MetricType enum:
| Key | Type | Unit | Source |
|---|---|---|---|
hr | number | bpm | HR sample. |
hrv_rmssd | number | ms | RMSSD over the adapter’s window. |
hrv_sdnn | number | ms | SDNN over the adapter’s window. |
steps | number | count | Period total (since the previous sample, or per-day depending on adapter). |
calories | number | kcal | Active energy. |
distance | number | km | Total distance over the period. |
stress | number | unitless | Vendor-specific score (e.g. Garmin 0–100); adapters do not normalise this across vendors. |
meta keys (stable)
| Key | Type | Notes |
|---|---|---|
battery | number 0–1 | Device battery level. |
synced | bool | Whether this sample arrived via real-time path (true) or backlog/sync (false). |
connection_state; WHOOP adds recovery_score, strain, etc. — refer to the per-vendor models.
rr_ms semantics
When present:
- Each value is one inter-beat interval in milliseconds.
- Order is the order observed by the device (chronological).
- The list is per sample, not cumulative — multiple samples at the same
timestampcan share anrr_mspayload via the meta field. - Range gates apply downstream: the runtime’s RR push rejects values outside
[200, 6000].
Adapter source IDs
The top-levelsource field carries the adapter id — typically the bare vendor/source name. More specific flavor information (cloud vs BLE, etc.) lives in meta.source_type.
source value | Adapter | meta.source_type flavor |
|---|---|---|
"apple_healthkit" | Apple HealthKit | — |
"health_connect" | Android Health Connect | — |
"ble_hrm" | BLE Heart Rate Profile | — |
"whoop" | WHOOP | "whoop_cloud" for OAuth + webhooks; WHOOP via BLE Broadcast HR uses source = "ble_hrm" |
"garmin" | Garmin via Connect API | "garmin_cloud" |
"garmin_sdk" | Garmin Health SDK (RTS, license-gated) | — |
"fitbit" | Fitbit | (planned) |
"oura" | Oura | proxied through HealthKit / Health Connect today |
source and meta.source_type values.
When new adapters land, they take new stable strings. Existing strings do not change meaning.
Compatibility rules
The shape is unversioned. Compatibility rules:- Producers MAY add new metric keys, new meta keys, and new
sourcevalues. - Producers MUST NOT remove or rename existing keys.
- Consumers MUST tolerate unknown metric keys and unknown
sourcevalues. - A future change to the top-level shape would be a breaking change; the SDK would expose both producers in parallel during migration.
Vendor → schema mapping (informal)
This table is informational only. Each adapter is the authoritative source for its mapping; this is a reading aid.| Vendor field | Maps to | Notes |
|---|---|---|
HealthKit HKQuantityTypeIdentifierHeartRate | metrics.hr | Average per query window. |
| HealthKit RR samples | rr_ms | Workout-mode only on most Apple Watch models. |
Health Connect HeartRateRecord | metrics.hr | One sample per record. |
WHOOP webhook recovery_score | meta.recovery_score | Not part of the canonical metric set. |
Garmin Connect restingHeartRate | metrics.hr | Daily resting HR baseline. |
| BLE GATT 0x180D HR characteristic | metrics.hr | Plus optional RR field → rr_ms. |
Apple XML HKQuantityTypeIdentifierHeartRateVariabilitySDNN | metrics.hrv_sdnn | Backfill only. |
How downstream uses this
synheart-session’s WearBiosignalProvider wraps streamHR / streamHRV and converts each WearMetrics into a BiosignalSample:
synheart-core forwards the same shape into the runtime via pushHr / pushRr after consent gating.
Related
- Wear Overview — full SDK surface.
- Adapters — per-vendor flow.
- Errors — failure modes.