For the complete documentation index, see llms.txt. This page is also available as Markdown.

Scans (DEXA)

DXA body-composition and bone-density scans go through the same upload endpoint as lab reports. This page covers what is different about the results.

Terra ingests DXA/DEXA scans — body composition and bone densitometry — through the same POST /v2/reports endpoint as clinical lab reports. There is no separate endpoint and no parameter to declare the type: Terra classifies the file on upload and tells you what it decided in report_type.

Everything else on this page describes the one thing that genuinely differs: a scan measures the same quantity at many places on the body, so a result is identified by a measure and a site.

Telling the two apart

Every session and every lab_report.completed webhook carries report_type:

Value
What it is

lab

Clinical laboratory report. Results are scoped by biomarker.specimen.

dexa

DXA body-composition or bone-density scan. Results are scoped by biomarker.region.

Branch on it before you read results. A session fetched over REST may also read unspecified while it is still being classified; a delivered webhook never does.

To list only one kind, pass report_type=lab or report_type=dexa to GET /v2/reports.

Site-scoped results

On a lab report, a biomarker appears once. biomarker.key identifies the result, and that is the end of it.

On a scan it does not. A total-body scan reports fat mass for the head, each arm, each leg, the trunk, android, gynoid, and the whole body — one row each, same biomarker.key every time. What separates them is biomarker.region.

The identity of a scan result is the pair (biomarker.key, biomarker.region). Neither half is unique on its own.

Two fields carry the site:

  • biomarker.region — the canonical key, from the closed vocabulary below. Use this for storage, joins and comparison across reports and vendors.

  • source.region_name — the site exactly as the report printed it, in its own language ("L1-L4", "Bras gauche"). Use this for display. It is present whenever the report showed a site, including when the printed label matched no canonical key — so a site Terra does not recognise is still visible to you rather than silently lost.

Serial scans in one report

Many scan reports print a trend table: the current scan alongside previous ones. Those prior rows come through as ordinary results, distinguished only by source.collection_date, which can be years earlier than the report-level report_date.

If you want only the current scan, filter to the latest collection_date rather than assuming one report means one point in time.

Region vocabulary

biomarker.region is drawn from this closed set. Terra discards anything outside it before storage, so you will never see a value not on this list.

Body composition (total-body scans)

head arms arm_left arm_right legs leg_left leg_right trunk trunk_left trunk_right android gynoid vat ribs ribs_left ribs_right pelvis spine spine_thoracic spine_lumbar subtotal total total_left total_right whole_body

Lumbar spine (bone density)

l1 l2 l3 l4 l1_l2 l1_l3 l1_l4 l2_l3 l2_l4 l3_l4

Hip / femur (bone density)

femur_neck femur_neck_left femur_neck_right femur_trochanter femur_trochanter_left femur_trochanter_right femur_intertrochanter femur_intertrochanter_left femur_intertrochanter_right femur_wards femur_wards_left femur_wards_right femur_total femur_total_left femur_total_right femur_dual_total

Forearm (bone density)

radius_ultradistal radius_ultradistal_left radius_ultradistal_right radius_mid radius_mid_left radius_mid_right radius_33 radius_33_left radius_33_right forearm_total forearm_total_left forearm_total_right

Laterality is a suffix, and the vocabulary is ordered anatomy-first, so a prefix match is a valid family query: femur_neck matches femur_neck, femur_neck_left and femur_neck_right.

Scores, negative values and units

T-scores and Z-scores are ordinary numeric results. Two things to expect:

  • They are routinely negative. A T-score of -2.1 is a normal reading, not an error. Do not treat a negative as a sentinel.

  • Their unit is {SD} (standard deviations) in measurement.ucum_code. Some reports print no unit at all for a score.

Mass values come back in the units the report printed — grams on one vendor, kilograms on another. Read measurement.ucum_code rather than assuming.

LOINC on scans

LOINC's DXA terms are pre-coordinated: the site is baked into the term, so bone mineral density at the lumbar spine and at the femoral neck are different LOINC codes for what Terra calls the same biomarker.key.

That means loinc_code on a scan is a property of the (measure, site) pair. Read it off each result. Caching one code against a biomarker.key mislabels every site but the first. Where a site has no LOINC term of its own, the field is omitted rather than filled with a code for a different site.

Coverage is partial. Bone density and the scores are coded at the standard sites; per-site body fat percentage and the mass measures (fat mass, lean mass, bone mineral content) have no LOINC term and omit the field. An absent loinc_code is not a matching failure — biomarker.key is the signal for that, and it is null when nothing matched.

If a file is neither

A file Terra cannot recognise as a lab report or a scan fails permanently with error code unsupported_report_type and retriable: false. Re-uploading the same file fails the same way; it is not a transient error.

Panels

On a scan, panels[] carries the scan's own sections — "AP Spine", "Total Body" — in the same shape a lab report uses for "CBC". Results reference them by biomarker.panel_id exactly as before.

Last updated

Was this helpful?