Lab Report API Documentation

Overview

The Blood Biomarkers API provides an advanced medical report parsing service that converts unstructured lab reports (PDFs, images) into structured, actionable biomarker data. Using state-of-the-art AI models, the API extracts, standardizes, and delivers comprehensive biomarker information with high accuracy.

Key Features

  • Multi-format Support: Accepts PDF, PNG, and JPEG files

  • Batch Processing: Upload multiple files in a single request

  • Real-time Status Tracking: Monitor processing progress through status updates

  • Standardized Output: Biomarkers mapped to standard enums with UCUM-compliant units

  • Flexible Delivery: Asynchronous webhook delivery or synchronous response

  • Reference Tracking: Associate uploads with your internal user/patient IDs

Quick Start

Basic Upload Request

curl --location 'https://api.tryterra.co/v2/lab-reports' \
--header 'dev-id: YOUR_DEV_ID' \
--header 'x-api-key: YOUR_API_KEY' \
--form 'files=@"/path/to/bloodtest.pdf"' \
--form 'files=@"/path/to/labresult.jpg"'

With Reference ID

curl --location 'https://api.tryterra.co/v2/lab-reports?reference_id=patient_123' \
--header 'dev-id: YOUR_DEV_ID' \
--header 'x-api-key: YOUR_API_KEY' \
--form 'files=@"/path/to/report.pdf"'

API Reference

Upload Endpoint

POST https://api.tryterra.co/v2/lab-reports

Alternative: POST /v2/reports/upload (legacy)

Headers

Name
Type
Required
Description

dev-id

string

Your Terra developer ID

x-api-key

string

Your Terra API key

Content-Type

string

Must be multipart/form-data

Query Parameters

Name
Type
Default
Description

reference_id

string

null

Your internal identifier for the patient/user. This ID will be included in the webhook payload for easy reconciliation

Request Body

Field
Type
Required
Description

files

file[]

One or more files to upload. Supported formats: PDF, PNG, JPEG. Maximum 10 files per request

Response Codes

Code
Description

202 Accepted

Upload successful, processing started asynchronously

200 OK

Upload and processing successful (sync mode only)

400 Bad Request

Invalid request (missing files, wrong format)

500 Internal Server Error

Processing error

Success Response (202/200)

{
    "upload_id": "550e8400-e29b-41d4-a716-446655440000",
    "files": [
        {"file_name": "blood_test_2024.pdf"},
        {"file_name": "lab_results.jpg"}
    ]
}

Error Response (400/500)

{
    "type": "about:blank",
    "title": "Invalid File Format",
    "status": 400,
    "detail": "File format must be PDF, PNG, or JPEG.",
    "instance": "/lab-reports"
}

Processing Pipeline

Status Progression

The system tracks detailed status updates throughout processing:

RECEIVED → QUEUED → DEQUEUED → PROCESSING → PROCESSED →
STANDARDIZING → STANDARDIZED → QUEUED (delivery) → SENT → COMPLETED
Status
Description
Terminal

received

Files uploaded and stored

No

queued

Task queued for processing

No

dequeued

Processing started

No

processing

Extracting biomarker data from files

No

processed

Extraction complete

No

standardizing

Mapping to standard biomarker enums and units

No

standardized

Standardization complete

No

sent

Results delivered to webhook

Yes ✅

failed

Error occurred during processing

Yes ❌

Status updates above are only used internally in https://dashboard.tryterra.co/dashboard/lab-reports at the moment.

Webhook Payload

Structure

The parsed results are delivered to your configured webhook endpoint:

{
    "upload_id": "550e8400-e29b-41d4-a716-446655440000",
    "reference_id": "patient_123",  // If provided in upload
    "data": [{
        "date": "2024-03-15",
        "time": "09:30",
        "results": [
            {
                "original_name": "Haemoglobin",
                "display_name": "Hemoglobin",
                "biomarker": "hemoglobin_blood",
                "type": "blood",
                "value": 14.2,
                "value_bound": null,
                "display_units": "g/dL",
                "unit_code": "g/dL",
                "units": {
                    "id": 123,
                    "name": "grams_per_deciliter",
                    "numerator": "g",
                    "denominator": "dL",
                    "exponent": null
                },
                "reference_ranges": [
                    {
                        "reference_lower_bound": 13.5,
                        "reference_upper_bound": 17.5,
                        "classification": "normal",
                        "context": {
                            "sex": "male",
                            "age_lower_bound": 18,
                            "age_upper_bound": null,
                            "modifiers": []
                        }
                    }
                ],
                "notes": null
            }
        ]
    }]
}

Field Specifications

Top Level Fields

Field
Type
Description

upload_id

string

Unique identifier for this upload

reference_id

string?

Your reference ID if provided

data

array

Array of report data (usually one item)

LabData Object

Field
Type
Description

date

string?

ISO date (YYYY-MM-DD) when specimen was collected

time

string?

Time in HH:MM format (24-hour)

results

Result[]

Array of biomarker measurements

Result Object

Field
Type
Description

