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

Best Practices

Recommendations for robust integration with the Lab Reports API.

Idempotency via Event ID

Every webhook event carries a unique event_id. Use it to deduplicate webhook deliveries and prevent processing the same event twice.

def handle_webhook(event):
    event_id = event["event_id"]

    if already_processed(event_id):
        return 200  # Acknowledge but skip

    process_results(event["data"]["results"])
    mark_processed(event_id)
    return 200

event_id is stable across redeliveries of the same event, so it's the right dedup key. If you reprocess a session (POST /v2/reports/{session_id}/reprocess), that emits a new event with a new event_id — intentional reprocessing is a distinct event, not a duplicate.

Handling Unmatched Biomarkers

When biomarker.key is null, the system could not confidently match the extracted name to a known biomarker. This is normal for uncommon or lab-specific tests.

for result in session["results"]:
    biomarker = result["biomarker"]
    biomarker_key = biomarker["key"]
    source_name = result["source"]["name"]

    if biomarker_key is not None:
        # Matched — the canonical key, scoped by site and by the date the
        # measurement was taken. On a lab report both extras are absent and this
        # collapses to the key alone; on a scan they are what keeps the same
        # measure at fifteen different sites fifteen distinct rows.
        store_by_biomarker(
            (biomarker_key,
             biomarker.get("region"),
             result["source"].get("collection_date")),
            result,
        )
    else:
        # Unmatched — fall back to the name printed on the report
        store_by_name(source_name, result)
        log_unmatched(source_name)

Reference Range Interpretation

First, check how many ranges there are. One range is a normal interval. Several ranges are bands — Quest's HbA1c comes as <5.7, 5.7–6.4, ≥6.5 — and the one in the middle is not "normal"; read each band's label ("Consistent with increased risk for diabetes (prediabetes)") and its coded type where present. Find the band the value falls in yourself; interpretation.applied_range is only set when exactly one range applies to the patient's demographics.

Reference ranges also include demographic context. Match the range to your patient's demographics before interpreting:

Terra also surfaces the lab's own verdict directly in interpretation.flag (a coded value like "high" / "low" / null) with the raw printed flag in interpretation.flag_raw. Use that when you want the report's flag rather than computing your own from the ranges above.

Some results have multiple reference ranges for different demographics (e.g., separate ranges for males and females, or for pregnant vs. non-pregnant patients). Always filter by context before interpreting.

Webhook Error Handling

Your webhook endpoint should:

  1. Return 2xx quickly — Do heavy processing asynchronously after acknowledging

  2. Be idempotent — The same payload may be delivered more than once

  3. Handle retries — If your endpoint returns a non-2xx status, Terra will retry delivery

Choosing Delivery Destinations

Webhooks aren't the only delivery option — lab reports can also be delivered to cloud storage, message queues, and databases. Delivery is opt-in per destination: a destination receives reports only if its destination_event_types allow-list includes "lab_report". Each destination's outcome is tracked independently, so one failing never fails the others (the session ends partially_sent in that case). Inspect per-destination state via the /deliveries sub-resource. See Delivery Destinations for the full mechanism.

UTF-8 Encoding

Lab report data may contain:

  • Scientific symbols: µ, ×, ±

  • Superscript notation: 10^9, 10^12

  • International characters in biomarker names and notes

  • Special units: µmol/L, µg/dL

Always parse response bodies as UTF-8. Most HTTP clients do this by default, but verify your JSON parser handles multibyte characters correctly.

Rate Limits

The Lab Reports API enforces rate limits to ensure fair usage:

Constraint
Limit

File size

20 MB per file

Files per request

1 (single file)

Processing time

Typically 30s–3min

If you need to upload many reports in bulk, space your requests and use reference_id to track which reports belong to which patient.

Storing Session IDs

Session IDs are snowflake int64 values serialized as JSON strings (e.g., "297405620317847552"). Store them as strings, not integers:

Polling vs. Webhooks

Approach
Pros
Cons

Webhook

Real-time, no wasted requests

Requires public endpoint, retry logic

Polling

Simple, no infrastructure needed

Wastes requests, adds latency

Recommendation: Use webhooks for production. Use polling only during development or as a fallback when your webhook endpoint is unavailable.

If you must poll, check no more frequently than every 5 seconds:

Last updated

Was this helpful?