| name | ddinter-database |
| description | Query DDInter drug-drug interactions via REST API (1.7M+ interactions, 2,400+ drugs). Search by drug name/ID for severity (major/moderate/minor), mechanisms, and clinical recommendations. No auth. For FDA labeling use dailymed-database; for pharmacogenomics use clinpgx-database. |
| license | CC-BY-4.0 |
DDInter Drug-Drug Interaction Database
Overview
DDInter is an open, curated database of drug-drug interactions (DDIs) covering 2,400+ drugs and 1.7M+ pairwise interactions with structured severity levels (major, moderate, minor), mechanistic annotations, and clinical management recommendations. Access is provided via a JSON REST API at https://ddinter.scbdd.com/api/ — no authentication or registration required.
When to Use
- Checking whether two co-administered drugs have a known interaction and its severity (major/moderate/minor)
- Retrieving all known interactions for a given drug to support polypharmacy risk assessment
- Identifying the mechanistic basis (pharmacokinetic vs. pharmacodynamic) of a drug-drug interaction
- Screening a drug combination list for potential major interactions before clinical decision support
- Building automated DDI checking pipelines for medication review or drug repurposing workflows
- Analyzing the DDI network for a drug class (e.g., all major interactions for CYP3A4 substrates)
- For FDA-approved drug labeling text (indications, dosage, contraindications) use
dailymed-database
- For pharmacogenomics interactions (CYP genotype-drug associations) use
clinpgx-database; DDInter covers drug-drug not gene-drug pairs
- For drug adverse event reports from FAERS use
fda-database
Prerequisites
- Python packages:
requests, pandas, matplotlib, networkx
- Data requirements: drug names or DDInter drug IDs
- Environment: internet connection; no API key required
- Rate limits: no officially published rate limit; use
time.sleep(0.3) between requests in batch loops for polite access
pip install requests pandas matplotlib networkx
Quick Start
import requests
BASE = "https://ddinter.scbdd.com/api"
r = requests.get(f"{BASE}/drug/", params={"drug_name": "warfarin", "format": "json"}, timeout=15)
r.raise_for_status()
data = r.json()
print(f"Results for 'warfarin': {data['count']} drugs found")
for drug in data["results"][:3]:
print(f" ID={drug['ddinter_id']} Name={drug['drug_name']}")
Core API
Query 1: Search Drug by Name
Find a drug's DDInter ID by searching its name. The DDInter ID is required for all interaction queries.
import requests
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def search_drug(drug_name):
"""Search DDInter for a drug by name. Returns list of matching drug records."""
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"},
timeout=15)
r.raise_for_status()
return r.json()
result = search_drug("warfarin")
print(f"Matches: {result['count']}")
if result["results"]:
drug = result["results"][0]
print(f"DDInter ID: {drug['ddinter_id']}")
print(f"Drug name: {drug['drug_name']}")
warfarin_id = drug["ddinter_id"]
print(f"\nWarfarin DDInter ID: {warfarin_id}")
drugs_to_find = ["warfarin", "aspirin", "atorvastatin", "metformin", "amiodarone"]
id_map = {}
for name in drugs_to_find:
res = search_drug(name)
if res[]:
id_map[name] = res[][][]
()
Query 2: Get All Interactions for a Drug
Retrieve all known DDIs for a drug by its DDInter ID. Returns interaction partners, severity, and clinical information.
import requests
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def get_drug_interactions(drug_id, page_size=100):
"""Get all DDIs for a drug by DDInter ID. Handles pagination automatically."""
all_interactions = []
url = f"{BASE}/interaction/"
params = {"drug_id": drug_id, "format": "json", "page_size": page_size}
while url:
r = requests.get(url, params=params, timeout=20)
r.raise_for_status()
data = r.json()
all_interactions.extend(data.get("results", []))
url = data.get("next")
params = {}
return all_interactions
interactions = get_drug_interactions("DDInter_D00001")
print(f"Warfarin total interactions: {len(interactions)}")
df = pd.DataFrame(interactions)
if not df.empty and "level" in df.columns:
severity_counts = df["level"].value_counts()
print("\nInteractions by severity:")
for level, count in severity_counts.items():
print(f" {level:15s}: {count:4d}")
Query 3: Get Interaction Details by Interaction ID
Retrieve full details for a specific drug-drug interaction, including mechanism and clinical recommendation.
import requests
BASE = "https://ddinter.scbdd.com/api"
def get_interaction_detail(interaction_id):
"""Get full details for a specific interaction by its DDInter interaction ID."""
r = requests.get(f"{BASE}/interaction/{interaction_id}/",
params={"format": "json"},
timeout=15)
r.raise_for_status()
return r.json()
interaction_id = "DDInter_I_000001"
try:
detail = get_interaction_detail(interaction_id)
print(f"Interaction: {detail.get('interaction_id')}")
print(f"Drug A: {detail.get('drug_a')}")
print(f"Drug B: {detail.get('drug_b')}")
print(f"Severity: {detail.get('level')}")
print(f"Mechanism: {detail.get('mechanism', 'Not specified')[:200]}")
print(f"Recommendation: {detail.get('recommendation', 'Not specified')[:200]}")
print(f"PK type: {detail.get('pharmacokinetic_type', )}")
()
Exception e:
()
Query 4: Check Interaction Between Two Specific Drugs
Query interactions between exactly two drugs using their DDInter IDs.
import requests
BASE = "https://ddinter.scbdd.com/api"
def check_drug_pair(drug_id_1, drug_id_2):
"""Check interactions between two specific drugs by their DDInter IDs."""
r = requests.get(f"{BASE}/between/",
params={"drug1": drug_id_1, "drug2": drug_id_2, "format": "json"},
timeout=15)
r.raise_for_status()
return r.json()
def find_drug_id(drug_name):
"""Helper: resolve drug name to DDInter ID."""
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"},
timeout=15)
r.raise_for_status()
results = r.json()["results"]
return results[0]["ddinter_id"] if results else None
warfarin_id = find_drug_id("warfarin")
aspirin_id = find_drug_id("aspirin")
if warfarin_id and aspirin_id:
interactions = check_drug_pair(warfarin_id, aspirin_id)
count = interactions.get("count", 0)
print(f"Warfarin + Aspirin: {count} interaction(s) found")
for ix in interactions.get("results", []):
()
()
()
:
()
Query 5: Filter Interactions by Severity Level
Retrieve only high-severity (major) interactions for a drug — essential for rapid clinical risk screening.
import requests
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def get_major_interactions(drug_id):
"""Get only major-severity interactions for a drug."""
all_interactions = []
r = requests.get(f"{BASE}/interaction/",
params={"drug_id": drug_id, "format": "json", "page_size": 200},
timeout=20)
r.raise_for_status()
data = r.json()
all_interactions.extend(data.get("results", []))
major = [ix for ix in all_interactions
if ix.get("level", "").lower() == "major"]
return major
drug_id = "DDInter_D00023"
major_ixs = get_major_interactions(drug_id)
print(f"Major interactions: {len(major_ixs)}")
if major_ixs:
df = pd.DataFrame(major_ixs)
for col in ["drug_a", "drug_b", "level", "pharmacokinetic_type"]:
if col in df.columns:
print(f" : ")
df.to_csv(, index=)
()
Query 6: Polypharmacy Screening for a Drug List
Screen a medication list for all pairwise major and moderate interactions.
import requests
import time
import itertools
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def find_drug_id(drug_name):
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"},
timeout=15)
r.raise_for_status()
results = r.json()["results"]
return (results[0]["ddinter_id"], results[0]["drug_name"]) if results else (None, None)
def check_pair(id1, id2):
r = requests.get(f"{BASE}/between/",
params={"drug1": id1, "drug2": id2, "format": "json"},
timeout=15)
r.raise_for_status()
return r.json().get("results", [])
medication_names = ["warfarin", "aspirin", "atorvastatin", "metformin", "amiodarone"]
id_map = {}
for name in medication_names:
ddid, resolved_name = find_drug_id(name)
if ddid:
id_map[name] = (ddid, resolved_name)
()
time.sleep()
flagged = []
(n1, (id1, rn1)), (n2, (id2, rn2)) itertools.combinations(id_map.items(), ):
ixs = check_pair(id1, id2)
ix ixs:
level = ix.get(, )
level.lower() (, ):
flagged.append({
: rn1,
: rn2,
: level,
: ix.get(, )[:],
})
time.sleep()
df = pd.DataFrame(flagged)
()
df.empty:
(df.to_string(index=))
df.to_csv(, index=)
()
Query 7: Visualize Interaction Network
Build and visualize a drug-drug interaction network for a set of drugs, with edges colored by severity.
import requests
import time
import itertools
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
BASE = "https://ddinter.scbdd.com/api"
def find_drug_id(drug_name):
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"},
timeout=15)
r.raise_for_status()
results = r.json()["results"]
return (results[0]["ddinter_id"], results[0]["drug_name"]) if results else (None, None)
def check_pair(id1, id2):
r = requests.get(f"{BASE}/between/",
params={"drug1": id1, "drug2": id2, "format": "json"},
timeout=15)
r.raise_for_status()
return r.json().get("results", [])
SEVERITY_COLORS = {"major": "#D32F2F", "moderate": "#F57C00", "minor": "#388E3C"}
drugs = ["warfarin", , , , ]
id_map = {}
name drugs:
ddid, rname = find_drug_id(name)
ddid:
id_map[name] = (ddid, rname)
time.sleep()
G = nx.Graph()
name, (ddid, rname) id_map.items():
G.add_node(rname)
edge_colors = []
(n1, (id1, rn1)), (n2, (id2, rn2)) itertools.combinations(id_map.items(), ):
ixs = check_pair(id1, id2)
ix ixs:
level = ix.get(, ).lower()
G.add_edge(rn1, rn2, severity=level, weight= level == )
time.sleep()
fig, ax = plt.subplots(figsize=(, ))
pos = nx.spring_layout(G, seed=, k=)
level, color SEVERITY_COLORS.items():
edges = [(u, v) u, v, d G.edges(data=) d.get() == level]
edges:
width = level ==
nx.draw_networkx_edges(G, pos, edgelist=edges, edge_color=color, width=width, alpha=, ax=ax)
nx.draw_networkx_nodes(G, pos, node_color=, node_size=, alpha=, ax=ax)
nx.draw_networkx_labels(G, pos, font_color=, font_size=, font_weight=, ax=ax)
matplotlib.patches Patch
legend = [Patch(color=c, label=l.capitalize()) l, c SEVERITY_COLORS.items()]
ax.legend(handles=legend, title=, loc=)
ax.set_title()
ax.axis()
plt.tight_layout()
plt.savefig(, dpi=, bbox_inches=)
()
Key Concepts
Severity Classification
DDInter classifies interactions into three severity levels, following established clinical pharmacology standards:
| Severity | Code | Clinical Meaning | Action |
|---|
| Major | major | Potentially life-threatening or causing permanent damage | Avoid combination; use alternative |
| Moderate | moderate | May cause clinical deterioration; increased monitoring required | Use with caution; monitor closely |
| Minor | minor | Limited clinical effects; interaction is documented but rarely significant | Generally safe; monitor if symptomatic |
Mechanism Types
Interactions are classified by mechanism:
- Pharmacokinetic (PK): One drug affects the absorption, distribution, metabolism, or excretion (ADME) of the other (e.g., CYP enzyme inhibition)
- Pharmacodynamic (PD): Drugs have additive, synergistic, or antagonistic effects at the pharmacological target level (e.g., additive bleeding risk)
- Mixed: Both PK and PD mechanisms contribute
Drug Identification
DDInter uses its own sequential identifier scheme (e.g., DDInter_D00001 for Warfarin). There is no direct mapping to ChEMBL IDs, PubChem CIDs, or RxCUI without a prior name search. Always resolve drug names to DDInter IDs using the /drug/ endpoint before querying interactions.
Common Workflows
Workflow 1: Comprehensive DDI Profile for a Drug
Goal: Retrieve all interactions for a drug, stratify by severity, and export a structured report.
import requests
import time
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def find_drug_id(name):
r = requests.get(f"{BASE}/drug/",
params={"drug_name": name, "format": "json"},
timeout=15)
r.raise_for_status()
res = r.json()["results"]
return (res[0]["ddinter_id"], res[0]["drug_name"]) if res else (None, None)
def get_all_interactions(drug_id, page_size=200):
all_results = []
url = f"{BASE}/interaction/"
params = {"drug_id": drug_id, "format": "json", "page_size": page_size}
while url:
r = requests.get(url, params=params, timeout=30)
r.raise_for_status()
data = r.json()
all_results.extend(data.get("results", []))
url = data.get("next")
params = {}
return all_results
drug_name = "clopidogrel"
drug_id, resolved_name = find_drug_id(drug_name)
if drug_id:
print(f"Drug: {resolved_name} ({drug_id})")
ixs = get_all_interactions(drug_id)
df = pd.DataFrame(ixs)
()
df.columns:
()
level, grp df.groupby():
()
major = df[df[]..lower() == ].copy()
()
_, row major.head().iterrows():
partner = row.get() row.get() == resolved_name row.get()
mech = (row.get(, ))[:]
()
df.to_csv(, index=)
()
Workflow 2: Pairwise Interaction Matrix for a Drug Panel
Goal: Build a severity matrix showing all pairwise interactions between a curated drug panel — useful for clinical pharmacology and formulary review.
import requests
import time
import itertools
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
BASE = "https://ddinter.scbdd.com/api"
SEVERITY_SCORE = {"major": 3, "moderate": 2, "minor": 1, "none": 0}
def find_drug_id(name):
r = requests.get(f"{BASE}/drug/",
params={"drug_name": name, "format": "json"},
timeout=15)
r.raise_for_status()
res = r.json()["results"]
return (res[0]["ddinter_id"], res[0]["drug_name"]) if res else (None, None)
def check_pair(id1, id2):
r = requests.get(f"{BASE}/between/",
params={"drug1": id1, "drug2": id2, "format": "json"},
timeout=15)
r.raise_for_status()
return r.json().get("results", [])
drug_names = [, , , , ]
id_map = {}
name drug_names:
ddid, rname = find_drug_id(name)
ddid:
id_map[name] = (ddid, rname)
time.sleep()
resolved = {name: rname name, (ddid, rname) id_map.items()}
n = (id_map)
names = (id_map.keys())
rnames = [resolved[n] n names]
matrix = np.zeros((n, n), dtype=)
i, (n1, (id1, _)) (id_map.items()):
j, (n2, (id2, _)) (id_map.items()):
i < j:
ixs = check_pair(id1, id2)
ixs:
worst = (SEVERITY_SCORE.get(ix.get(, ).lower(), ) ix ixs)
matrix[i, j] = matrix[j, i] = worst
time.sleep()
fig, ax = plt.subplots(figsize=(, ))
im = ax.imshow(matrix, cmap=, vmin=, vmax=)
ax.set_xticks((n))
ax.set_yticks((n))
ax.set_xticklabels(rnames, rotation=, ha=, fontsize=)
ax.set_yticklabels(rnames, fontsize=)
i (n):
j (n):
text = [, , , ][matrix[i, j]]
ax.text(j, i, text, ha=, va=, fontsize=)
plt.colorbar(im, ax=ax, label=)
ax.set_title()
plt.tight_layout()
plt.savefig(, dpi=, bbox_inches=)
()
Key Parameters
| Parameter | Endpoint | Default | Range / Options | Effect |
|---|
drug_name | /drug/ | — | any drug name string | Search term for drug name lookup |
drug_id | /interaction/ | — | DDInter_DXXXXX string | DDInter drug ID for interaction queries |
drug1, drug2 | /between/ | — | DDInter_DXXXXX strings | Both required to check a specific drug pair |
format | all endpoints | json | json | Response format; JSON only via API |
page_size | /interaction/, /drug/ | 10 | positive integer | Results per page; use 200 for bulk retrieval |
level | response field | — | major, moderate, minor | Interaction severity; filter client-side |
pharmacokinetic_type | response field | — | PK, PD, mixed | Mechanism category |
Best Practices
-
Always resolve drug names to DDInter IDs first: The API does not accept free-text drug names in interaction queries. Use /drug/?drug_name= to obtain the ddinter_id, then pass it to /interaction/ or /between/.
-
Handle pagination for complete interaction lists: The default page returns at most 10 results. Drugs like warfarin or amiodarone have hundreds of interactions — iterate next URLs until null:
while url:
data = requests.get(url, params=params).json()
results.extend(data["results"])
url = data.get("next")
params = {}
-
Use check_pair() for targeted queries, get_interactions() for full profiles: The /between/ endpoint is faster when you need one pair. The /interaction/ endpoint is needed for comprehensive DDI profiling.
-
Add time.sleep(0.3) in batch loops: DDInter has no published rate limits, but polite delays prevent server-side throttling on this publicly hosted research database.
-
Filter by severity client-side: The API does not support server-side severity filtering on the /interaction/ endpoint. Retrieve all interactions and filter in pandas:
df = pd.DataFrame(interactions)
major_only = df[df["level"].str.lower() == "major"]
-
Cross-reference with clinical databases for decision support: DDInter provides evidence-based interaction records, but for clinical decisions always verify against current prescribing information in dailymed-database and institutional drug interaction tools.
Common Recipes
Recipe: Quick Safety Check for a Drug Pair
When to use: Rapid single-pair interaction lookup before combining two drugs.
import requests
BASE = "https://ddinter.scbdd.com/api"
def quick_check(drug1_name, drug2_name):
"""Check interaction between two drugs by name. Returns severity or 'No interaction found'."""
def get_id(name):
r = requests.get(f"{BASE}/drug/",
params={"drug_name": name, "format": "json"},
timeout=15)
r.raise_for_status()
results = r.json()["results"]
return (results[0]["ddinter_id"], results[0]["drug_name"]) if results else (None, name)
id1, rn1 = get_id(drug1_name)
id2, rn2 = get_id(drug2_name)
if not id1 or not id2:
return f"Drug not found: {drug1_name if not id1 else drug2_name}"
r = requests.get(f"{BASE}/between/",
params={"drug1": id1, "drug2": id2, "format": "json"},
timeout=15)
r.raise_for_status()
ixs = r.json().get("results", [])
if not ixs:
return f"{rn1} + : No interaction found in DDInter"
worst = (ixs, key= x: {: , : , : }.get(x.get(, ).lower(), ))
(quick_check(, ))
(quick_check(, ))
(quick_check(, ))
Recipe: Count Interactions by Severity for Multiple Drugs
When to use: Generate a summary table comparing DDI burden across multiple drugs.
import requests
import time
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
def get_severity_summary(drug_name):
"""Return severity counts (major/moderate/minor) for a drug."""
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"},
timeout=15)
r.raise_for_status()
results = r.json()["results"]
if not results:
return None
drug_id = results[0]["ddinter_id"]
all_ixs = []
url = f"{BASE}/interaction/"
params = {"drug_id": drug_id, "format": "json", "page_size": 200}
while url:
r2 = requests.get(url, params=params, timeout=20)
r2.raise_for_status()
data = r2.json()
all_ixs.extend(data.get("results", []))
url = data.get("next")
params = {}
from collections import Counter
counts = Counter(ix.get("level", "unknown").lower() for ix in all_ixs)
return {
"drug": results[0]["drug_name"],
"total": (all_ixs),
: counts.get(, ),
: counts.get(, ),
: counts.get(, ),
}
drugs = [, , , ]
records = []
name drugs:
summary = get_severity_summary(name)
summary:
records.append(summary)
()
time.sleep()
df = pd.DataFrame(records)
df = df.sort_values(, ascending=)
df.to_csv(, index=)
()
Recipe: Export All Major Interactions Across a Drug List
When to use: Build a prioritized interaction alert list for formulary review or clinical decision support.
import requests
import time
import pandas as pd
BASE = "https://ddinter.scbdd.com/api"
drug_list = ["warfarin", "aspirin", "clopidogrel", "amiodarone", "fluconazole"]
all_major = []
for drug_name in drug_list:
r = requests.get(f"{BASE}/drug/",
params={"drug_name": drug_name, "format": "json"}, timeout=15)
r.raise_for_status()
res = r.json()["results"]
if not res:
continue
drug_id, resolved = res[0]["ddinter_id"], res[0]["drug_name"]
r2 = requests.get(f"{BASE}/interaction/",
params={"drug_id": drug_id, "format": "json", "page_size": 200}, timeout=30)
r2.raise_for_status()
for ix in r2.json().get("results", []):
if ix.get("level", "").lower() == "major":
all_major.append({
"query_drug": resolved,
"interaction_partner": ix.get("drug_a") if ix.get("drug_b") == resolved else ix.get("drug_b"),
: ,
: (ix.get(, ))[:],
: (ix.get(, ))[:],
})
time.sleep()
df = pd.DataFrame(all_major).drop_duplicates()
()
df.to_csv(, index=)
()
Troubleshooting
| Problem | Cause | Solution |
|---|
404 Not Found on /interaction/ | Invalid or malformed DDInter drug ID | Re-query /drug/?drug_name= to get a valid ID; format must be DDInter_DXXXXX |
count: 0 from /drug/ search | Drug name not matching DDInter nomenclature | Try INN name (e.g., "acetylsalicylic acid" not "aspirin"); try partial name |
| Interaction list is incomplete | Default page_size=10 truncates results | Set page_size=200 and iterate next URLs until null |
/between/ returns empty results | Drug pair has no curated interaction in DDInter | Absence does not mean no interaction — check dailymed-database label text |
ConnectionError or timeout | Server temporarily unavailable | Retry with timeout=30; use exponential backoff for bulk requests |
| Duplicate interactions in bulk export | Same interaction appears from both drug perspectives | Deduplicate by (drug_a, drug_b) pair after sorting drug IDs alphabetically |
JSONDecodeError | Server returned non-JSON error page | Check HTTP status code; r.raise_for_status() before parsing |
Related Skills
dailymed-database — FDA-approved drug label text including drug interaction sections (unstructured)
fda-database — openFDA for adverse event reports and drug recall data
drugbank-database-access — DrugBank local XML with structured DDI and target data
clinpgx-database — PharmGKB for drug-gene (pharmacogenomics) interaction data
pytdc-therapeutics-data-commons — TDC DDI benchmark datasets for ML model training
References