Reference

Metriport

Metriport helps digital health companies access and manage health and medical data, through a single universal API.

Metriport helps digital health companies access and manage health and medical data, through a single universal API.

Category: EHR Integrations. Adds 12 actions and 1 webhook to a care flow. Built by External.

What to configure

Set these once, on the extension in Awell Studio. An action fails at run time if a required setting is missing.

SettingRequiredNotes
API KeyYesThe API Key for the Metriport Medical API. Stored as a secret.
Base URLNoThe base URL of the Metriport Medical API.
Rate Limit DurationNoRate limit Metriport enrollment webhooks at a certain duration (e.g. only enroll once for a given webhook message every '30 s', '1 m', '12 h', '30 d'). Prevents duplicate deliveries of the same message from re-enrolling a patient. Value should be {number} {unit}. Defaults to seven days as '7 d'
Webhook KeyNoThe Metriport webhook key used to verify incoming webhook requests. Metriport signs each request with an HMAC-SHA256 of the raw body using this key, sent in the x-metriport-signature header. Found in the Settings/Developers tab of the Metriport dashboard. When left empty, incoming webhook requests are not verified. Stored as a secret.

Actions

Metriport adds these 12 actions to a care flow. Add one to a step, then fill in its inputs.

Create Patient

Creates a Patient in Metriport for the specified Facility where the Patient is receiving care. Passing in a cohort ID will register that patient for real-time monitoring.

This action can be previewed in Studio before you publish, and retries automatically on a transient failure.

InputTypeRequiredDescription
Facility IDstringYesThe ID of the facility to create the Patient in
First NamestringYesThe Patient's first name
Last NamestringYesThe Patient's last name
Date of BirthdateYesThe Patient's date of birth (DOB)
Gender at BirthstringYesThe Patient's gender at birth. Accepts M, F, O or U as well as Male, Female, Other or Unknown
Drivers License ValuestringNoThe Patient's driver's license number
Drivers License StatestringNoThe 2 letter state acronym where this ID was issued, for example: CA
Address Line 1stringYesThe address
Address Line 2stringNoThe address details
CitystringYesThe city
StatestringYesThe 2 letter state acronym, for example: CA
ZipstringYes5 digit zip code
CountrystringYesMust be “USA”
PhonestringNoThe Patient's 10 digit phone number, formatted 1234567899
EmailstringNoThe Patient's email address
CohortstringNoThe ID (UUID) of the cohort to enroll the Patient in for real-time monitoring

Returns:

Data pointType
patientIdstring

Creates a Patient in Metriport for the specified Facility where the Patient is receiving care.

Optionally, providing a Cohort ID enrolls the Patient in real-time monitoring by adding them to that cohort. Note that enrolling a Patient in real-time monitoring has downstream consequences: once you start receiving updates about the Patient, you are expected to contribute data back to Metriport.

Visit endpoint docs for more info.

Delete Patient

Removes the specified Patient.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe Patient ID
Facility IDstringYesThe facility ID

Get Consolidated Data Query Status

Gets the status of a consolidated data query for a Patient. Use after starting a consolidated query to check if results are ready.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient whose consolidated data query status to check

Returns:

Data pointType
queriesjson
statusstring

Get Patient

Gets a Patient.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe Patient ID

Returns:

Data pointType
addressLine1string
addressLine2string
citystring
countrystring
dobdate
driversLicenseStatestring
driversLicenseValuestring
emailstring
firstNamestring
genderAtBirthstring
lastNamestring
phonestring
statestring
zipstring

Retrieves the specified Patient.

Visit endpoint docs for more info.

Get Document URL

Fetches the document from S3 and sends a presigned URL.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
File NamestringYesThe file name of the document

Returns:

Data pointType
urlstring

Gets a presigned URL for downloading the specified Document.

Visit endpoint docs for more info.

NOTE: This endpoint returns a URL which you can use to download the specified Document using the file name provided from the List Documents endpoint.

Get Webhook Bundle

