DrChrono Lab API and Webhook

Important Notice 

Please send an email to api@drchrono.com. Aside from our API scopes and User Permissions, a specialist will need to enable the Lab Vendor permission for your application to be able to POST to our lab APIs. Provide the name of your DrChrono API app and the name of the lab you are connecting to.

The DrChrono Lab API does NOT electronically send orders to a laboratory or receive results from one. The purpose of these endpoints is to allow a third-party lab system to push data into DrChrono.

DrChrono Lab API

Complete API Sequence Summary


API Endpoint Action Purpose
1 /api/sublabs  POST One-time: Register your lab (save the id)
2 /api/lab_orders  POST Create order record
3 /api/lab_documents POST [Optional] Upload requisition PDF (type=REQ)
4 /api/lab_tests POST Submit test panels
5 /api/lab_documents POST Upload result PDF (type=RES)
6 /api/lab_results  POST Submit structured result values
7 /api/lab_orders/{id} PATCH Update order status to "R" (Results Received)

Pre-Requisite:

- Email api@drchrono.com to request Lab Vendor permission for your app (provide your DrChrono API app name)

- Required OAuth scopes: labs:read labs:write settings:read settings:write users:read users:write

- Required user permission: "Share Patients" (From Account > Staff Permissions)

Sublab API

This is a one-time setup. The sublab ID is required when creating lab orders. The sublab is an identifier for your laboratory. For instance, I am looking to connect to a Lab called "Custom DRC Labs". I will first need to create a sublab for my lab and store it inside the DrChrono system.

Here is a POST call to accomplish a new sublab creation.

POST https://app.drchrono.com/api/sublabs
{
    "facility_code": "00999CL",
    "name": "Custom DRC Labs"
}

Response:

{
    "id": 1084,
    "name": "Custom DRC Labs",
    "facility_code": "00999CL",
    "vendor_name": "Your Lab Vendor Name"
}

NOTE:

- vendor_name is set by the DrChrono API Specialist when granting Lab Vendor permission. If you want a specific name, specify it in your support ticket.

- id is the value you'll use as `sublab` in all subsequent lab_orders calls.

- This endpoint is read-only for standard API consumers; the Lab Vendor permission enables write access.

Lab Order

Create a lab order record in the patient's chart. This represents an order that has been placed with your lab.

JSON example for submitting an order via API.

POST https://app.drchrono.com/api/lab_orders

{
    "doctor": 319108,
    "patient": 124818685,
    "sublab": 1084,
    "status": "S",
    "notes": "Fasting required. Patient advised no food 12 hours prior.",
    "accession_number": "ACN-2025-0714-001",
    "icd10_codes": [
        {
            "code": "E11.65"
        },
        {
            "code": "E78.5"
        }
    ],
    "priority": "N",
    "requisition_id": "REQ-78432",
    "external_requisition_id": "EXT-LAB-99201"
}

If you are including a lab requisition form, please use the api/lab_documents endpoint and set "type" to REQ.

curl --location 'https://app.drchrono.com/api/lab_documents' \
--header 'Authorization: Bearer 123456' \
--form 'document=@"/Users/your.macbook/Downloads/LAB DOCUMENT A.pdf"' \
--form 'lab_order="11104895"' \
--form 'type="REQ"'

The patient's lab order should show in the patient chart > Lab Orders. 

Lastly, to update a status make a PATCH call to the lab_orders API.

PATCH https://app.drchrono.com/api/lab_orders/11104895
{
    "status": "R"
}

Here is a complete list of lab order status.

Value Note
N Not Sent
A ABN Required (Advance Beneficiary Notice)
S Sent
R Results Received
E Error
P Preliminary Results
Q Queued
C Canceled

Field Definitions for api/lab_orders

 Field                                                 Type                                                Required                                       Description                                 UI Effect 

