Skip to main content

What do Lab Data results look like in ROOK JSON and FHIR R4?

See the complete reference for a Lab Data result: every field of the ROOK JSON payload, the FHIR R4 bundle structure, and complete examples in both formats.

Written by Paola Malo Molina

This article is the complete reference for the Data Webhook payload that Lab Data sends for each processed document (data_structure: "lab_result_event").
​
Use it to build and test the handler that receives Lab Data results. For how to submit documents, see the Lab Data documentation.

Example data only Every identifier, laboratory name, and value in this article is fictional. Your payloads contain your own client_uuid, user_id, and document_id.


Example request

Submit the document from your backend as multipart/form-data, with the file and timezone fields. This example uses the Sandbox base URL (https://api.lab.rook-connect.review). In Production, use https://api.lab.rook-connect.com.

curl -X POST \   
"api.lab.rook- connect.review/client_uuid/$ROOK_CLIENT_UUID/user_id/$USER_ID" \
-u "$ROOK_CLIENT_UUID:$ROOK_SECRET_KEY" \
-F "file=@/path/to/laboratory_result.pdf" \
-F "timezone=-05:00"

The example reads your client_uuid and secret_key from the ROOK_CLIENT_UUID and ROOK_SECRET_KEY environment variables, so the credentials stay out of your source code and shell history.
​
The -u option builds the Authorization: Basic header from your client_uuid and secret_key. Never submit documents from a web browser or a mobile application, where the credentials would be exposed to end users.

If the request is valid, the endpoint returns 200 OK:

{

"document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",

"status": "received"

}

Store the document_id. The same value arrives in the Data Webhook as laboratory_data.metadata.document_id_string.

Receiving the result

Lab Data results arrive at your Data Webhook with the same HMAC validation and retries as the rest of your Data Webhooks. Validate the X-ROOK-HASH header, respond with a 2xx status as soon as you receive the payload, and then process it asynchronously.
​

The result arrives in one of two formats, depending on how Lab Data is activated for your organization:

ROOK JSON (default)

FHIR R4 (requires Clinical Ready)

Structure

ROOK normalized JSON

HL7 FHIR R4 Bundle of type collection

laboratory_data contains

metadata, panels_array, rejected_biomarkers_array

metadata, clinical_ready

Rejected biomarkers

rejected_biomarkers_array

Observation resources with status: "cancelled"

*FHIR R4 output for Lab Data requires the Clinical Ready add-on. Activate it from your ROOK Portal or through the ROOK Support team or your account manager.
​
Both formats share the same top-level fields:

Field

Type

Description

client_uuid

string

Your ROOK client identifier.

user_id

string

The user_id you sent in the request path.

version

integer

Version of the event envelope. Current value: 2.

document_version

integer

Version of the lab_result_event structure. Current value: 1.

data_structure

string

Always lab_result_event. Use it to route Lab Data results in your webhook handler.

laboratory_data

object

The processed laboratory result. Its content depends on the format.

ROOK JSON reference

`laboratory_data.metadata`

Field

Type

Description

datetime_string

string

Sample collection date and time as printed on the document, in ISO 8601 format. Includes the UTC offset when it is available, following the time zone rules described in Integrate Lab Data.

document_id_string

string

The document_id returned when the document was submitted.

user_id_string

string

The user_id associated with the document.

performing_lab_string

string or null

Name and location of the laboratory that performed the analysis, when it appears in the document.

sources_of_data_array

array of strings

Laboratory providers identified in the document.

is_fasting_bool

boolean or null

Whether the sample was taken while fasting, when the document states it.

`panels_array`

One entry per supported panel identified in the document. A single document can contain several panels.

Field

Type

Description

panel_name_string

string

Name of the panel, for example Complete Blood Count.

panel_code_string

string

Short panel code: CBC, CMP, LIPID, THYROID, or HBA1C.

panel_loinc_code_string

string

LOINC code of the panel.

biomarkers_array

array

Biomarkers of this panel that passed every validation.

`biomakers_array`

Field

Type

Description

biomarker_name_string

string

Name of the biomarker.

loinc_code_string

string

LOINC code of the biomarker. See Supported panels and biomarkers.

value_float

number

Result value, expressed in the canonical unit.

unit_string

string

Unit of value_float. Always equal to canonical_unit_string.

canonical_unit_string

string

Canonical unit of the biomarker.

reference_range_low_float

number or null

Lower limit of the reference range printed on the document, converted to the canonical unit.

reference_range_high_float

number or null

Upper limit of the reference range printed on the document, converted to the canonical unit.

reference_range_unit_string

string or null

Unit of the reference range.

status_string

string

Interpretation of the result: normal, low, high, critical_low, or critical_high.

confidence_float

number

Extraction confidence, from 0.0 to 1.0. Biomarkers below the minimum confidence required by ROOK are moved to rejected_biomarkers_array.

plausibility_flag

boolean

true when the value is physiologically possible but unusual, or inconsistent with a related biomarker of the same document. ROOK recommends reviewing these values before using them in clinical decisions.

value_corrected_bool

boolean

Present only when ROOK adjusted value_float during validation to resolve a unit conversion inconsistency. Always true when present.

original_value_float

number

Present only together with value_corrected_bool. The value before the adjustment, kept for traceability.

`rejected_biomarkers_array`
​

Biomarkers found in the document that did not pass validation. The array is always present, and it is empty when every biomarker passed.

Field

Type

Description

biomarker_name_string

string

Name of the biomarker as it appears in the document.

loinc_code_string

string or null

LOINC code, when it could be identified.

extracted_value_string

string

Value as extracted from the document.

extracted_unit_string

string

Unit as extracted from the document.

reason_string

string

Reason for the rejection. See the following table.

confidence_float

number

Extraction confidence at the time of the rejection.

reason_string

Meaning

low_confidence

The value could not be extracted with the minimum confidence required by ROOK, or its structure was not valid.

unsupported_biomarker

The biomarker is not part of the supported biomarkers.

unknown_unit

The unit printed on the document could not be converted to the canonical unit.

implausible_value

The value falls outside physiological limits.

not_mapped

The result could not be mapped to a LOINC code, for example qualitative results or non-standard markers.

Example ROOK JSON payload
​
The following document contains two panels (CBC and CMP) with accepted biomarkers, and one biomarker in rejected_biomarkers_array.
​

{

"client_uuid": "c2f4ce3b-8e6d-4b5f-9a3e-1d2c3b4a5f6e",

"user_id": "user_1234",

"version": 2,

"document_version": 1,

"data_structure": "lab_result_event",

"laboratory_data": {

"metadata": {

"datetime_string": "2026-03-15T08:30:00-05:00",

"performing_lab_string": "Example Clinical Laboratory - North Branch",

"is_fasting_bool": true,

"user_id_string": "user_1234",

"document_id_string": "3fa85f64-5717-4562-b3fc-2c963f66afa6",

"sources_of_data_array": ["Example Clinical Laboratory - North Branch"]

},

"panels_array": [

{

"panel_name_string": "Complete Blood Count",

"panel_code_string": "CBC",

"panel_loinc_code_string": "58410-2",

"biomarkers_array": [

{

"biomarker_name_string": "Hemoglobin",

"loinc_code_string": "718-7",

"value_float": 14.5,

"unit_string": "g/dL",

"canonical_unit_string": "g/dL",

"reference_range_low_float": 12.0,

"reference_range_high_float": 17.5,

"reference_range_unit_string": "g/dL",

"status_string": "normal",

"confidence_float": 0.98,

"plausibility_flag": false

},

{

"biomarker_name_string": "White Blood Cell Count",

"loinc_code_string": "6690-2",

"value_float": 5.05,

"unit_string": "10^3/uL",

"canonical_unit_string": "10^3/uL",

"reference_range_low_float": 4.5,

"reference_range_high_float": 11.0,

"reference_range_unit_string": "10^3/uL",

"status_string": "normal",

"confidence_float": 0.97,

"plausibility_flag": false

}

]

},

{

"panel_name_string": "Comprehensive Metabolic Panel",

"panel_code_string": "CMP",

"panel_loinc_code_string": "24323-8",

"biomarkers_array": [

{

"biomarker_name_string": "Blood Urea Nitrogen",

"loinc_code_string": "3094-0",

"value_float": 15.7,

"unit_string": "mg/dL",

"canonical_unit_string": "mg/dL",

"reference_range_low_float": 7.0,

"reference_range_high_float": 20.0,

"reference_range_unit_string": "mg/dL",

"status_string": "normal",

"confidence_float": 0.95,

"plausibility_flag": false,

"value_corrected_bool": true,

"original_value_float": 43.98

}

]

}

],

"rejected_biomarkers_array": [

{

"biomarker_name_string": "Vitamin B12",

"loinc_code_string": "2132-9",

"extracted_value_string": "250.0",

"extracted_unit_string": "pg/mL",

"reason_string": "unsupported_biomarker",

"confidence_float": 0.93

}

]

}

}


​What to notice in this example

  • metadata carries the sample collection date and time with its UTC offset, the performing laboratory, and the document_id_string returned by the request.
    ​

  • panels_array groups accepted biomarkers by panel. Each biomarker has its LOINC code and its value in the canonical unit.
    ​

  • Blood Urea Nitrogen shows value_corrected_bool: true: ROOK adjusted the value during validation to resolve a unit conversion inconsistency, and original_value_float keeps the value before the adjustment. These fields are present only when an adjustment happens.
    ​

  • Vitamin B12 appears in rejected_biomarkers_array with unsupported_biomarker, because it is not one of the supported biomarkers.

FHIR R4 reference

In FHIR R4 mode, laboratory_data keeps metadata and replaces panels_array and rejected_biomarkers_array with clinical_ready, an HL7 FHIR R4 Bundle of type collection.

Resource

Cardinality

Content

Patient

1

The user_id as identifier, with system urn:rook:user-id.

Practitioner

1

The ordering provider of the laboratory study. Referenced from each DiagnosticReport.

Organization

1

The laboratory that performed the analysis, from performing_lab_string.

Observation (status: "final")

One per accepted biomarker

LOINC code, value, unit, reference range, and interpretation.

DiagnosticReport

One per panel

Panel LOINC code, sample collection date and time, and references to the panel's Observation resources.

Observation (status: "cancelled")

One per rejected biomarker

Biomarker name, with the rejection reason and extracted value in note.

Each accepted biomarker maps to an Observation as follows:

ROOK JSON field

FHIR R4 field

loinc_code_string

code.coding[0].code (system http://loinc.org)

biomarker_name_string

code.coding[0].display and code.text

value_float

valueQuantity.value

canonical_unit_string

valueQuantity.unit, and valueQuantity.code in UCUM notation (for example, 10^3/uL becomes 10*3/uL)

reference_range_low_float / reference_range_high_float

referenceRange[0].low / referenceRange[0].high

status_string

interpretation[0].coding[0]: N (normal), L (low), H (high), LL (critical low), HH (critical high)

confidence_float, plausibility_flag, value_corrected_bool, and original_value_float are not included in the FHIR R4 output.

Example FHIR R4 payload

This example is an excerpt: it shows the shared resources, one accepted biomarker with its DiagnosticReport, and one rejected biomarker. A real bundle contains one Observation per accepted biomarker and one DiagnosticReport per panel.

{

"client_uuid": "c2f4ce3b-8e6d-4b5f-9a3e-1d2c3b4a5f6e",

"user_id": "user_1234",

"version": 2,

"document_version": 1,

"data_structure": "lab_result_event",

"laboratory_data": {

"metadata": {

"datetime_string": "2026-03-15T08:30:00-05:00",

"performing_lab_string": "Example Clinical Laboratory - North Branch",

"is_fasting_bool": true,

"user_id_string": "user_1234",

"document_id_string": "3fa85f64-5717-4562-b3fc-2c963f66afa6",

"sources_of_data_array": ["Example Clinical Laboratory - North Branch"]

},

"clinical_ready": {

"resourceType": "Bundle",

"id": "d720e9b8-e108-4f26-b784-30b1382e7be8",

"type": "collection",

"timestamp": "2026-03-15T14:02:11Z",

"entry": [

{

"fullUrl": "urn:uuid:2680a059-6f3c-4c1e-9d0a-5b7e1f3c9a11",

"resource": {

"resourceType": "Patient",

"id": "2680a059-6f3c-4c1e-9d0a-5b7e1f3c9a11",

"identifier": [

{ "system": "urn:rook:user-id", "value": "user_1234" }

]

}

},

{

"fullUrl": "urn:uuid:7b1d2c44-0a9e-4f7b-8c61-2e5d9f0a3b22",

"resource": {

"resourceType": "Practitioner",

"id": "7b1d2c44-0a9e-4f7b-8c61-2e5d9f0a3b22"

}

},

{

"fullUrl": "urn:uuid:c93e5a10-4d2b-4b8f-a7e6-9f1c0d2e4b33",

"resource": {

"resourceType": "Organization",

"id": "c93e5a10-4d2b-4b8f-a7e6-9f1c0d2e4b33",

"name": "Example Clinical Laboratory - North Branch"

}

},

{

"fullUrl": "urn:uuid:1bb895f4-8e2a-4d6c-b3f1-7a9e0c5d2f44",

"resource": {

"resourceType": "Observation",

"id": "1bb895f4-8e2a-4d6c-b3f1-7a9e0c5d2f44",

"status": "final",

"code": {

"coding": [

{ "system": "http://loinc.org", "code": "6690-2", "display": "White Blood Cell Count" }

],

"text": "White Blood Cell Count"

},

"subject": { "reference": "urn:uuid:2680a059-6f3c-4c1e-9d0a-5b7e1f3c9a11" },

"valueQuantity": {

"value": 5.05,

"unit": "10^3/uL",

"system": "http://unitsofmeasure.org",

"code": "10*3/uL"

},

"referenceRange": [

{

"low": { "value": 4.5, "unit": "10^3/uL", "system": "http://unitsofmeasure.org", "code": "10*3/uL" },

"high": { "value": 11.0, "unit": "10^3/uL", "system": "http://unitsofmeasure.org", "code": "10*3/uL" }

}

],

"interpretation": [

{

"coding": [

{

"system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",

"code": "N",

"display": "Normal"

}

]

}

]

}

},

{

"fullUrl": "urn:uuid:5e2f8a91-3c7d-4e0b-9a14-6d8b2c1f0e55",

"resource": {

"resourceType": "DiagnosticReport",

"id": "5e2f8a91-3c7d-4e0b-9a14-6d8b2c1f0e55",

"status": "final",

"code": {

"coding": [

{ "system": "http://loinc.org", "code": "58410-2", "display": "Complete Blood Count" },

{ "system": "urn:rook:panel-code", "code": "CBC", "display": "Complete Blood Count" }

],

"text": "Complete Blood Count"

},

"subject": { "reference": "urn:uuid:2680a059-6f3c-4c1e-9d0a-5b7e1f3c9a11" },

"effectiveDateTime": "2026-03-15T08:30:00-05:00",

"performer": [

{ "reference": "urn:uuid:7b1d2c44-0a9e-4f7b-8c61-2e5d9f0a3b22" },

{ "reference": "urn:uuid:c93e5a10-4d2b-4b8f-a7e6-9f1c0d2e4b33" }

],

"result": [

{ "reference": "urn:uuid:1bb895f4-8e2a-4d6c-b3f1-7a9e0c5d2f44" }

]

}

},

{

"fullUrl": "urn:uuid:35489c90-7b1e-4a2d-8f3c-0e9d6a5b4c66",

"resource": {

"resourceType": "Observation",

"id": "35489c90-7b1e-4a2d-8f3c-0e9d6a5b4c66",

"status": "cancelled",

"code": { "text": "Vitamin B12" },

"subject": { "reference": "urn:uuid:2680a059-6f3c-4c1e-9d0a-5b7e1f3c9a11" },

"note": [

{ "text": "Rejected — reason: unsupported_biomarker. Extracted value: 250.0" }

]

}

}

]

}

}

}

Two timestamps appear in the bundle: timestamp is the time ROOK generated the bundle, and DiagnosticReport.effectiveDateTime is the sample collection date and time.

Route by data_structure Lab Dat FHIR R4 results arrive with data_structure: "lab_result_event" and the bundle is at laboratory_data.clinical_ready. The Clinical Ready add-on uses a different structure (data_structure: "clinical_ready") for wearable summaries. Route both by data_structure.

Did this answer your question?