Drug formulary CSV import API
drug_formulary_v1
Import this template via API. Import a drug formulary from CSV. ATC-coded, GTIN-checksum-validated, Pharmacode-aware, emits FHIR Medication.
30-second curl
curl -X POST https://api.adaptivmapr.com/v1/uploads \ -H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \ -F "template=drug_formulary_v1" \ -F "file=@your_data.csv"
At a glance
- Pack
- Healthcare
- FHIR resource
- Medication
- Risk level
- medium
- Fields
- 6 (2 required, 3 validated)
Why this template?
The Drug formulary template is the canonical schema for a pharmacy's medication catalog. Each row emits a FHIR Medication resource — the ATC code lands in Medication.code with the WHO ATC coding system, the GTIN goes into Medication.identifier with the GS1 system URI, and the Swiss Pharmacode (4-7 digits) carries the local registry id. The template is `medium` risk not because it contains PHI — drugs are not patients — but because dosage-form and strength errors are downstream-dangerous; a transposed digit in a strength column produces a 100x dose error in the resulting prescription system. AdaptivMapr validates ATC against the published pattern (^[A-Z]NN[A-Z]{2}NN$), GTIN against the GS1 mod-10 checksum, and Pharmacode against the 4-7 digit shape. Customers use this template when seeding an e-prescribing system, when standardising an in-house pharmacy database, or when re-importing after a vendor migration.
GTIN supports 8 / 12 / 13 / 14 digit shapes (EAN-8, UPC-A, EAN-13, GTIN-14) with mod-10 checksum verification — the same algorithm as ITF-14 barcodes. ATC five-level codes (anatomical → therapeutic → pharmacological → chemical → substance) all validate against the same regex. Pharmacode is Swiss-specific and not enforced as a checksum because the algorithm is proprietary.
Migration scenarios & common foreign headers
Migration scenarios for the Drug formulary: seeding a new e-prescribing module with a clinic's in-house formulary, importing a hospital pharmacy's catalogue after a procurement-system switch, quarterly refreshes against Swissmedic / EMA / FDA bulletins, and consolidating multiple regional formularies after a healthcare-network acquisition. Foreign headers we routinely see: "ATC / Wirkstoffcode / Code ATC / GTIN / EAN / Barcode / Codice / Pharmacode / Pharma-Code / Präparat / Préparation / Medicamento / Farmaco / Darreichungsform / Forme galénique / Forma farmacéutica / Stärke / Dosage / Dosis". Trade names rarely match ATC patterns directly, so the resolver layer carries weight on this template — most imports rely on the high-confidence trade-name → ATC fallback to clear without manual intervention.
Schema
The canonical column set, with the type each row carries, whether it is required, the field-level validators that fire on commit, and the multilingual header hints the cascade resolves against.
| Column | Type | Required | Validators | Hints |
|---|---|---|---|---|
| atc_code | string | yes | atc_code | atc · wirkstoffcode |
| gtin | string | — | gtin | gtin · ean · barcode |
| pharmacode | string | — | pharmacode | pharmacode · pharma-code |
| name | string | yes | — | präparat · préparation · medicamento |
| dosage_form | string | — | — | darreichungsform · forme galénique · forma |
| strength | string | — | — | stärke · dosage · dosis |
How AdaptivMapr maps your headers to this template
Five layers run in order, cheapest first. Layer 1 (Statistics) auto-accepts headers that have been mapped the same way across past uploads. Layer 2 (Heuristic) compares your header to the column name, the optional label, and every registered hint (DE / FR / IT / EN / ES) after a Unicode-and-punctuation-normalising pass. Layer 3 (Fuzzy) catches typos and reordered words. Layer 4 (Semantic) uses cached embeddings to catch the long tail of paraphrases. Layer 5 (LLM) only fires on genuinely ambiguous columns, constrained to the template’s allowed column set so it cannot invent a field. When a layer auto-accepts, the lower-cost layers below it never run — that is the cost lever.
REST · POST /v1/uploads
Pass the template_id; the cascade picks up the rest.
curl -X POST https://api.adaptivmapr.com/v1/uploads \ -H "Authorization: Bearer $ADAPTIVMAPR_API_KEY" \ -F "template=drug_formulary_v1" \ -F "file=@your_data.csv"
The canonical template definition is read-only at GET /v1/templates/drug_formulary_v1.
MCP · Cursor / Claude Desktop
Drop AdaptivMapr into your IDE. Schema-only calls are free and unlimited.
// In Cursor or Claude Desktop with the AdaptivMapr MCP server installed:
adaptivmapr.match_headers({
template: "drug_formulary_v1",
headers: ["atc_code", "gtin", "pharmacode", "name"]
})MCP install instructions →FAQ — Drug formulary CSV import
Does AdaptivMapr resolve trade names to ATC codes?
Yes — the ATC validator falls back to a resolver that maps trade names ("Aspirin", "Dafalgan") to ATC codes when the direct validator fails, and the substitution commits when confidence ≥ 0.85.
What about controlled-substance schedules?
Add a `schedule` field via a fork. The canonical template stays jurisdiction-neutral because controlled-substance lists differ per country.
Can I import a formulary with mixed CH (Pharmacode) and EU (GTIN) products?
Yes — Pharmacode and GTIN are both optional. The minimum is ATC + name; the rest enrich the row.
Are dosage_form and strength validated as free text?
Yes. The lexicon is too large and too localised to enum-bound; teams with strict downstream systems usually post-process these fields against an internal lookup.