Fetches the FHIR bundle from a Metriport webhook payload URL (e.g. the Encounter Bundle from an ADT notification, or a discharge summary). The URL is provided by the realtime update webhook on the bundleUrl data point and is only valid for 10 minutes.

This action can be previewed in Studio before you publish, and retries automatically on a transient failure.

InputTypeRequiredDescription
Bundle URLstringYesThe pre-signed Metriport payload URL to fetch the FHIR bundle from. This is the bundleUrl data point emitted by the realtime update webhook. Note: Metriport pre-signed URLs are only valid for 10 minutes, so this action should run shortly after the webhook fires.
Event TypestringNoThe Metriport notification type, as emitted on the realtime update webhook eventType data point. Recorded on the Provenance of the importable bundle so admission, transfer and discharge imports can be told apart. Leave empty to omit it. One of: Admission (patient.admit), Transfer (patient.transfer), Discharge (patient.discharge).
Provenance ReasontextNoFree-text reason recorded on the Provenance of the importable bundle, describing why this data was imported. Lets imported bundles be traced back to the clinical event that triggered them.

Returns:

Data pointType
bundlejson
encounterIdstring
transactionBundlejson

Fetches the FHIR bundle from a Metriport webhook payload URL — e.g. the Encounter Bundle from an ADT notification, or a discharge summary. Pass the bundleUrl data point emitted by the **Realtime Update webhook; the action downloads the bundle and returns it on the bundle data point.

When the payload is a Patient Encounter Bundle, the action also rewrites it into an executable FHIR transaction and returns that on the transactionBundle data point, ready to hand to the Medplum Find or create resource action.

The Encounter's Metriport id is returned separately on the encounterId data point, so a later step can address the imported Encounter without re-parsing the bundle.

NOTE: Metriport pre-signed URLs are only valid for 10 minutes, so this action should run early in the care flow, shortly after the realtime update webhook fires.**