doctorintegerYesDrChrono doctor ID Shows as ordering provider on the lab order.
patientintegerYesDrChrono patient IDOrder appears in this patient's chart under Lab Orders
sublabintegerYesThe sublab ID N/A
statusstring (1 char) No (default: "N")Current status of the orderDisplayed in the "Status" column of the lab orders table
notestextNoFree-text notes about the orderVisible when viewing order details
accession_numberstring (max 70)NoThe lab's unique tracking number for this specimen/orderDisplayed in order details. Used to correlate with external lab systems
icd10_codesarray of objectsNoDiagnosis codes associated with the order. Each object must have a `code` field with a valid ICD-10 codeShows in the "Tests" column as the description text
prioritystring (1 char)No`"N"` = Normal, `"S"` = STAT (urgent)Indicates urgency of the order
requisition_idstring (max 100)NoYour internal requisition identifierStored for reference/correlation
external_requisition_idstring (max 100) NoExternal system requisition IDStored for cross-system tracking

Lab Tests

Submit the individual test panels/components for an order. Each test represents a grouping of results (e.g., "Complete Blood Count", "Comprehensive Metabolic Panel"). You can submit multiple tests per order.

JSON example

POST https://app.drchrono.com/api/lab_tests

[
    {
        "lab_order": 11104895,
        "code": "58410-2",
        "name": "Complete Blood Count (CBC)",
        "description": "CBC with Differential",
        "collection_date": "2025-07-14T08:30:00",
        "internal_notes": "Specimen collected at office. Tube type: EDTA lavender top.",
        "report_notes": "Results reviewed and verified by lab director.",
        "status": "F",
        "specimen_source": "Blood",
        "specimen_condition": "Satisfactory",
        "specimen_total_volume": 5.0
    },
    {
        "lab_order": 11104895,
        "code": "24323-8",
        "name": "Comprehensive Metabolic Panel (CMP)",
        "description": "CMP-14",
        "collection_date": "2025-07-14T08:30:00",
        "internal_notes": "Fasting specimen confirmed.",
        "report_notes": "All analytes within reference methodology limits.",
        "status": "F",
        "specimen_source": "Serum",
        "specimen_condition": "Satisfactory",
        "specimen_total_volume": 7.5
    }
]

Field Definitions for api/lab_tests

 Field                                                 Type                                                Required                                       Description                                 UI Effect 

lab_orderintegerYesThe lab order ID this test belongs to Links test to the order in the patient chart
codestring (max 16)NoLOINC code or your lab's internal panel code. Used to group results under this test.Displayed as the panel identifier. Used for grouping results in the plotter
namestring (max 100)NoName of the test panelShown as the panel/test name in the results table header
descriptionstring (max 200)NoDescription of what this test covers Shows in the "Tests" column on the lab orders list
collection_datedatetimeNoWhen the specimen was collected. Format: `YYYY-MM-DDTHH:MM:SS`Used as the timestamp for trending/plotting results over time. Critical for the plotter X-axis.
internal_notestextNoInternal notes visible to staffShown in test detail view
report_notestextNoNotes that appear on the reportDisplayed with the test results
statusstring (1 char)NoStatus of this testDetermines whether results are considered preliminary or final
specimen_sourcestring (max 100)NoSource of the specimen (e.g., Blood, Urine, Serum, Saliva)Displayed in test details
specimen_conditionstring (max 100) NoCondition of the specimen (e.g., Satisfactory, Hemolyzed, Lipemic)Displayed in test details
specimen_total_volumefloatNoVolume of specimen in mLDisplayed in test details

Lab Document

Upload PDF documents (requisition forms or result reports) and attach them to a lab order.

Important: The `id` from the RES document upload is required when submitting structured lab results.

curl --location 'https://app.drchrono.com/api/lab_documents' \
--header 'Authorization: Bearer 123456' \
--form 'document=@"/Users/your.macbook/Downloads/LAB DOCUMENT B.pdf"' \
--form 'lab_order="11104895"' \
--form 'type="RES"'

