CH · EU · US — worldwide drug data, public-source

One JSON API for
every drug — worldwide.

Every drug, one API. CH · EU · US — 28 public sources across 13 jurisdictions, staged, schema-validated, diff-tracked. REST + GraphQL + MCP, with a watchtower that catches upstream schema drift before you ship.

28curated public sourcesCH · EU · US · WHO · EMA
13jurisdictionsCH + 11 EU + US
24hschema-drift SLA
ingestion · live
run_id 8a3f
BAG-SL13,142 rows · CSV
promoted
AIPS11,891 monographs · XML
promoted
EPha48,304 pairs · JSON
promoted
oddb.org22,710 codes · CSV
quarantined
WHO ATC6,418 codes · CSV
promoted
4/5 promotedlast_synced 2 min ago

API Surfaces

Three shapes, one Postgres.

Same data, three transports. Pick the one your runtime speaks — REST for HTTP clients, GraphQL for one-round-trip dashboards, MCP for AI IDEs and agents.

REST

GET /v1/drugs

Typeahead, lookup, monographs, interactions, changes.

Trigram search across product names, ATC prefixes, and identifier resolution from NDC, CIP-13, GTIN, Pharmacode, RxCUI, UNII, dm+d AMPPID, and Swissmedic-No. ETag + Cache-Control on every stable resource. Cursor-paginated change feed for cache invalidation.

Operations
GET /v1/drugsGET /v1/drugs/:idPOST /v1/interactions/checkGET /v1/changes

GraphQL

POST /v1/graphql

One round-trip for drug + ATC + interactions.

Multi-region drug-catalogue queries are read-heavy and varied — "resolve NDC → drug, CIP-13 → drug, GTIN → drug, then ATC parents + interactions with my current med list" wants one query, not five. Persisted-query path on Growth+ for high-volume clients.

Operations
drug(id)drugByCode(system, code)interactionsWith(drugs)changes(since)

MCP

npx @medisuisse/mcp-server

Native tools for Claude, Cursor, Windsurf.

A thin TypeScript MCP server. Schema definitions and an HTTP shim only — no curated data lives in the npm tarball. Free tools: search, ATC lookup, schema docs. Gated: get_drug, check_interactions, validate_prescription.

Operations
search_drugatc_lookupget_drugcheck_interactionsvalidate_prescription

The Watchtower

The moat is the pipeline, not the data.

28 sources across 13 jurisdictions — FDA NDC, DailyMed, RxNorm, dm+d, CIMA, BDPM, AIFA, BAG-SL, AIPS, EPha, EMA SPOR and more — drift upstream without notice. Every consumer rediscovers the breakage individually, usually weeks late, usually after a customer complaint. We catch it at staging.

raw01
sources/raw/{source}/{run_id}
pull, retain 12 months
staging02
{source}_staging
typed staging table
validation03
schema validate
XSD · JSON-schema · regex
promotion04
drugs · interactions · atc
production read path

Pinned schemas

Per-source assertions across all 28 feeds — BAG-SL column checks, AIPS / dm+d / CIMA XSD, EPha / FDA NDC / DailyMed JSON-schema, oddb and RxNorm per-column regex. Failed rows land in a per-source quarantine; promotion is blocked above a 1% fail-rate.

Drift alerts

A run flagged `schema_drift` keeps the last-good snapshot in production, fires PagerDuty + Slack, and surfaces `schema_state: "stale"` in every API response so customers know before they ship a broken refill.

Diff-based change feed

Every promoted row writes a row to `changes` (before, after, source, occurred_at). Subscribe via webhook or `GET /v1/changes?since=...` — most-requested feature from EHR vendors.

Stale-data honesty

Every response carries `_meta.last_synced_at` and `schema_state` per source. The previous good snapshot is still served, but flagged. Silent shipping of broken data is the failure mode this exists to prevent.

In every response_meta
{
  "drug": { ... },
  "_meta": {
    "ndc":    { "last_synced_at": "2026-05-30T04:00:00Z", "schema_state": "ok" },
    "dmd":    { "last_synced_at": "2026-05-29T02:00:00Z", "schema_state": "ok" },
    "cima":   { "last_synced_at": "2026-05-30T03:00:00Z", "schema_state": "ok" },
    "bag_sl": { "last_synced_at": "2026-05-15T05:01:00Z", "schema_state": "ok" },
    "aips":   { "last_synced_at": "2026-05-26T05:00:00Z", "schema_state": "ok" },
    "epha":   { "last_synced_at": "2026-05-25T03:00:00Z",
                "schema_state": "stale", "reason": "schema_drift_2026-05-29" }
  }
}

