# Sending Orders with Medplum-Health Gorilla Integration

This guide explains how laboratory orders work in the Medplum-Health Gorilla labs integration.

The high-level workflow for sending laboratory & imaging orders is:

1. Present the provider with the appropriate lab order form (CPOE)
2. Create the appropriate FHIR resources based on that information
3. Execute the appropriate Medplum Bot to send the order to the performing lab.

## Key Concepts

Laboratory ordering involves unique complexities: coordinating between providers, labs, and collection facilities; handling physical specimens; and gathering clinical data. Understanding these core concepts is essential before implementing the technical details.

The following concepts form the foundation of laboratory ordering:

| Concept | Description | Importance |
| --- | --- | --- |
| Order | Request for one or more lab tests, uniquely identified and tracked. | Organizes tests, specimens and results. Maintains chain of custody and enables status tracking. |
| Test | Specific diagnostic procedure with defined requirements for specimen and data collection. | Determines specimen needs, required clinical data, and handling protocols. Impacts turnaround times and costs. |
| Specimen | Physical sample (blood, urine, etc.) for analysis. | Samples are only valid for a certain amount of time after collection. Accurately measuring sample collection time is critical for accurate processing. Samples can either be collected by the performing lab, or by the requesting provider. |
| Ask on Order Entry (AOE) | **Required** questions for some labs to gather additional clinical context for test processing. | Affects lab processing, result interpretation, and billing. Missing data can cause rejections or delays. |
| Order Splitting | Breaking a single order into multiple independent orders, typically when tests require different specimen types. | Allows labs to process specimens independently and maintain separate workflows for different test types. Prevents delays when specimens are collected at different times. |

## Creating an Order Form in React

Medplum provides a "headless UX" approach through specialized React components for building laboratory order forms.

### Core Components

The integration centers around two main components:

1. `HealthGorillaLabOrderProvider`: Context provider for state management
2. `useHealthGorillaLabOrder`: Hook for accessing state and operations

### State Management

The hook manages a comprehensive state object:

```typescript
type HealthGorillaLabOrderState = {

performingLab: LabOrganization | undefined;

selectedTests: TestCoding[];

testMetadata: Record<string, TestMetadata>;

diagnoses: DiagnosisCodeableConcept[];

billingInformation: BillingInformation;

specimenCollectedDateTime: Date | undefined;

orderNotes: string | undefined;

};
```

### Building an Order Form

