Skip to main content

Hospital Integrations

Routes: /hospitals, /hospitals/new, /hospitals/:id Files: src/hospitals/HospitalsPage.tsx, src/hospitals/HospitalIntegrationPage.tsx

Hospital Integrations register EHR endpoints so patients can connect via SMART on FHIR OAuth. Each entry is stored as a standard FHIR Endpoint resource with vendor-specific data encoded in extensions.


Hospital List (/hospitals)​

File: HospitalsPage.tsx

Fetches Endpoint resources via medplum.search('Endpoint', ...) with:

  • _sort: '-_lastUpdated'
  • _count: 20 (paginated, max offset 10,000)
  • _total: 'accurate'

Filters​

FilterFHIR Search ParamNotes
Name searchname:containsApplied on Enter or search button click
EHR Vendorehr-vendorCustom search param on the Endpoint resource
Statusstatusactive or suspended

Table columns​

ColumnSourceNotes
NameEndpoint.name
EHR Vendorextension[url=.../endpoint-ehr-vendor].valueCodeBlue = epic, Teal = healow, Violet = meditech
FHIR Base URLEndpoint.addressTruncated at 320px
Status toggleEndpoint.statusactive → suspended toggle via medplum.updateResource()
Edit—Navigates to /hospitals/:id
Delete—Shows confirmation modal, then medplum.deleteResource('Endpoint', id) — hard delete

Create / Edit Hospital (/hospitals/new, /hospitals/:id)​

File: HospitalIntegrationPage.tsx

In edit mode, loads the Endpoint resource via medplum.readResource('Endpoint', id) and maps fields back from extensions. On save:

  • Create: medplum.createResource(endpoint) → redirects to /hospitals
  • Edit: medplum.updateResource(endpoint) → redirects to /hospitals

Form Fields​

Hospital Name​

Required. Maps to Endpoint.name. This is the display name shown to patients in the member portal when they browse hospitals to connect. Use the official name of the hospital or health system.

EHR Vendor​

Required. Stored as extension[url = 'http://devapi.chartchathealth.com/fhir/StructureDefinition/endpoint-ehr-vendor'].valueCode.

ValueLabelNotes
epicEpicMost common. Uses PKCE, no client secret required.
healowHealow (eClinicalWorks)Requires Practice Code field.
meditechMEDITECHRequires Client ID field. Client Secret optional.

Selecting a vendor dynamically shows/hides conditional fields (Practice Code for Healow, Client ID / Client Secret for MEDITECH).

FHIR Base URL​

Required. Maps to Endpoint.address. This is the root URL of the hospital's FHIR R4 API, e.g. https://fhir.example.org/api/FHIR/R4.

The URL must be a valid URL (validated client-side). The SMART discovery endpoint is derived from this URL during the Test Connection check.

Stored in Endpoint.address.

Test SMART Discovery button​

Calls:

GET fhir/ehr-import/smart-discovery?url=<encoded fhirBaseUrl>

The server fetches the SMART configuration document (.well-known/smart-configuration or /metadata) at that URL and returns authorization_endpoint and token_endpoint. On success the UI shows the discovered authorization URL in a green alert. On failure it shows the error message in red.

Always run this before saving a new hospital. If discovery fails, the patient OAuth flow will also fail.

Practice Code​

Shown only when EHR Vendor = Healow. Required for Healow. Stored in modifierExtension[url='practiceCode'].valueString.

This is the Healow/eClinicalWorks-specific practice identifier that is embedded in the FHIR base URL and used during the authorization flow. It is provided by eClinicalWorks when they set up your integration. Example: JAFJCD.

Client ID​

Shown only when EHR Vendor = MEDITECH. Required for MEDITECH. Stored in modifierExtension[url='clientId'].valueString.

The OAuth client ID issued by the hospital's MEDITECH system when your app was registered. MEDITECH issues a unique client ID per hospital.

Client Secret​

Shown only when EHR Vendor = MEDITECH. Optional. Stored in modifierExtension[url='clientSecret'].valueString.

Only required if the hospital configured your app as a confidential client in MEDITECH. Most MEDITECH public-client setups do not require this. Check with the hospital's IT team.

OAuth Scope​

Optional. Stored in modifierExtension[url='scope'].valueString.

Space-separated list of SMART on FHIR scopes requested during the patient OAuth authorization. If left blank, the member portal uses its built-in default scopes for that vendor.

Example:

launch/patient patient/*.read openid fhirUser offline_access

Common scopes:

ScopePurpose
launch/patientRequest patient context at launch
patient/*.readRead all patient-level resources
openidInclude identity token
fhirUserInclude the FHIR user reference in the token
offline_accessGet a refresh token for background syncs

Redirect URI​

Optional — overrides the vendor default. Stored in modifierExtension[url='redirectUri'].valueUri.

The URL the EHR's authorization server redirects the patient back to after they approve access. In most deployments the member portal has one configured redirect URI per EHR vendor already built in. Only set this field if you need to override it for a specific hospital.

Logo URL​

Optional. Stored in extension[url='logoUrl'].valueUrl.

A publicly accessible URL to the hospital's logo image. Displayed in the member portal when the patient browses hospital connections. Should be a square or landscape image at least 64×64px.

Enabled​

Required (checkbox, default: checked). Maps to Endpoint.status: active when checked, suspended when unchecked.

Only hospitals with status = active are visible to patients in the member portal. Use this to register a hospital without making it available yet (e.g. during testing or before credentials are finalised).


How Fields Are Stored on the Endpoint Resource​

The FHIR Endpoint resource splits fields into two categories:

CategoryExtension typeReadable by patients?Fields
Publicextension[]Yes (via access policy)ehrVendor, logoUrl
PrivatemodifierExtension[]No (hidden by access policy)clientId, clientSecret, practiceCode, scope, redirectUri

The modifierExtension mechanism means the server's access policy strips these fields from any response to patient-level tokens, so OAuth credentials are never exposed to the member portal frontend.

The full resource structure after save:

{
"resourceType": "Endpoint",
"status": "active",
"name": "Northwell Health",
"address": "https://fhir.example.org/api/FHIR/R4",
"connectionType": {
"system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type",
"code": "hl7-fhir-rest"
},
"payloadType": [{ "coding": [{ "code": "not-applicable" }] }],
"extension": [
{ "url": "http://devapi.chartchathealth.com/fhir/StructureDefinition/endpoint-ehr-vendor", "valueCode": "epic" },
{ "url": "logoUrl", "valueUrl": "https://cdn.example.com/logo.png" }
],
"modifierExtension": [
{ "url": "clientId", "valueString": "abc-123" },
{ "url": "scope", "valueString": "launch/patient patient/*.read openid fhirUser offline_access" },
{ "url": "redirectUri", "valueUri": "https://app.chartchathealth.com/ehr/callback" }
]
}