DEV Community

Cover image for How to Add Drug Interaction Checking to Your Health App in 5 Minutes
Josh
Josh

Posted on

How to Add Drug Interaction Checking to Your Health App in 5 Minutes

Nearly 1 in 4 Americans takes a prescription drug alongside a dietary supplement. That's roughly 75 million people who might not know that their fish oil could be amplifying their blood thinner, or that their St. John's Wort is undermining their antidepressant.

If you're building a health app, a pharmacy tool, or any patient-facing software, drug interaction checking isn't a nice-to-have -- it's table stakes.

The problem is that getting reliable interaction data into your app has historically been painful.

The Problem: Separate Databases, None of Them Talk to Each Other

The US government maintains excellent drug and supplement data. It's authoritative, it's free, and it's scattered across separate systems with different formats:

  • openFDA (api.fda.gov) -- drug labels, NDC directory, drug-interaction label sections, adverse events
  • RxNorm (rxnav.nlm.nih.gov) -- drug naming and RxCUI identifiers
  • NIH ODS (ods.od.nih.gov) -- supplement fact sheets and interactions

Each API has its own conventions, its own data format, and its own quirks. RxNorm uses RxCUI identifiers. openFDA uses NDC codes. NIH supplement data comes in yet another format. To get a complete picture of a drug plus its supplement interactions, you need to cross-reference all of them.

Most teams either spend weeks building and maintaining their own integration layer, or they pay $500+/month for a commercial database license. Neither option is great for a side project, an MVP, or a startup trying to validate an idea.

MedData API: One Endpoint, All the Data

MedData API unifies these government databases into a single REST API. You get drug search, supplement lookup, and interaction checking through clean, consistent endpoints.

It's built by Anthesia and runs on the actual government data sources -- nothing is generated or inferred. Drug-drug interactions come from FDA structured product labels (openFDA) plus a curated set of major interactions; drug-supplement interactions come from the NIH.

Let me show you how it works.

Quick Start

You'll need an API key. The free tier gives you 250 requests/month, which is enough to test everything out.

  1. Go to the API docs
  2. Generate your API key via the /api/v1/billing/subscribe endpoint or contact support for a free-tier key
  3. Pass your key in the X-API-Key header on every request

All set. Let's write some code.

Example 1: Search for a Drug

Let's start simple -- search for "metformin" and get back structured data.

Python (httpx)

import httpx

API_KEY = "your_api_key_here"
BASE_URL = "https://meddata.anthesia.io"

async def search_drug(name: str):
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{BASE_URL}/api/v1/drugs/search",
            params={"name": name, "limit": 5},
            headers={"X-API-Key": API_KEY},
        )
        response.raise_for_status()
        data = response.json()

        for drug in data["results"]:
            print(f"{drug['brand_name']} ({drug['generic_name']})")
            print(f"  RxCUI: {drug['rxcui']}")
            print(f"  Maker: {drug['manufacturer']}")
            print()

        return data

# Run it
import asyncio
asyncio.run(search_drug("metformin"))
Enter fullscreen mode Exit fullscreen mode

JavaScript (fetch)

const API_KEY = "your_api_key_here";
const BASE_URL = "https://meddata.anthesia.io";

async function searchDrug(name) {
  const params = new URLSearchParams({ name, limit: "5" });
  const response = await fetch(
    `${BASE_URL}/api/v1/drugs/search?${params}`,
    { headers: { "X-API-Key": API_KEY } }
  );

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  const data = await response.json();

  for (const drug of data.results) {
    console.log(`${drug.brand_name} (${drug.generic_name})`);
    console.log(`  RxCUI: ${drug.rxcui}`);
    console.log(`  Maker: ${drug.manufacturer}`);
  }

  return data;
}

searchDrug("metformin");
Enter fullscreen mode Exit fullscreen mode

The response looks like this:

