Medication Data Exchange

Medication Data Exchange

Medication data is simultaneously one of the most exchanged and most misimplemented data types in FHIR. The pattern failure is almost always the same: developers pick the medication resource that sounds right and ignore the others, or they treat all four medication resources as interchangeable containers for “drugs a patient is taking.”

They are not interchangeable. FHIR models the medication lifecycle as four distinct resources, each representing a different clinical event with different implied intent. Using the wrong resource causes downstream systems to misinterpret clinical intent — a prescription treated as a medication history, or a patient-reported drug treated as an active order. These are not cosmetic errors.


The four-resource lifecycle

ResourceClinical EventWho Creates ItDrives
MedicationRequestA clinician writes a prescription or places a medication orderPrescribing provider / EHRDispensing at the pharmacy
MedicationDispenseA pharmacy fills or partially fills a prescriptionPharmacy systemMedication Administration Record (MAR)
MedicationAdministrationA nurse or automated system administers a doseNursing / MAR systemMedication reconciliation; billing
MedicationStatementA medication is reported — patient says they take it, or external record says soPatient / referring provider / care coordinatorMedication reconciliation; problem list context

The chain of custody: a MedicationRequest drives a MedicationDispense (linked via basedOn), which informs a MedicationAdministration. MedicationStatement stands apart — it is not part of the prescribe-dispense-administer chain because it does not imply that a prescription was written or that the medication was dispensed from a known pharmacy.

MedicationRequest

Use MedicationRequest when a clinician is ordering or prescribing a medication. This resource represents intent: “this patient should receive this medication.”

The intent field is required and determines the nature of the request:

Intent valueMeaning
proposalA suggestion — from a care plan or decision support; not yet ordered
planPart of a care plan; expected to be ordered at an appropriate time
orderA prescription or medication order — the standard clinical scenario
original-orderThe original order (when an order has been subsequently revised)
reflex-orderAutomatically generated in response to another order or result
filler-orderThe pharmacy’s interpretation of the order (less common in FHIR contexts)
instance-orderA specific administration instruction derived from the order
optionA choice among alternatives

For the standard “clinician prescribes medication” scenario, intent is order. For a care plan recommendation that has not yet been ordered, use proposal. Getting intent wrong causes receiving systems to misclassify the request — a proposal should not trigger pharmacy dispensing.

MedicationDispense

Use MedicationDispense when a pharmacy fills a prescription. This resource records what was actually dispensed — which may differ from what was prescribed (different quantity, substitution, partial fill).

basedOn links back to the MedicationRequest. If the dispense is not linked to a request — because the prescription came in on paper or via fax and was not captured as a FHIR resource — basedOn may be absent, but document this in your interface specification.

whenPrepared and whenHandedOver are distinct: preparation time vs the time the patient received the medication. Both matter for medication adherence tracking.

MedicationAdministration

Use MedicationAdministration when a dose was given in a clinical setting. This is the inpatient/infusion-center resource. It records that a specific dose was administered to a patient at a specific time by a specific practitioner.

Do not use MedicationAdministration for outpatient self-administration — there is no clinical record of that event. When a patient takes their home medication, you have a MedicationStatement, not a MedicationAdministration.

effective[x] records when administration occurred. Use effectiveDateTime for a point-in-time administration and effectivePeriod for an infusion or administration over a duration.

MedicationStatement

Use MedicationStatement for any reported medication: the patient says they take it, a referring provider documented it, an external record includes it, or a care coordinator collected it on admission. MedicationStatement does not imply that a prescription exists in your system or that the medication was dispensed from a known pharmacy.

The most common MedicationStatement error is using it for prescriptions. If a clinician is writing a new prescription, that is a MedicationRequest. MedicationStatement is for the medication history — what the patient was taking before they arrived, or what an external system reported.

informationSource identifies who reported the medication. This is clinically meaningful: a patient-reported medication history carries different reliability than a pharmacy claims feed.


JSON examples

MedicationRequest with structured dosage