The DrChrono patient chart orders page should look like this.

The "type" field will determine the type of document upload. Here is a complete list of the "type" values.

Value Note
REQ Requisition Form
RES Lab Results
R-A Requisition Form and ABN 
ABN ABN (Advance Beneficiary Notice)

Lab Results

Submit the individual structured result values (observations) for each test. This is what populates the results table AND the graphical plotter in the patient chart.

POST https://app.drchrono.com/api/lab_results 

[
    {
        "lab_test": 156196635,
        "document": 17836725,
        "status": "F",
        "observation_code": "6690-2",
        "observation_description": "White Blood Cell Count",
        "test_performed": "2025-07-14T14:30:00",
        "value": "7.2",
        "value_is_numeric": true,
        "unit": "10*3/uL",
        "normal_range": "4.5 11.0",
        "abnormal_status": "N",
        "is_abnormal": false,
        "comments": "Within normal limits."
    },
    {
        "lab_test": 156196635,
        "document": 17836725,
        "status": "F",
        "observation_code": "789-8",
        "observation_description": "Red Blood Cell Count",
        "test_performed": "2025-07-14T14:30:00",
        "value": "5.1",
        "value_is_numeric": true,
        "unit": "10*6/uL",
        "normal_range": "4.7 6.1",
        "abnormal_status": "N",
        "is_abnormal": false,
        "comments": ""
    },
    {
        "lab_test": 156196635,
        "document": 17836725,
        "status": "F",
        "observation_code": "718-7",
        "observation_description": "Hemoglobin",
        "test_performed": "2025-07-14T14:30:00",
        "value": "11.8",
        "value_is_numeric": true,
        "unit": "g/dL",
        "normal_range": "12.0 17.5",
        "abnormal_status": "L",
        "is_abnormal": true,
        "comments": "Slightly below reference range. Consider iron studies."
    },
    {
        "lab_test": 156196636,
        "document": 17836725,
        "status": "F",
        "observation_code": "2345-7",
        "observation_description": "Glucose",
        "test_performed": "2025-07-14T14:30:00",
        "value": "105",
        "value_is_numeric": true,
        "unit": "mg/dL",
        "normal_range": "70.0 99.0",
        "abnormal_status": "H",
        "is_abnormal": true,
        "comments": "Elevated. Fasting confirmed. Recommend follow-up A1C."
    }
]

Field Definitions for api/lab_results

 Field                                                 Type                                       Required                              Description                       UI Effect                              Plotter Impact 

lab_testintegerYesThe lab test ID this result belongs toGroups results under the correct test panel in the results tableDetermines panel grouping in chart
documentintegerYesThe lab document ID (from step 4, type=RES)Links the result to the PDF report. Clicking the document link opens this PDFNone directly
statusstring (1 char)YesResult status. Same values as test status (F, P, C, I, X)Shown in result detail. "F" indicates verified final resultOnly `F` and `C` results are considered definitive
observation_codestring (max 16)NoLOINC code for this specific observation (e.g., "6690-2" for WBC)Displayed as identifierCritical for trending. Results with the same `observation_code` across multiple orders are plotted together on the same chart over time
observation_descriptionstring (max 200)NoName (e.g., "White Blood Cell Count")Shown as the row label in the results table and as the chart titleChart title
test_performeddatetimeYesWhen the test/analysis was performed. Format: `YYYY-MM-DDTHH:MM:SS`Shown in result detailsUsed as the X-axis data point on the plotter chart
valuestring (max 100)YesThe result value (e.g., "7.2", "Positive", "Non-reactive")Displayed in the "Value" columnThe Y-axis data point when numeric
value_is_numericbooleanYesWhether the value should be treated as a numberDetermines display formattingControls whether the plotter renders a chart. If `false`, no chart is generated for this observation. Only numeric results get plotted
unitstring (max 16)NoUnit of measurement (e.g., "mg/dL", "10*3/uL", "g/dL")Shown next to the valueDisplayed on the Y-axis label
normal_rangestringNoReference range. When `value_is_numeric` is `true`, format as `"<lower> <upper>"` (e.g., `"70.0 99.0"`). When not numeric, provide as descriptive text (e.g., `"Negative"`)Displayed in "Reference Range" columnDefines the shaded normal band on the chart. The plotter draws a gray band from `lower` to `upper`. Values outside the band are visually abnormal
abnormal_statusstringNoCoded abnormal flag. See table belowDisplayed with color coding (red for abnormal)Affects the abnormal indicator on data points
is_abnormalbooleanNoWhether this result is abnormalRow is highlighted/flagged when `true`. Panel header shows abnormal indicatorData point may be colored differently on chart
commentstextNoComments/notes about this specific resultShown in result details and as tooltip on chart hoverAppears in chart tooltip
group_codestringNoAlternative grouping code (maps to internal `result_code`)Used for panel-level grouping if presentCan affect which panel a result is displayed under
specimen_receiveddatetimeNoWhen the lab received the specimenStored for referenceNot directly used in plotter

