AnpherosAnpheros PlatformDevelopers

Medication data for apps and AI agents

Patient medication lists vs drug knowledge: FHIR resources, RxNorm, ATC, openFDA and EMA sources, and a tested join of a FHIR record with RxNorm and FDA labels.

Healthcare software needs two different kinds of medication data: the patient's medication list — what this person takes, since when, at what dose, who recorded it — and drug knowledge — what a product contains, its official label, warnings and interactions. The first belongs in the patient's record; the second comes from authoritative drug databases. Mixing them up is how AI agents end up stating drug facts from model memory. This page explains both, the FHIR R4 resources and code systems involved, which public sources exist in the US and the EU, and a working example that joins a patient's list from a FHIR record with RxNorm and the FDA label.

Two kinds of medication data

Patient medication list Drug knowledge
Answers What does Ana take, since when, how often? What is metformin 500 mg, what does its label warn about?
Changes When the patient or a clinician updates it When a regulator or publisher updates it
Lives in The patient's record (EHR, PHR, FHIR server) Drug databases and terminologies
FHIR MedicationStatement, MedicationRequest, MedicationAdministration, Medication Mostly outside the record; product information can itself be FHIR
Who may read it Only with the patient's consent Public or licensed

An app or agent that answers "can I take ibuprofen with my blood pressure pill?" needs both: the patient's list to know which pill, and a drug knowledge source to know what is known about the combination — plus a clinician or pharmacist for the answer.

FHIR resources for the medication list

The medicine is coded: in the US with RxNorm (from the National Library of Medicine) and NDC product codes; internationally with the WHO ATC classification; in Europe also with national product codes and, increasingly, the EMA's FHIR-based electronic product information. A statement can carry several codings for the same medicine.

Drug knowledge sources

United States

European Union

Interactions are the hardest part. NLM retired its drug-drug interaction API around January 2024, and comprehensive interaction checking today relies on licensed clinical knowledge bases. A label's interactions section is text written for clinicians, not a checker.

Joining the record with drug knowledge

The example reads a patient's active medications from Anpheros, resolves each name to an RxNorm concept and fetches the FDA label. It was run against a local instance of the platform and the live RxNorm and openFDA APIs.

import { Anpheros, apiKey } from '@anpheros/sdk';

const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) });

// 1. What the person takes: from their record (ATC codes, names as they were entered)
const { data: meds } = await anpheros.medications.list(patientId, { status: 'active' });

// 2. What each medicine is: RxNorm (US National Library of Medicine), free, no key
async function rxcui(name: string): Promise<string | null> {
  const r = await fetch(`https://rxnav.nlm.nih.gov/REST/approximateTerm.json?term=${encodeURIComponent(name)}&maxEntries=1`);
  const j: any = await r.json();
  const id = j.approximateGroup?.candidate?.[0]?.rxcui;
  if (!id) return null;
  // An approximate match can be an outdated concept: keep it only if RxNorm still describes it as a drug
  const props: any = await (await fetch(`https://rxnav.nlm.nih.gov/REST/rxcui/${id}/properties.json`)).json();
  return ['SCD', 'SBD', 'GPCK', 'BPCK'].includes(props.properties?.tty) ? id : null;
}

// 3. What the official label says: openFDA drug label API (US FDA), free
async function label(id: string) {
  const r = await fetch(`https://api.fda.gov/drug/label.json?search=openfda.rxcui:%22${id}%22&limit=1`);
  if (!r.ok) return null;
  const doc: any = (await r.json()).results?.[0];
  return doc && { set_id: doc.set_id, boxed_warning: doc.boxed_warning?.[0]?.slice(0, 120), has_interactions_section: !!doc.drug_interactions };
}

for (const m of meds) {
  const id = await rxcui(m.display);
  console.log(JSON.stringify({ record: { display: m.display, atc: m.code, dosage: m.dosage }, rxnorm: id, fda_label: id ? await label(id) : null }));
}

Output for a patient who reported metformin and enalapril:

{"record":{"display":"Metformin 500 mg tablet","atc":"A10BA02","dosage":"500 mg twice a day"},"rxnorm":"861007",
 "fda_label":{"set_id":"011de1a5-…","boxed_warning":"BOXED WARNING WARNING: LACTIC ACIDOSIS …","has_interactions_section":true}}
{"record":{"display":"Enalapril maleate 10 mg oral tablet","atc":"C09AA02","dosage":"10 mg once a day"},"rxnorm":"858817",
 "fda_label":{"set_id":"074fe718-…","boxed_warning":"WARNING: FETAL TOXICITY …","has_interactions_section":true}}

What we learned running it. With the name written as "Enalapril 10 mg tablet", RxNorm's approximate match returned RXCUI 328290, a concept RxNorm no longer describes, with no label behind it. With the full clinical name, "enalapril maleate 10 mg oral tablet", it returned 858817, a current clinical drug with a label. Names typed by people are approximate; check what a match resolves to, store the code once it is confirmed, and show the person what was matched.

Rules for AI agents

  1. Never let the model supply drug facts from memory. Give it the patient's list from the record and the relevant text from an authoritative source, and ask it to cite them.
  2. Keep the two sources visible. "You take metformin (your record, entered by you on 3 March)" and "the FDA label warns about lactic acidosis (label set 011de1a5…)" are different claims with different owners.
  3. Narrow scopes. An agent that only needs the medication list should get read access to MedicationStatement, not the whole record. With Anpheros that is a consent scope or the MCP server's read-only tools.
  4. Do not answer what needs a clinician. Interactions, dose changes and stopping a medicine go to a pharmacist or doctor; the agent can prepare the question.

Where Anpheros fits

Anpheros stores the medication list: MedicationStatement and MedicationAdministration with ATC or other codes, who recorded each item, history, and consent for other apps; the context API includes active medications in the summary it prepares for a model, and the MCP server exposes them to agents read-only. It bundles a small ATC subset (about 50 common medicines) to name codes automatically; any other code is accepted, without an automatic name.

It is not a drug database: it does not provide labels, interactions, dosing or contraindications, and it does not support MedicationRequest or Medication resources today.

Frequently asked questions

Which FHIR resource should a medication list use?

MedicationStatement for what a person takes or took, including patient-reported medicines. Prescriptions are MedicationRequest; individual doses are MedicationAdministration.

Is there a free drug database API?

In the US, RxNorm (NLM) for drug identifiers and names, and openFDA for official product labels, are free. In Europe, EMA and national agencies publish product information. Comprehensive interaction checking generally needs a licensed knowledge base.

How should an AI agent get medication information?

From two tools: one that reads the patient's medication list from their record with consent, and one that looks up an authoritative drug source. The agent should cite both and leave clinical decisions to a professional.

Does Anpheros check drug interactions?

No. It stores what a person takes, with provenance and consent. Interaction checking belongs to a drug knowledge source and a clinician.

Related