original_name

string?

Exact name from the report

display_name

string?

Standardized English name

biomarker

string?

Standardized biomarker enum (see list below)

type

string

Specimen type: "blood" or "urine"

value

number?

Numeric measurement value

value_bound

object?

Boundaries for non-exact values

display_units

string?

Units as shown on report

unit_code

string?

UCUM-compliant unit code

reference_ranges

ReferenceRange[]

Normal/abnormal ranges

notes

string?

Additional lab comments

Value Bound Object

Used when exact values aren't available (e.g., ">5" or "<0.1"):

Field
Type
Description

greater_than

number?

Lower bound when result is ">X"

less_than

number?

Upper bound when result is "<Y"

Units Object

Structured breakdown of measurement units:

Field
Type
Description

id

number?

Internal unit identifier

name

string?

Internal unit name

numerator

string?

Top unit (e.g., "mg", "mmol")

denominator

string?

Bottom unit (e.g., "L", "dL")

exponent

number?

Power of 10 multiplier (e.g., 9 for 10^9/L)

Reference Range Object

Field
Type
Description

reference_lower_bound

number?

Lower normal limit

reference_upper_bound

number?

Upper normal limit

classification

string

"normal", "abnormal", or "borderline"

context

Context

Demographic context for this range

Context Object

Field
Type
Description

sex

string?

"male", "female", or "other"

age_lower_bound

number?

Minimum age in years

age_upper_bound

number?

Maximum age in years

modifiers

Modifier[]

Additional qualifiers

Modifier Object

Field
Type
Description

dimension

string?

Qualifier type (e.g., "menstrual_phase")

value

any?

Associated value

Handling Edge Cases

Missing Data

The API gracefully handles missing or unclear data:

  • Missing dates/times: Fields set to null

  • Unclear values: value field set to null, may use value_bound

  • Missing units: All unit fields null, display_units = "Unknown"

  • One-sided ranges: One bound is null (e.g., reference_upper_bound: null means ">X")

UTF-8 Encoding

⚠️ Important: Always use UTF-8 encoding when parsing responses. The data may contain:

  • Scientific symbols (µ, ×, ±)

  • Superscript/subscript notation

  • International characters in names

Error Handling

Implement retry logic for failed webhooks:

// Example webhook handler
app.post('/webhook/lab-reports', async (req, res) => {
    try {
        const data = req.body;

        // Verify upload_id exists
        if (!data.upload_id) {
            return res.status(400).send('Missing upload_id');
        }

        // Process biomarker data
        for (const report of data.data) {
            await processBiomarkers(report.results);
        }

        res.status(200).send('OK');
    } catch (error) {
        console.error('Webhook processing error:', error);
        res.status(500).send('Processing failed');
        // Terra will retry on 5xx responses
    }
});

Biomarker Enums

The system standardizes biomarkers to consistent enum values. Common examples:

Display Name
Biomarker Enum
Typical Units

Hemoglobin

hemoglobin_blood

g/dL

Glucose

glucose_blood

mg/dL or mmol/L

Cholesterol Total

cholesterol_total

mg/dL

Vitamin D

vitamin_d_25_oh

ng/mL

TSH

thyroid_stimulating_hormone

mIU/L

White Blood Cell Count

white_blood_cell_count

10^9/L

For the complete list of biomarker enums, refer to the supplementary files:

  • biomarkers.json - Full biomarker enum list

Best Practices

1. Implement Idempotency

Track upload_id to prevent duplicate processing:

def handle_webhook(data):
    upload_id = data['upload_id']

    if already_processed(upload_id):
        return  # Skip duplicate

    process_results(data)
    mark_as_processed(upload_id)

2. Handle Partial Data

Not all biomarkers/units may be successfully extracted:

for result in data['results']:
    if result.get('biomarker') == 'unknown':
        # Log for manual review
        log_unknown_biomarker(result)
    else:
        process_biomarker(result)

3. Validate Reference Ranges

Consider patient context when interpreting results:

def is_abnormal(result, patient_age, patient_sex):
    for range_obj in result['reference_ranges']:
        context = range_obj['context']

        # Check if range applies to patient
        if (context['sex'] == patient_sex and
            context['age_lower_bound'] <= patient_age <= context['age_upper_bound']):

            # Check if value is within range
            lower = range_obj['reference_lower_bound']
            upper = range_obj['reference_upper_bound']

            if lower and result['value'] < lower:
                return True
            if upper and result['value'] > upper:
                return True

    return False

Rate Limits & Quotas

  • File Size: Maximum 10MB per file

  • Files per Request: Maximum 10 files

  • Processing Time: Typically 1-10 minutes per report, based on size

Support

For technical support or questions:

Changelog

v2 (Current)

  • Enhanced biomarker standardization

  • UCUM-compliant unit codes (in Beta)

  • Improved reference range context

  • Status tracking system

  • Multi-file batch processing

v1 (Deprecated)

  • Basic PDF parsing

  • Limited biomarker recognition

Last updated

Was this helpful?