Headless API

Connect once. Stop writing a parser per vendor.

The same harmonisation layer the clinical product runs on, available on its own. Connect once, read one schema, and stop writing a parser per vendor. Access is granted per integration. There is no self-serve signup or public sandbox yet.

8

connected data sources

Apple Health, Oura, Whoop, Garmin, Fitbit, Polar, Google Fit, Strava

87

harmonised measures

Vitals, sleep, activity, body, cycle, glucose and 37 lab analytes

UCUM

units on every value

One dictionary, so two devices reporting the same thing stop being two things

Ingestion

From device to one schema.

  1. 01

    Connect

    OAuth per provider, or a signed device token for Apple Health.

    Oura · Whoop · Garmin · Fitbit · Polar · Google Fit · Strava · Apple Health

  2. 02

    Receive

    Signed webhooks for push providers, scheduled reconciliation for the rest.

    Signature verified · replay is a no-op

  3. 03

    Archive

    The raw payload is written to object storage before anything parses it.

    Server-side encryption with KMS

  4. 04

    Normalise

    Each reading resolves to one of 84 measures and a UCUM unit.

    Unknown unit rejected, never guessed

  5. 05

    Derive

    Daily features, then medians and spreads over each person's own window.

    Workers drain every 15 minutes

  6. 06

    Serve

    One schema out, whether to the roster or to your own systems.

    Scoped per care relationship

What harmonised actually means

Most integrations fail on the details rather than the transport. These are the four that cost the most to discover late.

One name per measurement

Heart rate variability measured as SDNN and as RMSSD are two different measurements, and stay two entries rather than being averaged into one number that means neither.

One unit per value

Every value carries a UCUM unit. Where a unit cannot be established the reading is rejected rather than guessed, because a silently wrong unit is worse than a gap.

Provenance on every row

Which device, which app, which version of the normaliser. Two sources reporting the same instant both survive; choosing between them is a decision you can see rather than one made during import.

Gaps stay gaps

Missing days are reported as missing. Nothing is interpolated to make a chart look continuous.

What a reading looks like

Every row is the same shape whichever device it came from, and carries enough provenance to answer where a number came from a year later.

Apple HealthOuraWhoopGarminFitbitPolarGoogle FitStrava

Additional sources are added per integration. Ask about anything not listed.

{
  "person_id": "9f2c…",
  "concept":   "hrv.sdnn",
  "value":     58.4,
  "unit":      "ms",
  "ts":        "2026-09-15T05:12:00Z",
  "local_date":"2026-09-15",
  "source":    { "provider": "oura", "device": "ring_gen3" },
  "quality":   { "coverage": 0.94 }
}

Before you ask, three answers

Where does the data sit?
Raw payloads are stored immutably so a normalisation change can be replayed over history rather than losing it. Region is set per deployment.
Is it certified?
Not yet. We are pre-certification and will tell you exactly where we are on the call rather than showing a badge we have not earned.
Can we self-serve?
Not today. Access is granted per integration, which means a real conversation about your data before anything is wired up.
Talk to us about access