{
  "results": [
    {
      "rxcui": "6809",
      "brand_name": "Riomet",
      "generic_name": "METFORMIN HYDROCHLORIDE",
      "dosage_form": null,
      "strength": null,
      "manufacturer": "Sun Pharmaceutical Industries, Inc."
    }
  ],
  "total_count": 1,
  "query": "metformin"
}
Enter fullscreen mode Exit fullscreen mode

Heads up: dosage_form and strength aren't populated for every drug yet and can come back null. The reliably present fields are brand name, generic name, RxCUI, and manufacturer.

The API checks its local cache first (fast), then hits openFDA and RxNorm if needed (slower on first request, cached for subsequent calls).

Example 2: Check Warfarin + Supplement Interactions

This is where it gets interesting. Warfarin is one of the most interaction-prone drugs out there. Let's check it against a few supplements a patient might be taking.

Python

async def check_warfarin_supplements():
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"{BASE_URL}/api/v1/interactions/supplements",
            params={
                "drugs": "warfarin",
                "supplements": "Fish Oil,Vitamin D,St. John's Wort",
            },
            headers={"X-API-Key": API_KEY},
        )
        response.raise_for_status()
        data = response.json()

        print(f"Checked {data['item_count']} items")
        print(f"Found {len(data['interactions'])} interactions:\n")

        for interaction in data["interactions"]:
            print(f"  {interaction['item_1_name']} + {interaction['item_2_name']}")
            print(f"  Severity: {interaction['severity']}")
            print(f"  {interaction['description']}")
            print(f"  Source: {interaction['source']}")
            print()

asyncio.run(check_warfarin_supplements())
Enter fullscreen mode Exit fullscreen mode

JavaScript

async function checkWarfarinSupplements() {
  const params = new URLSearchParams({
    drugs: "warfarin",
    supplements: "Fish Oil,Vitamin D,St. John's Wort",
  });

  const response = await fetch(
    `${BASE_URL}/api/v1/interactions/supplements?${params}`,
    { headers: { "X-API-Key": API_KEY } }
  );

  const data = await response.json();

  console.log(`Checked ${data.item_count} items`);
  console.log(`Found ${data.interactions.length} interactions:\n`);

  for (const ix of data.interactions) {
    console.log(`  ${ix.item_1_name} + ${ix.item_2_name}`);
    console.log(`  Severity: ${ix.severity}`);
    console.log(`  ${ix.description}`);
    console.log(`  Source: ${ix.source}\n`);
  }
}

checkWarfarinSupplements();
Enter fullscreen mode Exit fullscreen mode

There's also a unified endpoint at /api/v1/interactions/check that auto-detects whether each item is a drug or supplement. Just pass a comma-separated list:

GET /api/v1/interactions/check?items=warfarin,aspirin,Fish Oil
Enter fullscreen mode Exit fullscreen mode

It figures out that warfarin and aspirin are drugs (resolves them via RxNorm) and Fish Oil is a supplement, then checks all pairwise interactions across both categories.

Example 3: Batch Check Multiple Pairs

If your app needs to check a patient's entire medication list, use the batch endpoint. It checks up to 50 pairs in a single request.

Python

async def batch_interaction_check():
    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"{BASE_URL}/api/v1/batch/interactions",
            json={
                "pairs": [
                    ["aspirin", "ibuprofen"],
                    ["warfarin", "Fish Oil"],
                    ["metformin", "alcohol"],
                    ["lisinopril", "potassium"],
                    ["simvastatin", "amiodarone"],
                ]
            },
            headers={"X-API-Key": API_KEY},
        )
        response.raise_for_status()
        data = response.json()

        print(f"Checked {data['total_pairs_checked']} pairs")
        print(f"Found {data['total_interactions_found']} interactions")
        print(f"Used {data['queries_used']} API queries\n")

        for result in data["results"]:
            pair_label = " + ".join(result["items"])
            if result["interactions"]:
                for ix in result["interactions"]:
                    print(f"  {pair_label}: {ix['severity']} - {ix['description'][:80]}...")
            else:
                print(f"  {pair_label}: No interactions found")