Platform

Built for worldwide drug data.

ATC normalisation, cross-jurisdictional identifier bridges (NDC, dm+d, CIP-13, GTIN, Pharmacode, PZN, AIC), reimbursement tiers, and indication codes — what HCI, Vidal, Rote Liste, BNF, and USP-NF each charge separately, unified in one JSON shape with sane DX.

Identifier resolver

NDC ↔ RxCUI ↔ UNII ↔ dm+d AMPPID ↔ CIP-13 ↔ PZN ↔ AIC ↔ GTIN ↔ Pharmacode ↔ Swissmedic-No ↔ ATC. One indexed read on `/v1/drugs/lookup` for every dispense flow, every jurisdiction.

ATC-pair interactions

EPha-style severity (contraindicated · severe · moderate · minor · info), mechanism, recommendation. Lexicographically-sorted pairs, cross-jurisdictional by construction.

Change feed webhooks

Subscribe to "what changed across NDC, dm+d, CIMA, BAG-SL this week" via webhook on Growth+, or cursor-paginate `GET /v1/changes?since=...` yourself.

Raw upstream preserved

`drugs.payload` carries the raw upstream fields from every source. When a customer asks "why is this strength 200 mg/ml and not 0.2 g/ml?", we have the answer without re-fetching.

BYOL passthrough

A customer who already licences a paid catalogue — HCI, Vidal, Rote Liste, ABDA, BNF, RxNorm-paid extensions, USP-NF, KNMP G-Standaard — can supply their own credentials. Per-tenant only, never cached cross-tenant. We never become a reseller.

PHI-safe by default

`/drugs` and `/interactions/check` do not touch PHI and need no DPA. `/prescriptions/validate` accepts bucketed context only (age band, eGFR band, pregnancy) and routes through PHI Gateway.

MCP server

Native in Claude, Cursor, Windsurf.

Drop @medisuisse/mcp-server into your editor and the AI resolver becomes us — not a tab switch to a national compendium. Free tier covers search, ATC tree, and schema docs. Paid tier unlocks full drug records, interactions, and prescription validation.

claude_desktop_config.json
{
  "mcpServers": {
    "drugcatalog": {
      "command": "npx",
      "args": ["-y", "@medisuisse/mcp-server"],
      "env": {
        "MEDISUISSE_API_KEY": "ms_live_…",
        "PHI_GATEWAY_API_KEY": "phi_live_…"
      }
    }
  }
}

Positioning

Worldwide. Public-source. DX-first.

HCI, Vidal, Rote Liste, BNF, USP-NF, and G-Standaard are entrenched in their own jurisdictions. We won't out-cover any of them locally in year one. We win on worldwide coverage, developer ergonomics, and price.

Public-source-only, by choice

No paid-catalogue dependency on the read path

Our foundation is 28 public sources — FDA NDC, Orange Book, DailyMed, RxNorm, UNII, dm+d, CIMA, BDPM, AIFA, AIPS, BAG-SL, EPha, oddb, EMA SPOR, WHO ATC and more. HCI, Vidal, Rote Liste, ABDA, BNF, RxNorm-paid extensions, USP-NF, KNMP G-Standaard are explicitly excluded from the shared catalogue. Customers who already licence them can BYOL credentials per-tenant; we never resell.

Person-quarters, returned

Stop running 28 crons yourself

Every team that touches multi-jurisdiction drug data today writes the same 28 jobs: NDC weekly pull, DailyMed daily, RxNorm monthly, dm+d weekly, CIMA, BDPM, BAG-SL, AIPS XML parse, EPha normalize, oddb identifier bridge, EMA SPOR, WHO ATC, plus 16 more. Person-quarters of work, indefinite maintenance, and you still miss the schema drift. We run it, you call the API.

Pricing that scales with developers

Built for global DX, not enterprise procurement

Developer tier is free with 10k req/month. Starter at $99, Growth at $490 — generous on purpose. HCI, Vidal, Rote Liste, BNF, USP-NF, G-Standaard each charge tens of thousands per tenant per jurisdiction. The data we ship is mostly public; restricting access aggressively kills adoption, and adoption is the only durable defence against a global incumbent modernisation.