Developer·4 min read

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.

openFDA API: A Developer's Getting Started Guide

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