Skip to main content
POST /v1/med-lists/from-documents accepts one or more clinical PDFs for a single patient and returns the same kind of deduplicated medication list you’d get from /v1/medications/infer — but driven by the document text instead of structured FHIR. Use it when your input is what the patient or referring clinic actually sends: a faxed referral packet, an Epic-rendered discharge summary, a printed After-Visit Summary, or a stack of progress notes. We pull the medication mentions from each document, reconcile them across the packet, and return one entry per drug with the page / text-snippet evidence it was inferred from.

Try it in the playground

Upload your own clinical PDFs — or run a pre-loaded sample — and see the deduplicated med list right in your browser. Pick “PDFs” under “Source data”. Uploaded files go straight to the API and are never stored.

API key

Same Bearer key that powers /v1/medications/infer. No separate setup.

Quickstart

1

Get an API key

Same flow as the FHIR endpoint — see Authentication.
2

POST your PDFs as multipart/form-data

Each file goes under the files form field. Repeat files=@… for every PDF in the packet.
Don’t set Content-Type: multipart/form-data manually — let your HTTP client compute the boundary. Setting the header by hand drops the boundary and the request fails validation.
3

Read the response

The H&P referenced the brand Pen-Vee K and the others used the generic Penicillin V Potassium — all three collapse into one entry, with each mention preserved as a sources[] item.

How dedup works

A medication mentioned in three documents becomes one entry in medications with three items in sources[]. Cross-document reconciliation matches by canonical drug name (brand → generic where applicable), so:
  • Lipitor in one doc and Atorvastatin in another → one Atorvastatin entry
  • The same med in 5 of 8 progress notes → one entry, 5 sources
  • Differing doses across docs → the reconciler picks the one from the most authoritative section (Discharge > Active/Current > Home/Outpatient > MAR > others)

Response shape

The body contains only medications. Cross-cutting metadata lives in response headers: Each entry in medications[] is an ExtractedMedication: Each ingredients[] item: Each sources[] item: Order of medications[]: by section recency of each med’s canonical mention (Discharge > Active/Current > …), then alphabetically by drug_name.

More worked examples

The single-ingredient case above (Penicillin V) covers the basic shape. Two more shapes worth seeing — combo products and packs.

Combo product (Bactrim)

Mentions of "Bactrim" across documents (sulfamethoxazole + trimethoprim) merge into one entry whose ingredients carry per-strength data straight from RxNorm:
Key behaviors:
  • dose_quantity / dose_unit are "1" / "tablet" because Bactrim’s dose form is countable — the patient takes one tablet at a time. The per-ingredient strengths sit on ingredients[].
  • Both ingredients surface with their RxNorm IN codes — that’s what you’d key off for drug-interaction or class-level allergy checks.

Branded pack (Trinessa-style BPCK)

A 28-day contraceptive pack with 4 different pills across the cycle is one medication (one BPCK), not four:
Key behaviors:
  • drug_name is the patient-recognizable short form, not the verbose RxNorm canonical that enumerates every pill. RxNorm’s canonical {7 (...) / 7 (...) / 7 (...) / 7 (inert ingredients ...) } Pack [Trinessa 28 Day] is unusable as a display string; we extract the brand annotation.
  • dose_quantity / dose_unit are null. A pack contains different pills on different days, so there’s no single “one thing per dose” summary.
  • ingredients[] walks through the pack’s component pills to surface every active ingredient. Strengths reflect what’s in each active pill.
  • rxnorm_tty: BPCK is the signal that this entry represents a pack — treat it differently from an SCD if your downstream logic cares.
For a deeper walkthrough of every field and how to interpret them clinically, see Understanding the PDF output.

Limits

Larger packets should be split into multiple calls today. Server-side batching for very large packets is on the roadmap.

Errors

Same error envelope and retry semantics as the rest of /v1/* — see Errors. Endpoint-specific 422 details: 503 here generally means the upstream OCR service was briefly unavailable or has not been configured. Retry with backoff.

Differences from /v1/medications/infer

Both endpoints share authentication, organization scoping, and rate-limit counters. You can build a single integration that uses whichever shape your upstream system happens to produce.