Abnormal Status Values

| Value | Meaning | Visual Indicator |
---------------------------------------
| `N` | Normal | No flag |
| `L` | Low | Below range flag |
| `LL` | Alert Low | Critical low flag |
| `H` | High | Above range flag |
| `HH` | Alert High | Critical high flag |
| `<` | Panic Low | Critical alert |
| `>` | Panic High | Critical alert |
| `A` | Abnormal | General abnormal flag |
| `AA` | Very Abnormal | Critical abnormal flag |
| `S` | Susceptible | Microbiology |
| `R` | Resistant | Microbiology |
| `I` | Intermediate | Microbiology |
| `NEG` | Negative | Negative finding |
| `POS` | Positive | Positive finding |
| (empty) | No Comment | No indicator |

How normal_range works with the Plotter.

When `value_is_numeric` is `true`:

- Format: `"<lower_bound> <upper_bound>"` (space-separated floats)

- Example: `"70.0 99.0"` means normal range is 70.0 to 99.0

- The plotter draws a **shaded band** between these values representing the normal zone

- The Y-axis auto-scales to show the range plus 5% padding above/below

- Values falling **outside** the shaded band are visually abnormal

When `value_is_numeric` is `false`:

- Provide as descriptive text (e.g., `"Negative"`, `"Non-Reactive"`)

- **No chart is rendered** for non-numeric results

- The range text is displayed as-is in the reference column

How the Plotter Trends Results Over Time.

The plotter groups results by `observation_code`. When the same patient has multiple lab orders over time with results sharing the same `observation_code`:

- All values are plotted on a single spline chart

- X-axis = `collection_date` (from the parent lab_test) or `test_performed`

- Y-axis = `value` (numeric)

- The normal range band persists across all data points

- This allows providers to see trends (e.g., glucose trending upward over 6 months)

Lab Webhook

The lab order API has a webhook for when the order was created, modified, and deleted. You can subscribe to those events from the API page (Account > API). 

Webhook Events:

| Event | Fires When |
----------------------
| `LAB_ORDER_CREATE` | A lab order is created (via UI or API) |
| `LAB_ORDER_MODIFY` | A lab order is modified (status change, etc.) |
| `LAB_ORDER_DELETE` | A lab order is deleted |

Reference

https://app.drchrono.com/api-docs/#tag/Clinical/operation/sublabs_create

https://app.drchrono.com/api-docs/#tag/Clinical/operation/lab_orders_create

https://app.drchrono.com/api-docs/#tag/Clinical/operation/lab_documents_create

https://app.drchrono.com/api-docs/#tag/Clinical/operation/lab_tests_create

https://app.drchrono.com/api-docs/#tag/Clinical/operation/lab_results_create

https://app.drchrono.com/api-docs/#section/Webhooks