{
  "resourceType": "MedicationRequest",
  "id": "rx-metformin-001",
  "status": "active",
  "intent": "order",
  "medicationCodeableConcept": {
    "coding": [
      {
        "system": "http://www.nlm.nih.gov/research/umls/rxnorm",
        "code": "861007",
        "display": "Metformin Hydrochloride 500 MG Oral Tablet"
      }
    ]
  },
  "subject": {
    "reference": "Patient/pat-001",
    "display": "John Smith"
  },
  "encounter": {
    "reference": "Encounter/enc-20231015"
  },
  "authoredOn": "2023-10-15",
  "requester": {
    "reference": "Practitioner/pract-jones",
    "display": "Dr. Sarah Jones"
  },
  "dosageInstruction": [
    {
      "text": "Take 1 tablet by mouth twice daily with meals",
      "timing": {
        "repeat": {
          "frequency": 2,
          "period": 1,
          "periodUnit": "d",
          "when": ["MORN", "EVE"]
        }
      },
      "route": {
        "coding": [
          {
            "system": "http://snomed.info/sct",
            "code": "26643006",
            "display": "Oral route"
          }
        ]
      },
      "doseAndRate": [
        {
          "type": {
            "coding": [
              {
                "system": "http://terminology.hl7.org/CodeSystem/dose-rate-type",
                "code": "ordered"
              }
            ]
          },
          "doseQuantity": {
            "value": 1,
            "unit": "tablet",
            "system": "http://terminology.hl7.org/CodeSystem/v3-orderableDrugForm",
            "code": "TAB"
          }
        }
      ]
    }
  ],
  "dispenseRequest": {
    "numberOfRepeatsAllowed": 5,
    "quantity": {
      "value": 60,
      "unit": "tablet"
    },
    "expectedSupplyDuration": {
      "value": 30,
      "unit": "days",
      "system": "http://unitsofmeasure.org",
      "code": "d"
    }
  },
  "substitution": {
    "allowedBoolean": true
  }
}

MedicationStatement for reported home medication

{
  "resourceType": "MedicationStatement",
  "id": "medstmt-lisinopril-001",
  "status": "active",
  "medicationCodeableConcept": {
    "coding": [
      {
        "system": "http://www.nlm.nih.gov/research/umls/rxnorm",
        "code": "314076",
        "display": "Lisinopril 10 MG Oral Tablet"
      }
    ]
  },
  "subject": {
    "reference": "Patient/pat-001"
  },
  "context": {
    "reference": "Encounter/enc-20231015"
  },
  "effectivePeriod": {
    "start": "2021-06-01"
  },
  "dateAsserted": "2023-10-15",
  "informationSource": {
    "reference": "Patient/pat-001",
    "display": "John Smith (self-reported)"
  },
  "dosage": [
    {
      "text": "10mg once daily",
      "timing": {
        "repeat": {
          "frequency": 1,
          "period": 1,
          "periodUnit": "d"
        }
      },
      "doseAndRate": [
        {
          "doseQuantity": {
            "value": 10,
            "unit": "mg",
            "system": "http://unitsofmeasure.org",
            "code": "mg"
          }
        }
      ]
    }
  ]
}

Coding systems by jurisdiction

JurisdictionPreferred SystemCode Level for PrescribingCode Level for DispensingSystem URI
United StatesRxNormSCD or SBDNDChttp://www.nlm.nih.gov/research/umls/rxnorm
United Kingdomdm+dVMP (generic) or AMP (brand)AMPhttps://dmd.nhs.uk
AustraliaAMTMPP (medicinal product pack)MPUU or TPUhttp://snomed.info/sct (AMT is a SNOMED extension)
New ZealandNZMTMP (medicinal product)MPUU or TPUhttp://nzmt.org.nz

For US implementations, use SCD (Semantic Clinical Drug) codes for MedicationRequest — they encode ingredient, strength, and dose form, which is exactly what a prescription needs. NDC codes are appropriate in MedicationDispense because they identify the specific packaged product that was dispensed. Using NDC in MedicationRequest is incorrect: NDC codes change when manufacturers reformulate products or change package sizes, making historical medication records unreliable.


The medication[x] decision

FHIR medication resources accept the medication as either an inline medicationCodeableConcept or a reference to a separate Medication resource (medicationReference). This is the medication[x] pattern.

Use medicationCodeableConcept when the medication is fully and unambiguously described by a standard code (RxNorm SCD or SBD). This covers the large majority of commercial medications. It is simpler, requires fewer resources, and is what US Core expects.

Use medicationReference (with a separate Medication resource) when:

  • The medication is a custom compound not representable by a standard code
  • The formulation requires detailed ingredient information
  • Multiple resources reference the same non-standard medication and you want to avoid duplication

The US Core MedicationRequest profile allows both options. Receiving systems must handle both. Do not assume medicationCodeableConcept will always be present — a server that returns medicationReference is compliant.


US Core medication profiles

US Core v6 and later defines profiles for MedicationRequest (required for US FHIR APIs). Key constraints:

  • status is required; must be a value from the MedicationRequest status value set
  • intent is required; must be one of the defined intent codes
  • medication[x] is required; RxNorm coding is expected for US implementations
  • subject is required; must reference a Patient
  • requester is required
  • authoredOn is required

Failing to populate any required element causes US Core validation to fail. Servers must also support search by patient, status, and intent.


Dosage instruction complexity

The dosageInstruction element is where most implementations cut corners. The most common shortcut: providing only dosageInstruction.text without structured timing.