asyncio.run(batch_interaction_check())
Enter fullscreen mode Exit fullscreen mode

JavaScript

async function batchInteractionCheck() {
  const response = await fetch(
    `${BASE_URL}/api/v1/batch/interactions`,
    {
      method: "POST",
      headers: {
        "X-API-Key": API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        pairs: [
          ["aspirin", "ibuprofen"],
          ["warfarin", "Fish Oil"],
          ["metformin", "alcohol"],
          ["lisinopril", "potassium"],
          ["simvastatin", "amiodarone"],
        ],
      }),
    }
  );

  const data = await response.json();

  console.log(`Checked ${data.total_pairs_checked} pairs`);
  console.log(`Found ${data.total_interactions_found} interactions`);
  console.log(`Used ${data.queries_used} API queries\n`);

  for (const result of data.results) {
    const label = result.items.join(" + ");
    if (result.interactions.length > 0) {
      for (const ix of result.interactions) {
        console.log(`  ${label}: ${ix.severity} - ${ix.description.slice(0, 80)}...`);
      }
    } else {
      console.log(`  ${label}: No interactions found`);
    }
  }
}

batchInteractionCheck();
Enter fullscreen mode Exit fullscreen mode

Each pair counts as one API call against your quota, so checking 5 pairs uses 5 calls.

What's in the Database

Here's a snapshot of the data available right now:

  • 120+ supplements with dosage info, evidence summaries, and known interactions (sourced from NIH ODS)
  • 100,000+ drugs searchable by brand name, generic name, RxCUI, or NDC code
  • 250+ verified drug-supplement interactions curated from NIH and FDA sources
  • Drug-drug interactions from FDA structured product labels (openFDA) plus a curated set of major, clinically significant interactions

All interaction data comes from established medical databases. Nothing is generated or inferred -- that's important when you're dealing with patient safety.

How It Compares

Feature MedData API DrugBank API DIY (build it yourself)
Drug search Yes Yes Weeks of integration work
Supplement data Yes (120+ supplements) Limited Separate NIH integration
Drug-drug interactions Yes (FDA labels + curated) Yes Build it yourself
Drug-supplement interactions Yes (250+ verified) Limited Manual curation needed
Unified drug + supplement check Yes (auto-detects) No Custom logic required
Batch checking Yes (50 pairs/request) Varies Build your own
Free tier 250 calls/month No free tier Free (but your time isn't)
Starting price $29/month $500+/month $0 + engineering time
Setup time 5 minutes Hours Weeks

Pricing

Straightforward per-month pricing, no per-call fees within your tier:

Plan Requests/Month Price
Free 250 $0
Starter 5,000 $29/mo
Growth 25,000 $79/mo
Business 100,000 $199/mo
Enterprise 100,000+ Custom (support@anthesia.io)

The free tier is there so you can test everything before committing. No credit card required.

API Design Notes

A few decisions worth mentioning if you're evaluating this for production use:

  • Authentication is via X-API-Key header (SHA-256 hashed on the server, never stored in plaintext)
  • Caching is aggressive -- drug data is cached for 7 days, interactions for 30 days, pricing for 24 hours. First requests are slower; subsequent ones are fast
  • Error responses follow a consistent format: {error, detail, status_code, request_id}. The request_id is useful for debugging
  • Rate limiting is per-API-key, tracked monthly with automatic reset
  • OpenAPI docs are auto-generated -- the Swagger UI at /docs is fully interactive

Disclaimer

This API provides drug and supplement information for informational purposes only. It is not medical advice. Always consult a qualified healthcare professional before making clinical decisions. All interaction data is sourced from established government and medical databases (RxNorm, NIH, FDA) -- nothing is generated or inferred.

Try It Out

The API is live right now:

Grab a free API key, run through the examples above, and see if it fits what you're building. If you have questions or feature requests, drop a comment below.


Built by Anthesia. Data sourced from openFDA, RxNorm, and the NIH Office of Dietary Supplements.

Top comments (0)