Capability · Drug search

Search 610,367 drugs, one query.

Trigram full-text search across 19 jurisdictions — filter by country and ATC, get back the canonical product with reimbursement, dispensing and freshness metadata.

GET /api/v1/drugs

What you get

Built for production drug data

Point GET /api/v1/drugs at the catalog and search by name, brand or substance with a typo-tolerant trigram index. Narrow with country (ISO-2) and atc (prefix), page with limit — the same surface serves a CH pharmacy lookup and an EU formulary import.

Every result is the canonical, deduplicated product, not a raw register row: ATC code, manufacturer, dispensing category, reimbursement flag and the watchtower freshness fields travel with each hit.

Search

Typo-tolerant trigram match

q runs against a Postgres trigram index over product, brand and substance names, so "ibuprofien" still finds ibuprofen and partial brand names rank sensibly.
Filters

Country + ATC scoping

country pins the jurisdiction (CH, DE, FR, IT, US, …) and atc accepts any prefix — pass M01 to sweep every NSAID under the node, M01AE01 for one substance.
Canonical

Deduplicated products

Multiple registers describing the same pack collapse to one canonical drug with a stable id you can store; the _meta.sources array tells you which registers backed it.
Freshness

last_synced_at on every row

Each result carries last_synced_at and the source schema_state, so you can show — or gate on — how fresh the underlying register data is.

Try it

A real call, end to end

A single GET with q, country and limit returns ranked canonical products. Filter by ATC prefix with &atc=.

GET /api/v1/drugs?country=CH&q=aspirin
curl 'https://drug-database.com/api/v1/drugs\
?country=CH&q=aspirin&limit=2' \
  -H 'Authorization: Bearer dd_live_…'
response
{
  "results": [
    {
      "id": "3f8a1c2d-1b4e-4c7a-9d2f-0a1b2c3d4e5f",
      "product_name": "Aspirin Cardio 100 mg",
      "atc_code": "B01AC06",
      "manufacturer": "Bayer (Schweiz) AG",
      "dispensing_cat": "B",
      "is_reimbursed": true,
      "country_code": "CH",
      "last_synced_at": "2026-06-27T02:14:00Z"
    }
  ],
  "_meta": { "sources": ["bag_sl", "aips", "oddb", "atc"] }
}

Coverage & freshness

  • 610,367 canonical drugs across 19 jurisdictions, aggregated from 30+ public registers.
  • Switzerland is first-class: BAG-SL reimbursement, Swissmedic dispensing category and Pharmacode on CH rows.
  • Every response carries last_synced_at and schema_state; stale sources are frozen, never silently served as current.
  • Results are ETag-cached and revalidatable through the changes feed.
Good to know
  • · Search needs the drugs:read scope.
  • · Default limit is 20, max 100; deep pagination uses a cursor — see the docs.

FAQ

Common questions

610,367 canonical products across 19 jurisdictions, aggregated from more than 30 public registers and deduplicated into one catalog. The count grows as new sources are ingested.
q runs against a Postgres trigram index over product, brand and substance names, so it tolerates typos and partial words. Results are ranked by trigram similarity, with exact prefix matches first.
Yes. Pass country with an ISO-2 code (CH, DE, FR, IT, US, …) to scope the search to one jurisdiction. Omit it to search the full multi-jurisdiction catalog.
Pass atc with any prefix of a WHO ATC code. atc=M01 sweeps every product in that anatomical group; atc=M01AE01 narrows to a single substance. Combine it with q and country.
Every result carries last_synced_at and the source schema_state. The ingestion watchtower freezes a source if its upstream schema drifts, so a stale register is reported as stale rather than served as if current.

Ready when you are

Put drug search in production this afternoon.

Spin up a key in minutes. The free tier covers prototyping and low-volume production.

Free tier · 100 requests/day · No card required