openFDA API: A Developer's Getting Started Guide
How to query the openFDA API for drug data, adverse events, recalls, and labels. Includes endpoints, authentication, rate limits, and example queries.

What openFDA gives you
openFDA is a free, public API maintained by the FDA. It provides structured access to several FDA datasets without requiring registration or API keys for basic use.
Available endpoints:
| Endpoint | Data | Records |
|---|---|---|
/drug/event |
Adverse event reports (FAERS) | 20M+ |
/drug/label |
Drug labeling/package inserts | 130K+ |
/drug/enforcement |
Recall/enforcement reports | 30K+ |
/drug/ndc |
National Drug Code directory | 300K+ |
/drug/drugsfda |
Drug approvals | 40K+ |
/device/event |
Medical device adverse events | 15M+ |
/food/enforcement |
Food recall reports | 20K+ |
Your first API call
No signup needed. Hit this endpoint to get the 5 most recent drug adverse event reports:
curl "https://api.fda.gov/drug/event.json?limit=5"
The response is JSON. Each result includes patient demographics, reported drugs, reactions, and outcomes.
Search syntax
openFDA uses a custom query syntax. The search parameter accepts field-value pairs:
# Reports where the drug is metformin
?search=patient.drug.openfda.generic_name:"metformin"
# Class I recalls from 2026
?search=classification:"Class+I"+AND+recall_initiation_date:[20260101+TO+20261231]
# Combine multiple conditions
?search=patient.drug.openfda.brand_name:"Lipitor"+AND+serious:1
Supported operators: AND, OR, NOT, range queries with [min TO max], and exact match with quotes.
Counting and aggregation
The count parameter returns frequency distributions instead of individual records:
# Top 10 reported reactions for a drug
?search=patient.drug.openfda.generic_name:"metformin"&count=patient.reaction.reactionmeddrapt.exact&limit=10
# Recalls by year
?count=recall_initiation_date
This is the most useful feature for analysis. Instead of pulling thousands of records and counting client-side, let the API do the aggregation.
Rate limits
Without an API key: 240 requests per minute, 120,000 per day.
With an API key (free, register at open.fda.gov): 240 requests per minute, 120,000 per day (same limits, but your usage is tracked separately).
The rate limits are generous for most use cases. Hitting them means you should consider bulk downloads instead.
Pagination
Use skip and limit to paginate:
?limit=100&skip=0 # First 100 results
?limit=100&skip=100 # Next 100
Maximum skip value is 25,000. Maximum limit is 1,000. For datasets larger than 26,000 records, you need to partition by date range or use the bulk download files.
Common gotchas
Field names are deeply nested. A drug's brand name lives at patient.drug.openfda.brand_name, not at the top level. Read the API documentation for the full field hierarchy.
Not all records have openFDA fields. The openfda object is populated by FDA's matching algorithm. Older records or unusual drugs may have empty openFDA fields even though the raw data exists.
Date format is YYYYMMDD, not ISO 8601. Queries use 20260814, not 2026-08-14.
Spaces in queries need encoding. Use + for spaces in search terms, or URL-encode properly.
Bulk data downloads
For large-scale analysis, skip the API entirely. openFDA provides bulk download files at:
https://open.fda.gov/apis/downloads/
These are partitioned JSON files, compressed with ZIP. Total dataset sizes:
- Drug adverse events: ~35 GB uncompressed
- Drug labels: ~8 GB uncompressed
- Enforcement reports: ~200 MB uncompressed
Building something useful: a recall monitor
A practical example: check for new Class I recalls daily.
import requests
from datetime import datetime, timedelta
yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y%m%d")
today = datetime.now().strftime("%Y%m%d")
url = (
"https://api.fda.gov/drug/enforcement.json"
f"?search=classification:\"Class+I\""
f"+AND+report_date:[{yesterday}+TO+{today}]"
"&limit=100"
)
response = requests.get(url)
data = response.json()
if "results" in data:
for recall in data["results"]:
print(f"{recall['product_description']}: {recall['reason_for_recall']}")
else:
print("No new Class I recalls today.")
Run this on a cron job and pipe the output to Slack, email, or whatever alerting system you prefer.
FAQ
Is openFDA free? Completely free. No payment, no mandatory registration. An API key is optional and only needed for usage tracking.
How fresh is the data? Enforcement reports update weekly. Adverse events update quarterly. Drug labels update as new labeling is submitted.
Can I use openFDA data commercially? Yes. The data is public domain. The API terms of service restrict abusive usage (DDoS, etc.) but not commercial use of the data itself.
What programming language works best?
Any language that can make HTTP requests. Python with requests is the most common choice in health data circles. JavaScript fetch, Ruby, Go all work fine.
Are there SDKs or client libraries? No official SDK. The community has built unofficial wrappers in Python and JavaScript, but the API is simple enough that raw HTTP works well.
Published on 2026-08-10 · 4 min read
← Back to all articles