Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.medlistiq.com/llms.txt

Use this file to discover all available pages before exploring further.

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 / section / text-snippet evidence it was inferred from.

Try it in the playground

Pre-loaded sample PDFs you can post in one click. Swap “Source data” to “PDFs” once you’re in.

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.
curl -X POST https://api.medlistiq.com/v1/med-lists/from-documents \
  -H 'Authorization: Bearer ml_YOUR_KEY' \
  -F 'files=@discharge_summary.pdf' \
  -F 'files=@h_and_p.pdf' \
  -F 'files=@referral_note.pdf'
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

{
  "medications": [
    {
      "display": "Penicillin V Potassium 250 mg PO",
      "drug_name": "Penicillin V Potassium",
      "rxnorm_code": "203195",
      "rxnorm_system": "http://www.nlm.nih.gov/research/umls/rxnorm",
      "dose": "250 mg",
      "route": "PO",
      "frequency": null,
      "status": "active",
      "status_conflict": true,
      "sources": [
        {
          "document_name": "h_and_p.pdf",
          "page": 1,
          "section": "Medications",
          "evidence_text": "Pen-Vee K 250 MG Oral Tablet"
        },
        {
          "document_name": "discharge_summary.pdf",
          "page": 1,
          "section": "Medications",
          "evidence_text": "Penicillin V Potassium 500 MG Oral Tablet"
        },
        {
          "document_name": "referral_note.pdf",
          "page": 1,
          "section": "Medications",
          "evidence_text": "STOPPED: Penicillin V Potassium 250 MG Oral Tablet"
        }
      ]
    }
  ]
}
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. The referral marked the med STOPPED:, which raised status_conflict: true for downstream review.

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)
status_conflict: true flags meds whose source documents disagreed on state (e.g. one says active, another says stopped). MVP surfaces the conflict but does not auto-resolve it — clients should review manually.

Response shape

The body contains only medications. Cross-cutting metadata lives in response headers:
HeaderMeaning
x-request-idUUID for support tickets / log lookup
x-document-countNumber of PDFs in the request
x-total-page-countTotal pages across all PDFs after parsing
x-output-medication-countlen(medications) — same as the body field
x-processing-time-msEnd-to-end latency on our side
x-ruleset-versionVersioned tag of the extraction logic that ran
Each entry in medications[] is an ExtractedMedication:
FieldTypeNotes
displaystringHuman-readable composite (drug + dose + route + frequency).
drug_namestringCanonical name; brand → generic when a mapping exists. Use as the dedup key on your side.
rxnorm_codestring | nullRxCUI from RxNorm. null when no match.
rxnorm_systemstring | nullConstant URI; present iff rxnorm_code is.
dosestring | nullDose as parsed (e.g. "500 mg").
routestring | nullNormalized route abbreviation (PO, IV, IM, SC, INH, TOP, …).
frequencystring | nullNormalized frequency (BID, TID, QHS, PRN, Q6H, …).
statusstring"active", "stopped", or "unknown". Driven by the section heading the canonical mention was found under.
status_conflictbooltrue when sources disagreed.
sources[]arrayOne item per detected mention. See below.
Each sources[] item:
FieldTypeNotes
document_namestringFilename you submitted (discharge_summary.pdf).
pageint1-indexed page within that PDF.
sectionstring | nullDetected section heading ("Discharge Medications", "Active Medications", …) or null if none was identified.
evidence_textstringThe raw line of text where the mention was matched.
Order of medications[]: by section recency of each med’s canonical mention (Discharge > Active/Current > …), then alphabetically by drug_name.

Limits

LimitValueWhat happens past it
Files per request15422 validation error
Bytes per file50 MB422
Total bytes per request150 MB422
Total pages per request200422 (during processing)
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:
DetailCause
at least one file is requiredEmpty multipart body — no files field at all.
every file must have a filenameA files part was uploaded with no filename.
too many files: max 15 per request (received N)More than 15 PDFs.
file 'X' must be application/pdf (got image/png)Wrong Content-Type on a files part.
file 'X' does not look like a PDF (missing %PDF- header)Bytes don’t start with %PDF-. Catches renamed .txt/.docx.
file 'X' is N bytes; max per file is 52428800 bytesSingle file over 50 MB.
total upload size exceeds 157286400 bytes across all filesCombined upload over 150 MB.
payload exceeds 200-page synchronous limit; async mode coming laterTotal page count too large.
503 here generally means the upstream OCR service was briefly unavailable or has not been configured. Retry with backoff.

Differences from /v1/medications/infer

/v1/medications/infer/v1/med-lists/from-documents
InputFHIR resources (JSON body)PDF files (multipart)
Status vocabularyactive / completed / stopped / cancelled / unknownactive / stopped / unknown
Confidence scorePer-medication floatNot yet — confidence work in progress
Provenanceprovenance[med_id] keyed by med ID, with rule-trace evidencesources[] per medication, with page + section + text-snippet evidence
Verbosity / format selectorsverbosity × formatNone — single response shape
Latency~200 ms typicalSeveral seconds (page-bound)
Rate limit cost1 unitHigher per-page; see plan limits
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.