openFDA Drug and Adverse Event Database
Overview
openFDA provides public access to FDA regulatory data through a simple REST API. Key datasets include the FDA Adverse Event Reporting System (FAERS) with 20M+ adverse event reports, drug product labeling (NDC, SPL), drug approvals (Drugs@FDA), medical device reports, and recall enforcement actions. The API supports full-text search and structured queries using Elasticsearch-style syntax.
When to Use
- Retrieving adverse event reports for a drug to assess safety signals and side effect profiles
- Querying FAERS for disproportionality analysis (comparing drug vs. drug adverse event profiles)
- Looking up official drug labeling (indications, contraindications, warnings, dosing) by drug name or NDC
- Searching for drug recalls and enforcement actions by drug name or company
- Identifying all marketed products containing a given active ingredient
- Building pharmacovigilance pipelines that monitor drug safety signals from public regulatory data
- For clinical trial efficacy data use
clinicaltrials-database-search; for drug structures/targets usedrugbank-database-access
Prerequisites
- Python packages:
requests,pandas - Data requirements: drug names, active ingredients, MedDRA terms, NDC codes
- Environment: internet connection; no authentication required for basic use
- Rate limits: 1000 req/day without API key; 120,000 req/day with free API key from https://open.fda.gov/apis/authentication/
pip install requests pandas
Quick Start
import requests
BASE = "https://api.fda.gov/drug"
# Optional: add api_key parameter for higher rate limits
# Find adverse events for aspirin
r = requests.get(
f"{BASE}/event.json",
params={
"search": 'patient.drug.medicinalproduct:"aspirin"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": 10
}
)
r.raise_for_status()
data = r.json()
print("Top adverse reactions for aspirin:")
for item in data["results"][:5]:
print(f" {item['term']:40s} count={item['count']}")
Core API
Query 1: Adverse Event Report Search (FAERS)
Search the FDA Adverse Event Reporting System for drug-event associations.
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def faers_search(drug_name, limit=100):
"""Search FAERS for adverse event reports mentioning a drug."""
r = requests.get(f"{BASE}/event.json",
params={"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = faers_search("warfarin", limit=5)
total = data["meta"]["results"]["total"]
print(f"Total FAERS reports for warfarin: {total:,}")
# Show first report summary
report = data["results"][0]
print(f"\nReport {report['safetyreportid']}:")
print(f" Date : {report.get('receivedate', 'n/a')}")
print(f" Serious : {report.get('serious', 'n/a')}")
drugs = [d.get("medicinalproduct", "n/a") for d in report.get("patient", {}).get("drug", [])]
print(f" Drugs : {drugs[:5]}")
reactions = [r.get("reactionmeddrapt", "n/a") for r in report.get("patient", {}).get("reaction", [])]
print(f" Reactions: {reactions[:5]}")
Query 2: Count Top Adverse Events for a Drug
Use the count parameter to aggregate adverse event terms.
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def top_adverse_events(drug_name, limit=20):
"""Get the most frequently reported adverse events for a drug."""
r = requests.get(f"{BASE}/event.json",
params={
"search": f'patient.drug.medicinalproduct:"{drug_name}"',
"count": "patient.reaction.reactionmeddrapt.exact",
"limit": limit
})
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame(results).rename(columns={"term": "reaction", "count": "reports"})
df_atorvastatin = top_adverse_events("atorvastatin", limit=15)
print("Top adverse events for atorvastatin:")
print(df_atorvastatin.head(10).to_string(index=False))
df_atorvastatin.to_csv("atorvastatin_adverse_events.csv", index=False)
# Compare two drugs: adverse event profile overlap
df_drug1 = top_adverse_events("simvastatin", limit=20)
df_drug2 = top_adverse_events("atorvastatin", limit=20)
common = set(df_drug1["reaction"]) & set(df_drug2["reaction"])
print(f"\nCommon adverse events (simvastatin ∩ atorvastatin): {len(common)}")
print("Shared reactions:", list(common)[:10])
Query 3: Drug Labeling Search
Retrieve official drug labels (indications, warnings, dosing, contraindications).
import requests
BASE = "https://api.fda.gov/drug"
def get_label(drug_name):
"""Retrieve FDA drug label by brand or generic name."""
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.brand_name:"{drug_name}"',
"limit": 1})
if r.status_code == 404:
r = requests.get(f"{BASE}/label.json",
params={"search": f'openfda.generic_name:"{drug_name}"',
"limit": 1})
r.raise_for_status()
results = r.json()["results"]
return results[0] if results else None
label = get_label("Lipitor")
if label:
print(f"Brand name : {label.get('openfda', {}).get('brand_name', ['n/a'])[0]}")
print(f"Generic name: {label.get('openfda', {}).get('generic_name', ['n/a'])[0]}")
print(f"Manufacturer: {label.get('openfda', {}).get('manufacturer_name', ['n/a'])[0]}")
indications = label.get("indications_and_usage", ["n/a"])[0]
print(f"\nIndications (first 300 chars):\n{indications[:300]}...")
Query 4: Drug Product Lookup by NDC
Retrieve marketed product information by National Drug Code.
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def ndc_search(ndc_or_name, limit=10):
"""Search NDC directory for drug product information."""
# Search by product name or NDC
r = requests.get(f"{BASE}/ndc.json",
params={"search": f'generic_name:"{ndc_or_name}"',
"limit": limit})
r.raise_for_status()
return r.json()
data = ndc_search("metformin", limit=10)
total = data["meta"]["results"]["total"]
print(f"Metformin products: {total}")
rows = []
for prod in data["results"]:
rows.append({
"product_ndc": prod.get("product_ndc"),
"brand_name": prod.get("brand_name"),
"generic_name": prod.get("generic_name"),
"dosage_form": prod.get("dosage_form"),
"route": ", ".join(prod.get("route", [])),
"labeler": prod.get("labeler_name"),
})
df = pd.DataFrame(rows)
print(df.to_string(index=False))
Query 5: Drug Recall Search
Search FDA enforcement actions and drug recalls by drug name or company.
import requests, pandas as pd
BASE = "https://api.fda.gov/drug"
def drug_recalls(drug_name, limit=20):
"""Find FDA drug recalls for a given drug name."""
r = requests.get(f"{BASE}/enforcement.json",
params={
"search": f'product_description:"{drug_name}"',
"limit": limit
})
if r.status_code == 404:
return pd.DataFrame()
r.raise_for_status()
results = r.json()["results"]
return pd.DataFrame([{
"recalling_firm": rec.get("recalling_firm"),
"product": rec.get("product_description", "")[:80],
"reason": rec.get("reason_for_recall", "")[:100],
"classification": rec.get("classification"),
"recall_date": rec.get("recall_initiation_date"),
"status": rec.get("status"),
} for rec in results])
recalls = drug_recalls("metformin", limit=5)
print(f"Metformin recalls: {len(recalls)}")
if not recalls.empty:
print(recalls[["recalling_firm", "classificati