A 1health platform service

Continuous signal, stored whole.

Patient Vault stores the person. VitalStream stores the signal — every biosensor reading kept as-is at full fidelity, normalized and sensed on read, keyed to the same patient record.

Free to start · BAA-covered in production · Full fidelity, never downsampled on ingest

The surface

Three verbs. One mental model.

Open a stream, feed it readings, sense what they mean. Learn three nouns — stream, observation, watch — and you've learned the API.

Open

Bind a feed to a patient

One call creates a stream against an existing Patient Vault patient and declares its analytes inline — no separate setup call before the first reading flows.

POST /v1/stream
Feed

Append a raw reading

The keystone call. Post a reading in its native unit; the response returns it stored, normalized, scored against the patient's own baseline, and checked against any watches — in one round trip.

POST /v1/stream/{streamId}/observation
Sense

Read the trend, set a watch

Pull a longitudinal trend against the N-of-1 baseline band, or declare a threshold that fires a webhook — and, if you want, a workflow — the moment it's breached.

GET /v1/stream/{streamId}/trend
The keystone call

Write and sense in one round trip.

Stored as-is. The raw reading lands in the record untouched — never downsampled, never averaged away on the way in.
Normalized on read. Unit harmonization and corrections (creatinine ratio, specific gravity) are a view over raw, returned inline — the stored value stays raw.
Scored against the patient. Each reading comes back with its delta from that patient's own rolling baseline, so "normal" means normal for them.
Watches evaluated. Any threshold you've set is checked on the same write — no polling, no second call.
POST /v1/stream/st_a71c9d4/observation
{
  "analyte": "testosterone",
  "value": 655,
  "observedAt": "2026-07-07T07:12:04Z"
}
──────────────
201
{
  "stored": "as-is",
  "normalized": { "value": 642 },
  "baselineDelta": { "z": 0.4, "inBand": true },
  "watchesEvaluated": [ { "fired": false } ]
}
Why not just store FHIR

FHIR is the export format. The stream is the record.

FHIR has no primitive for a live feed. A FHIR Observation is a discrete clinical event, so systems that treat FHIR as storage face a forced choice: downsample on ingest and lose the signal, or mint one heavyweight Observation per reading and lose queryability. That forced choice is why the industry downsamples — not because the data science wants it.

VitalStream takes the third path: store each reading as a lightweight time-series tuple keyed to the patient, derive everything else on read, and emit FHIR only when you export a window back to the Patient Vault record.

Ingest

Every reading stored whole, full fidelity. Downsampling on ingest is never on the roadmap — it's the anti-pattern the service exists to avoid.

Read

Normalization and rollups are views over raw, computed at read time and re-derivable. Change a rule, replay history — raw untouched.

Export

Collapse a window into one clinician-legible FHIR Observation in the patient's vault record. Export summarizes; it never dumps the firehose. In design

Composes with

One tile on the sidewalk.

VitalStream is built on the same canonical model as the rest of the platform, so it reaches for its siblings by default.

Built for

The workloads this tile is being built for.

Target scenarios shaping the design — the high-volume, continuous cases that break a discrete-event data model.

Continuous biomarker monitoring from wearable and at-home sensors N-of-1 baselines that track each patient against their own history High-frequency device feeds that would flood a FHIR-as-storage model
FAQ

Straight answers.

How is VitalStream different from storing FHIR Observations?

FHIR has no primitive for a continuous feed. Rather than downsample on ingest or mint one heavyweight Observation per reading, VitalStream stores each reading as a lightweight time-series tuple keyed to a Patient Vault patient, and emits FHIR only at the export boundary.

Do you downsample or aggregate readings on the way in?

Never on ingest — every reading is stored as-is at full fidelity. Aggregation exists only as a read-side rollup layer computed from raw, and raw is never discarded, so any rule can be changed and replayed against untouched history.

What do I have to learn to start?

Three nouns: stream, observation, watch. Open a stream with its analytes inline, feed it raw observations, and optionally set a watch that fires a webhook on a threshold. Baselines and trends come back inline, not as separate endpoints.

Bring your busiest sensor. Keep every reading.

Free to start. BAA-covered in production.