You can find an open-source example order form [here](https://github.com/medplum/medplum-health-gorilla-demo/blob/main/src/HomePage.tsx). Feel free to use this as a starting point.

1. Wrap your application:

```tsx
function OrderPage() {

return (

<HealthGorillaLabOrderProvider>

<OrderForm />

</HealthGorillaLabOrderProvider>

);
}
```

2. Initialize with context:

```tsx
function OrderForm() {

const [patient, setPatient] = useState<Patient>();

const [requester, setRequester] = useState<Practitioner>();

const labOrderReturn = useHealthGorillaLabOrder({

patient,

requester,

});
}
```

3. Access operations:

```tsx
const {

state,

searchAvailableTests,

setTests,

setDiagnoses,

updateBillingInformation,

setSpecimenCollectedDateTime,

setOrderNotes,

createOrderBundle,

} = labOrderReturn;
```

| Command | Purpose |
| --- | --- |
| `searchAvailableTests` | Uses the `autocomplete` bot to fetch available lab tests from Health Gorilla's API based on search string |
| `searchAvailableLabs` | Uses the `autocomplete` bot to fetch available diagnostic labs from Health Gorilla's API based on search string |
| `setTests` | Updates selected tests in order state |
| `setDiagnoses` | Updates ICD-10 diagnosis codes in order state |
| `updateBillingInformation` | Updates payment details (patient, insurance, customer account) |
| `setSpecimenCollectedDateTime` | Sets when specimens were/will be collected |
| `setOrderNotes` | Adds notes/instructions for the lab |
| `createOrderBundle` | Creates FHIR resources for the complete order |
| `setPerformingLab` | Sets which lab will process the tests |
| `setPerformingLabAccountNumber` | Overrides the practice-level lab account number for the order |
| `validateOrder` | Checks order for required fields and valid data |

### Example

Lab Selection:

```tsx
<MyAutoComplete

label="Performing Lab"

loadOptions={searchAvailableLabs}

onChange={(e) => {

setPerformingLab(e.value as Organization);

}}
/>
```

Test Selection:

```tsx
<MyAutoComplete label="Selected tests" loadOptions={searchAvailableTests} onChange={setTests} />
```

Diagnosis Code Selection

```tsx
<ValueSetAutocomplete

label="Diagnoses"

binding="http://hl7.org/fhir/sid/icd-10-cm"

name="diagnoses"

maxValues={10}

onChange={(items) => {

const codeableConcepts = items.map((item) => ({

coding: [item],

})) as DiagnosisCodeableConcept[];

setDiagnoses(codeableConcepts);

}}
/>
```

Billing Type:

```tsx
<input

type="radio"

id="billToPatient"

name="billTo"

value="patient"

onChange={(e) => {

updateBillingInformation({ billTo: e.target.value });

}}
 />
 <label htmlFor="billToPatient">Patient</label>
 <input
   type="radio"
   id="billToInsurance"
   name="billTo"
   value="insurance"
   onChange={(e) => {
     updateBillingInformation({ billTo: e.target.value });
   }}
 />
 <label htmlFor="billToInsurance">Insurance</label>
```

Optional Insurance Coverage Selection (if `billTo` is `insurance`):

```tsx
{

patient && state.billingInformation.billTo === 'insurance' && (

<select

name="coverage"

onChange={(e) => {

updateBillingInformation({

patientCoverage: { reference: `Coverage/${e.target.value}` },

});

}}
    >
      <option value="">Select Insurance Coverage</option>
      {coverages.map((coverage) => (
        <option key={coverage.id} value={coverage.id}>
          {coverage.payor?.[0]?.display || 'Unknown Insurance'}
        </option>
      ))}
    </select>
  );
}
```

Optional Specimen Collection Time (if drawing in-house):

```tsx
<input

type="datetime-local"

onChange={(e) => {

setSpecimenCollectedDateTime(e.target.value ? new Date(e.target.value) : undefined);

}}
 />
```

Order Creation:

```tsx
async function handleOrderCreation() {

try {

const { serviceRequest } = await createOrderBundle();

await sendLabOrderToHealthGorilla(medplum, serviceRequest);

} catch (err) {

if (err instanceof LabOrderValidationError) {

// Handle validation errors

}

}
}
```

## Lab Account Numbers

Some labs (notably **Labcorp**) require account numbers to be included with each order. Account number requirements vary by lab—some require none, some require one, and some require both of the following:

### Physician-level account number

Stored as an `identifier` on the `Practitioner` resource with type `AN` and an `assigner` reference pointing to the performing lab's `Organization` in Medplum. The `send-to-health-gorilla` bot automatically reads this identifier and includes it in the order—no form input required.

```json
{
  "resourceType": "Practitioner",
  "identifier": [
    {
      "type": {
        "coding": [{ "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "AN" }]
      },
      "value": "[PHYSICIAN_ACCOUNT_NUMBER]",
      "assigner": { "reference": "Organization/[PERFORMING_LAB_ORGANIZATION_ID]" }
    }
  ]
}
```

### Practice-level account number

Stored as a nested extension on the `Practitioner` resource, keyed by lab. Each entry has a `lab` sub-extension (reference to the performing lab `Organization`) and a `value` sub-extension (the account number string). The bot automatically reads it and includes it in the order—no form input required.

```json
{
  "resourceType": "Practitioner",
  "extension": [
    {
      "url": "https://medplum.com/integrations/health-gorilla/lab-org-account",
      "extension": [
        { "url": "lab", "valueReference": { "reference": "Organization/[PERFORMING_LAB_ORGANIZATION_ID]" } },
        { "url": "value", "valueString": "[PRACTICE_ACCOUNT_NUMBER]" }
      ]
    }
  ]
}
```

If a practitioner orders under multiple practice-level accounts with the same lab, you can override the account number at order time using `setPerformingLabAccountNumber` from the `useHealthGorillaLabOrder` hook:

```tsx
setPerformingLabAccountNumber(selectedAccountNumber);
```

## FHIR Data Model

Laboratory orders use a two-level hierarchy of FHIR resources, with a parent order containing multiple individual tests.

### Order Structure

The parent order is represented by a `ServiceRequest` resource with the profile `https://medplum.com/profiles/integrations/health-gorilla/StructureDefinition/MedplumHealthGorillaOrder`. This order contains high-level information like:

- The ordering provider (`ServiceRequest.requester`)
- The performing laboratory (`ServiceRequest.performer`)
- Overall order status (`ServiceRequest.status`)
- Diagnosis codes (`ServiceRequest.reasonCode`)
- Minimum Patient demographic information (`ServiceRequest.subject`)
- Shared documentation (`ServiceRequest.supportingInfo`)

Each individual test within the order is represented by its own `ServiceRequest` resource that:

- Links back to the parent order using `ServiceRequest.basedOn`
- Contains the specific test code from the performing lab's compendium
- Holds test-specific details, including Ask on Order Entry (AoE) questions.

### Diagnosis codes

ICD-10 diagnosis codes belong on the **parent** lab order as `ServiceRequest.reasonCode`. Child test `ServiceRequest` resources do not carry diagnoses; they only hold the lab test `code`.

When using `useHealthGorillaLabOrder`, call `setDiagnoses` (or `addDiagnosis` / `removeDiagnosis`) with ICD-10 `CodeableConcept`s. `createOrderBundle` passes that state into `createLabOrderBundle()`, which writes it to the parent order's `reasonCode`.

If you build the order bundle yourself, set `reasonCode` on the parent order to ICD-10 `CodeableConcept`s before calling `$health-gorilla-send`. The `send-to-health-gorilla` bot reads `reasonCode` from the parent order and includes those codes on the outbound Health Gorilla `RequestGroup`.

### Patient requirements

The order's `ServiceRequest.subject` must reference a `Patient` that satisfies the **Medplum Health Gorilla Patient** profile. Before transmitting an order, `send-to-health-gorilla` validates and syncs that patient to Health Gorilla; missing required demographics cause the send to fail.

| Requirement | FHIR path | Notes |
| --- | --- | --- |
| Birth date | `Patient.birthDate` | Required |
| Name | `Patient.name` | At least one name with `family` and at least one `given` |
| Address | `Patient.address` | At least one address with `line`, `city`, `state`, and `postalCode`. If `country` is omitted, the send bot defaults it to `US` |
| Medical record number (MRN) | `Patient.identifier` | Exactly one identifier with type code `MR` |
| Phone | `Patient.telecom` | At least one phone with `use` of `home` or `mobile` |
| Sex | `Patient.gender` **or** US Core Birth Sex | Either `gender`, or the US Core Birth Sex extension |

Example of the required MRN identifier:

```json
{
  "type": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
        "code": "MR"
      }
    ]
  },
  "system": "https://example.com/mrn",
  "value": "123456"
}
```

Use FHIR profile validation in your project so patients are complete at registration time, rather than discovering gaps only when an order is submitted.

### Supporting Resources

Several additional FHIR resources provide important order details:

1. **Ask on Entry (AoE) Responses**: Stored as `QuestionnaireResponse` resources referenced by each test's `ServiceRequest.supportingInfo`.
2. **Specimens**: The `Specimen` resource tracks specimen details, particularly important for recording `collectionDate` with in-house collections.
3. **Documents**: Two types of `DocumentReference` resources are linked through `ServiceRequest.supportingInfo`: 
   - **Requisition Form**: The official order documentation with the lab's requisition number.
   - **Specimen Label**: PDF with specimen labeling information that can be affixed to sample collection tubes.

## Order Lifecycle

Orders progress through several states:
1. `draft`: Initial state from the order form. Order has not yet been sent to the Health Gorilla.
2. `active`: Order has been transmitted to Health Gorilla and the performing lab.
3. `completed`: Results have been received. Order processing is finished.
4. `on-hold`: An error occurred during processing. Requires intervention to resolve.
5. `revoked`: Order has been canceled.

### Automation Bots

#### send-to-health-gorilla Bot
 - Syncs patient and practitioner data with Health Gorilla.
 - Transmits order with billing information and diagnosis codes.

#### split-order Bot
 - Creates new parent orders for each group when splitting is required.
 - Reassigns child test `ServiceRequest` resources.

Example payload:

```typescript
const params = {
  resourceType: 'Parameters',
  parameter: [
    { name: 'order', valueReference: { reference: 'ServiceRequest/example' } },
    { name: 'groups', valueString: '436|1877;9230;900323' },
  ],
};
```
