How to Combine Wearable Vitals and PROMIS-29 into a Single FHIR Bundle

Remote monitoring programs collect two streams that eventually have to sit in the same clinical view. The wearable stream carries steps, resting heart rate, sleep summaries, and sometimes SpO2. The PROMs stream carries the PROMIS-29 profile: seven domains, four items each, plus a pain intensity item. The clean way to hand both to a downstream system is one FHIR Bundle per patient per reporting interval. The pattern is not complicated, but each step has a decision that shapes what the analytics layer sees.

Step 1: Fix the Reporting Interval

A weekly Bundle is the common choice for chronic disease RPM. Pick the interval before writing any code, because it drives the Encounter reference, the timestamp semantics, and the analytics grain. If the program mixes intervals (daily vitals, weekly PROMIS-29), the Bundle interval matches the slower stream and the daily vitals get aggregated to weekly summaries inside the Bundle.

Step 2: Model Wearable Data as Observations

Each wearable metric is one Observation. Use the LOINC code (55423-8 for steps, 8867-4 for heart rate, and so on) and UCUM units per the vital signs profile. The device reference points at a Device resource for the specific wearable, and the effectivePeriod covers the interval the reading represents. Sleep summaries become a single Observation with a component per stage, not one Observation per stage. That decision saves the analytics team a self-join.

Step 3: Emit PROMIS-29 as a QuestionnaireResponse Plus Extracted Observations

The QuestionnaireResponse carries the raw item-level answers. The extraction step produces the seven T-scored domain Observations plus the pain intensity Observation. For the coding side, PROMs typically bind LOINC codes (the PROMIS-29 domain scores each have LOINC bindings published by Regenstrief); systems like Formbox rely on a terminology server such as Termbox to resolve these at populate time, which keeps the emitted Observations consistent across sites without hardcoding LOINC in application logic.

Both the QuestionnaireResponse and the extracted Observations go into the Bundle. Keeping the raw response lets a later audit or an updated scoring rule recompute the T-scores without re-collecting the survey.

TWO STREAMS → ONE WEEKLY BUNDLE

WEARABLE STREAM

Steps · Heart rate · SpO2 LOINC 55423-8 · 8867-4 · UCUM units

Sleep stages one Observation · one component per stage

Device reference Device resource per wearable effectivePeriod covers the reading

PROMIS-29 STREAM

QuestionnaireResponse raw item-level answers · 7 domains · 4 items

SDC extraction 7 T-scored domain Observations

Pain intensity extra Observation, LOINC-bound valueQuantity 0–10

TRANSACTION BUNDLE type: transaction · one Encounter Patient · Encounter · Devices · wearable Observations · QuestionnaireResponse · extracted Observations — all in one POST

VALIDATE

US Core validator · category · device ref · authored ts

WEEKLY INTERVAL · 1 BUNDLE PER PATIENT

Step 4: Assemble the Bundle as a Transaction

Set type: transaction. Include one Patient reference (either as a resource or as a resolvable reference), one Encounter that represents the reporting interval, one Device per wearable, all wearable Observations, the QuestionnaireResponse, and all extracted Observations. Give each entry a request with method: POST and a url matching the resource type. Downstream servers treat the whole payload atomically, which is the property that saves the analytics view from partial states.

Step 5: Validate Before You Ship

Run the Bundle through a validator that knows US Core or the profile pack the receiving system requires. The recurring failure modes are missing device references on wearable Observations, missing category on Observations that carry vital-signs codes, and QuestionnaireResponse entries missing the authored timestamp. A Bundle-level validation pass catches all three in one round.

For a quick sanity check on the PROMIS-29 side without wiring the full runtime, drop the Questionnaire into form-builder.aidbox.app, answer the items in the browser, and inspect the raw QuestionnaireResponse and the extracted Observations before pointing production traffic at the pipeline.

For adjacent walkthroughs, QuestionnaireResponse vs custom JSON for form data capture covers the schema choice for the PROMs side, and FHIR SDC form builders 2026 reference guide covers the surrounding SDC tooling.

For the broader Bundle-assembly context, the FHIR forms and SDC reference is where the adjacent walkthroughs sit.

A single Bundle per interval is not the fanciest pattern, but it is the one that keeps the downstream analytics honest. Once the schema is settled, the pipeline stops being interesting, which is exactly what you want in production.