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.

⚠️ Pre-Release

This page is currently under active development and is provided in a pre-release state.

Some content may evolve as we continue to iterate on the implementation based on your feedback, but the core concepts and functionality are expected to remain consistent.

The page will be marked as general release in the near future

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/lab-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.

Reference Range Interpretation

Reference ranges 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?