FieldTypeDescription
urlstringThe pre-signed payload URL to fetch (the webhook's bundleUrl data point).
eventTypestring (optional)The Metriport notification type — wire this from the realtime update webhook's eventType data point. Recorded on the import Provenance so admit, transfer and discharge can be told apart.
provenanceReasontext (optional)Free-text reason recorded on the import Provenance, describing why the data was imported.
Data pointTypeDescription
bundlejsonThe FHIR bundle fetched from the URL, exactly as Metriport sent it.
transactionBundlejsonThe same data rewritten as an executable FHIR transaction. Omitted when the payload is not a Patient Encounter Bundle.
encounterIdstringMetriport's UUID for the Encounter in the bundle. Resolve the imported Encounter in Medplum with Encounter?identifier=https://metriport.com/fhir/encounter|<encounterId>. Omitted when the bundle carries no Encounter.

List Documents

Queries for all available document metadata for the specified patient across HIEs.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient for which to list their available Documents

Returns:

Data pointType
documentsjson

Lists all Documents that can be retrieved for a Patient.

Visit endpoint docs for more info.

NOTE: It also returns the status of querying Document references across HIEs, indicating whether there is an asynchronous query in progress (status processing) or not (status completed). If the query is in progress, you will also receive the total number of Documents to be queried as well as the ones that have already been completed.

Start Document Query

Triggers a document query for the specified patient across HIEs.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient for which to query Documents across HIEs
Facility IDstringNoThe facility providing the NPI to support this operation. Optional if the patient has only one facility.

Returns:

Data pointType
downloadStatusstring
downloadSuccessfulnumber
downloadTotalnumber
requestIdstring

Remove Patient from Cohort

Removes the specified Patient from a cohort.

This action can be previewed in Studio before you publish, and retries automatically on a transient failure.

InputTypeRequiredDescription
Cohort IDstringYesThe ID of the cohort to remove the Patient from
Patient IDstringYesThe Metriport ID of the Patient to remove from the cohort

Returns:

Data pointType
cohortjson
messagestring

Removes the specified Patient from a cohort.

Visit endpoint docs for more info.

Start Consolidated Data Query

Starts an asynchronous query for the Patient's consolidated FHIR data. Results are sent via webhooks.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient whose consolidated data to query
Resource TypesstringNoOptional comma-separated list of FHIR resource types to filter by (e.g. "Condition,Observation,MedicationRequest"). If empty, all resource types are returned.
Date FromstringNoOptional start date to filter resources by (inclusive), formatted YYYY-MM-DD
Date TostringNoOptional end date to filter resources by (inclusive), formatted YYYY-MM-DD
Conversion TypestringNoHow to render the medical record: "json" (default), "pdf", or "html"

Returns:

Data pointType
requestIdstring
statusstring

Start Network Query

Triggers an asynchronous query for the specified Patient across available health data networks (HIEs, pharmacies, labs). Results are sent via webhooks.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient for which to query health data

Returns:

Data pointType
requestIdstring
statusstring

Update Patient

Updates the specified Patient.

This action can be previewed in Studio before you publish.

InputTypeRequiredDescription
Patient IDstringYesThe ID of the Patient to update
Facility IDstringYesThe ID of the facility to create the Patient in
First NamestringYesThe Patient's first name
Last NamestringYesThe Patient's last name
Date of BirthdateYesThe Patient's date of birth (DOB)
Gender at BirthstringYesThe Patient's gender at birth. Accepts M, F, O or U as well as Male, Female, Other or Unknown
Drivers License ValuestringNoThe Patient's driver's license number
Drivers License StatestringNoThe 2 letter state acronym where this ID was issued, for example: CA
Address Line 1stringYesThe address
Address Line 2stringNoThe address details
CitystringYesThe city
StatestringYesThe 2 letter state acronym, for example: CA
ZipstringYes5 digit zip code
CountrystringYesMust be “USA”
PhonestringNoThe Patient's 10 digit phone number, formatted 1234567899
EmailstringNoThe Patient's email address
CohortstringNoThe ID (UUID) of the cohort to enroll the Patient in for real-time monitoring

Updates the specified Patient.

Visit endpoint docs for more info.

Webhooks

Metriport can send this event into Awell, where each one can start a care flow or move a patient along. Point the webhook at the URL Studio shows you when you enable it.

realtimeUpdate

Payload:

Data pointType
bundleUrlstring
eventTypestring
externalIdstring
messageIdstring
metriportPatientIdstring
whendate

Setup and notes

Metriport is Plaid for healthcare data. We help digital health companies access and manage patient health and medical data, through an open-source and universal API.

Through a single integration, our API enables modern health companies to get the comprehensive patient data they need from both HIEs and EHRs, as well as popular wearable devices.

As a developer-first interoperability solution, Metriport is powering the next wave of innovative companies, accelerating a revolution in digital health.

To learn more visit https://www.metriport.com/

Extension settings

In order to set up this extension, **you will need to provide a Metriport API key. You can obtain an API key via the Metriport dashboard by selecting the Developers tab. To learn more on how to get started with Metriport visit our quick start docs for our Medical API. Also, to better understand how our API keys work check out the API Keys section of our docs as well.

GENERAL NOTE: Make sure to create Organizations and Facilities in Metriport before using this extension. A Patient must be associated with a Facility by providing the facilityId when stated in the actions.

Remove Patient

Removes a Patient at Metriport and at HIEs the Patient is linked to.

Visit endpoint docs for more info.

Query Documents

Triggers a Document query for the specified Patient across HIEs.

Visit endpoint docs for more info.

NOTE: When executed, this endpoint triggers an asynchronous Document query with HIEs and immediately returns the status of Document query, processing .

Building the transaction bundle

Metriport delivers a bundle of type: 'collection', which is not executable. Handing it straight to Medplum does nothing useful: no entry carries request metadata saying what to do with it, and every internal reference points at a Metriport UUID that means nothing in Medplum. The action therefore builds a second, executable bundle rather than passing the original through.

The transformation is a pure function with no Medplum access of its own — this extension holds Metriport credentials only. That rules out reading Medplum to reconcile against what is already there, so every lookup is expressed declaratively and resolved by the server when the transaction executes.

The Patient is never written. Awell/Medplum is the source of truth for patient demographics, so the Patient entry is dropped entirely and every reference to it becomes a conditional reference:

Patient?identifier=https://awellhealth.com/patients|<awell patient id>

Omitting the entry guarantees structurally that a Metriport ADT feed can never overwrite the patient record.

Everything else is written idempotently. Each Metriport resource is stamped with an identifier derived from its Metriport id and written with a conditional update:

identifier: { system: 'https://metriport.com/fhir/encounter', value: '<metriport id>' }
request:    PUT Encounter?identifier=https://metriport.com/fhir/encounter|<metriport id>

A conditional update creates on zero matches and updates on one, so a redelivered notification updates in place instead of duplicating Conditions, Observations, Practitioners and Locations — and the admit and discharge notifications for one visit converge on a single Encounter. Existing identifiers are kept, so the Encounter keeps its HL7 VN visit number alongside ours.

References are rewritten to Metriport's own fullUrls.** Metriport resolves its relationships correctly, but emits them in a form FHIR cannot match: entries carry urn:uuid: fullUrls while references to them are relative.

fullUrl:    urn:uuid:3ca5e8d2-7c84-45ab-91e7-834f8becde12
reference:  Location/3ca5e8d2-7c84-45ab-91e7-834f8becde12

A transaction resolves an internal reference by matching it against fullUrl verbatim, and a relative reference does not match a urn:uuid: one — Medplum would read it as a reference to a Medplum Location with that id, which does not exist. Rewriting the reference to the entry's fullUrl closes the gap while keeping Metriport's identity. This is also why the result is a transaction and not a batch: urn:uuid resolution is a transaction feature.

**meta is stripped from every resource. Medplum's meta.accounts is inherited from the compartment of the Patient a resource references, but specifying meta at all on a create or update replaces those inherited accounts instead of adding to them. Metriport's Encounter arrives with a meta, so it is removed. resource.id is dropped too, for a separate reason: Medplum assigns identity, and the entry's fullUrl already carries the local identity the transaction needs.

Two entries are synthesised.** An Organization named Metriport Realtime Monitoring, created with ifNoneExist so an existing one is reused rather than overwritten; and a Provenance recording the import — what it created, when, which Metriport bundle it came from, and which ADT event triggered it (patient.admitA01, patient.transferA02, patient.dischargeA03).

extensions/metriport/actions/webhookBundle/bundle/transform.test.ts asserts the complete output for a real patient.admit bundle, if you want to see the whole before/after in one place.

Wiring it into a care flow

  1. **Realtime Update webhook fires and emits bundleUrl and eventType.
  2. Get Webhook Bundle — pass bundleUrl to url and eventType to eventType. Run this early; the URL expires after 10 minutes.
  3. Medplum Find or create resource — pass the transactionBundle data point to its resourceJson field. No changes to that action are needed; it detects a Bundle and executes it.

PREREQUISITE: for imported resources to be tagged with the Metriport organization, the Medplum Patient must already carry it in meta.accounts before the notification arrives.** Resources created without a meta inherit their accounts from the compartment of the Patient they reference, so tagging the Patient once causes every subsequent import to inherit it automatically. Note that this only covers resources in the patient compartment — Location and Practitioner are shared directory resources and are intentionally created untagged, since scoping a hospital or a physician to one patient's tenant would be wrong.

**NOTE: the conditional Patient reference only resolves if your Medplum Patients carry an identifier under the https://awellhealth.com/patients system with the Awell patient id as its value. A conditional reference that matches no Patient fails the whole transaction.

When the transaction bundle is omitted

Get Webhook Bundle serves several Metriport webhook types and only ADT notifications carry encounter bundles. For any payload that is not a collection bundle, transactionBundle is simply omitted and bundle is emitted on its own — the action still succeeds.

A collection bundle that is missing its Patient or Encounter entry is treated differently: that is an encounter bundle which does not describe an encounter, so the action fails rather than silently emitting a partial result.

Webhooks

Realtime Update

An enrollment trigger that starts a care flow when Metriport sends a real-time patient notification.

Metriport POSTs every notification type to the same endpoint. Four of them share one payload shape — a meta envelope plus a payload pointing at a pre-signed bundle URL — and this webhook enrolls a patient on all four:

  • patient.admit (HL7 ADT^A01)
  • patient.discharge (HL7 ADT^A03)
  • patient.transfer (HL7 ADT^A02)
  • medical.discharge-summary

The eventType data point carries the raw Metriport webhook type, so a care flow can branch on it. The payload's url is a pre-signed link to the FHIR Encounter Bundle.

The webhook validates the request, emits the data points (including the pre-signed bundle URL on bundleUrl), and replies immediately — it does not download the bundle. Fetch the bundle later in the care flow with the Get Webhook Bundle** action, using the bundleUrl data point. Because the URL expires after 10 minutes, run that action early.

Any other notification type Metriport sends — medical.document-download, medical.consolidated-data, and anything added in future — is acknowledged with a 200 and does not enroll a patient. A notification whose type is handled but whose payload is malformed fails loudly instead, so a genuine integration problem is not mistaken for an event we chose to ignore. Metriport verification ping messages are answered with a 200 that echoes the ping value back as pong: <value>.

Data points

Data pointTypeDescription
eventTypestringThe Metriport webhook type: patient.admit, patient.discharge, patient.transfer or medical.discharge-summary
metriportPatientIdstringThe Metriport patient ID (also used as the patient identifier for enrollment)
externalIdstringYour external patient ID, if provided to Metriport
whendateWhen the event occurred — the admit time on an admit event, the discharge time on a discharge event
messageIdstringThe Metriport message ID for the notification
bundleUrlstringPre-signed URL to the FHIR bundle; fetch it with the **Get Webhook Bundle action (valid for 10 minutes)

Verifying incoming requests

Optionally set the Webhook Key** setting to the webhook key from the Metriport dashboard (Settings/Developers tab). Metriport authenticates each webhook with an HMAC-SHA256 signature of the raw request body, keyed with your webhook key and sent in the x-metriport-signature header. When the setting is populated, the webhook recomputes the HMAC over the raw body and rejects any request whose signature is missing or does not match (401). When left empty, requests are not verified.

More Info

For more information on how to integrate with Metriport please visit our Medical API docs

Changelog

August 2026

  • Rename the enrollment webhook to realtimeUpdate. The old name described what Awell does with the notification rather than what Metriport sends, which read confusingly next to the genuine enrolment concepts (the Cohort field, enrolling a patient into a care flow). Behaviour is unchanged. Breaking: the webhook endpoint URL changes, so any webhook already configured in the Metriport dashboard must be repointed.
  • Date of Birth on the Create Patient and Update Patient actions is now a date field rather than a free-text string, so care flows can map a date onto it directly instead of hand-formatting YYYY-MM-DD. The value is normalised to the date-only string Metriport expects, so care flows already passing YYYY-MM-DD are unaffected.

July 2026

  • Add enrollment webhook: an enrollment trigger for Metriport real-time patient notifications. The eventType data point carries the Metriport webhook type (patient.admit or medical.discharge-summary) so care flows can distinguish on it. The webhook validates and replies immediately, emitting the pre-signed FHIR bundle URL on the bundleUrl data point rather than downloading the bundle inline.
  • Add Get Webhook Bundle action: fetches the FHIR bundle from a Metriport webhook payload URL (the webhook's bundleUrl), for use later in the care flow.
  • Add optional Webhook Key setting used to verify incoming webhook requests via Metriport's HMAC-SHA256 signature (x-metriport-signature header), computed over the raw request body.

Where this page comes from

The settings, actions, inputs, outputs and webhooks above are generated from the extension's own code, at @awell-health/awell-extensions v2.1.159. They match what the platform actually does rather than a description of it.

Field-level detail also appears in Awell Studio when you configure the action. Something wrong or missing? Email support@awellhealth.com.

On this page