A receiving system cannot act on "Take twice daily" as a string. It cannot:

  • Verify administration timing against the MAR
  • Trigger PRN alerts when a dose is due
  • Check against maximum dose-per-period rules
  • Interface with automated dispensing cabinet software

Structured dosage is not optional if downstream systems need to act on it. Populate both text (required by US Core for human readability) and the structured elements.

Key dosage elements

ElementTypeExample
timing.repeat.frequencyInteger2 (twice)
timing.repeat.periodDecimal1 (per…)
timing.repeat.periodUnitCode (UCUM)d (day)
timing.repeat.whenCode list["MORN", "EVE"]
timing.repeat.offsetMinutes30 (30 minutes before/after event)
doseAndRate.doseQuantityQuantity{value: 500, unit: "mg"}
doseAndRate.doseRangeRange{low: 250mg, high: 500mg} — for variable dosing
routeCodeableConceptSNOMED oral route code
asNeededBooleanBooleantrue for PRN
maxDosePerPeriodRatio{numerator: 2000mg, denominator: 1 day}

If the source system only provides free text and structured dosage is needed downstream, a human review or NLP step is required. Document this gap in the interface specification and do not silently truncate dosage data.


Substitution

MedicationRequest.substitution tells the pharmacy whether generic substitution is permitted. Omitting this element when dispensing information matters is an interface error — the pharmacy may either default to allowing substitution or reject the request for missing required information.

  • substitution.allowedBoolean: true = generic substitution allowed; false = dispense as written
  • substitution.allowedCodeableConcept: for more granular control (e.g., allowed for therapeutic class but not formulation)

Always populate substitution in MedicationRequest resources that will be sent to a pharmacy system.


Medication reconciliation patterns

Medication reconciliation on hospital admission involves collecting medication history from multiple sources, resolving conflicts, and producing a verified current medication list. The FHIR pattern:

  1. Collect MedicationStatements from multiple sources:
    • Patient self-report (informationSource = Patient)
    • Pharmacy claims feed (informationSource = Organisation — pharmacy or PBM)
    • Referring provider summary (informationSource = Practitioner or Organisation)
    • Previous encounter records (informationSource = Encounter)
  2. Present conflicting records to the clinician for review
  3. Clinician reconciles: confirms, modifies, or discontinues each medication
  4. Confirmed, active medications become MedicationRequests (with intent = order or plan)
  5. Discontinued medications: set status = stopped on the MedicationRequest or MedicationStatement

The reconciliation event itself can be documented as a clinical note or as a Composition resource referencing the reconciled medication list.


Cross-system medication exchange

When sending a MedicationRequest to a pharmacy system, the Patient reference must be resolvable by the receiving system. This is the same identifier problem described in patient matching: if your Patient resource carries an MRN as its only identifier, and the pharmacy does not know your MRN namespace, the pharmacy cannot look up the patient.

For cross-organisation medication exchange:

  • Include multiple Patient identifiers (MRN with system URI, insurance ID, and optionally SSN last 4)
  • Confirm with the receiving system which identifier they use for patient lookup
  • If using a medication order network (Surescripts/NewRx for e-prescribing), follow that network’s patient identifier requirements — which are separate from FHIR conventions

Common mistakes

Using MedicationRequest for reported medication history. If the clinician is documenting what the patient was taking at home, use MedicationStatement. MedicationRequest implies an order was placed; MedicationStatement implies it was reported.

Using MedicationStatement for a new prescription. If the clinician is writing a new prescription, that is a MedicationRequest with intent = order. MedicationStatement does not drive dispensing.

Omitting intent on MedicationRequest. It is a required field. A MedicationRequest without intent fails US Core validation and may be interpreted incorrectly by receiving systems.

Omitting status. Every medication resource has a required status. A resource without status is invalid and unusable by downstream systems for filtering active vs discontinued medications.

Providing only dosageInstruction.text. String dosage is human-readable; it is not machine-actionable. If downstream systems need to act on dosage timing, populate the structured elements.

Using NDC codes in MedicationRequest. NDC is a dispensing identifier, not a prescribing identifier. Use RxNorm SCD or SBD for prescriptions.

Missing substitution when sending to pharmacy. The pharmacy needs substitution instructions. Omitting it produces ambiguity that different pharmacy systems resolve differently — not safely.

Not populating authoredOn. Receiving systems use this to determine currency of the order. Without it, medication reconciliation systems cannot determine whether a prescription is recent or years old.

Section: interop Content Type: pattern Audience: technical
Interoperability Level:
Semantic
Published: 05/10/2023 Modified: 01/02/2026 14 min read
Keywords: MedicationRequest MedicationDispense MedicationAdministration MedicationStatement RxNorm medication exchange FHIR medications dosage instruction medication reconciliation US Core
Sources: