Health Data APIs Compared: openFDA vs CDC SODA vs CMS
A side-by-side comparison of the three major US government health data APIs. Query syntax, rate limits, data freshness, and which to use for what.

Three APIs, three philosophies
The US government publishes health data through three major API systems. Each was built by a different agency at a different time with different design philosophies. Choosing the right one depends on what data you need and how you plan to consume it.
| openFDA | CDC SODA | CMS Provider Data | |
|---|---|---|---|
| Maintained by | FDA | CDC (via Socrata) | CMS |
| Base URL | api.fda.gov | data.cdc.gov | data.cms.gov |
| Auth required | No | Optional (app token) | No |
| Query language | Custom syntax | SoQL (SQL-like) | SODA/custom |
| Response format | JSON | JSON, CSV, GeoJSON | JSON, CSV |
| Rate limit | 240/min | ~1000/hr | Varies |
| Bulk download | Yes (ZIP) | Yes (CSV) | Yes (CSV) |
Query syntax comparison
The biggest practical difference is how you write queries.
openFDA uses field:value syntax with AND/OR operators:
# Drug adverse events for metformin in 2025
curl "https://api.fda.gov/drug/event.json?search=patient.drug.openfda.generic_name:\"metformin\"+AND+receivedate:[20250101+TO+20251231]&limit=10"
CDC SODA uses SoQL (Socrata Query Language), which looks like SQL:
# COVID deaths in California, ordered by date
curl "https://data.cdc.gov/resource/r8kw-7aab.json?\$where=state='California'&\$order=end_date DESC&\$limit=10"
CMS uses a mix depending on the dataset:
# Hospital general info
curl "https://data.cms.gov/provider-data/api/1/datastore/query/xubh-q36u/0?limit=10&offset=0"
For developers comfortable with SQL, CDC SODA is the most intuitive. openFDA's custom syntax has a steeper learning curve but offers powerful counting/aggregation built in.
Data freshness
How quickly each API reflects real-world events:
| API | Update frequency | Typical lag |
|---|---|---|
| openFDA (enforcement) | Weekly | 1-2 weeks |
| openFDA (FAERS) | Quarterly | 1-3 months |
| openFDA (labels) | As submitted | Days to weeks |
| CDC SODA (COVID) | Weekly | 1-2 weeks |
| CDC SODA (mortality) | Annually | 12-18 months |
| CMS (quality) | Quarterly | 3-6 months |
| CMS (pricing) | Weekly (NADAC) | 1 week |
If freshness matters for your use case (drug recall alerts, outbreak monitoring), openFDA enforcement and CDC COVID endpoints are the most responsive. For historical analysis, the lag is less relevant.
Aggregation capabilities
openFDA has a built-in count parameter that returns frequency distributions:
# Top 10 adverse reactions for a drug (no client-side counting needed)
?search=...&count=patient.reaction.reactionmeddrapt.exact&limit=10
This is powerful for analytics. You get pre-aggregated results in one API call instead of fetching thousands of records and counting locally.
CDC SODA supports GROUP BY and aggregate functions in SoQL:
?\$select=state,sum(new_death)&\$group=state&\$order=sum_new_death DESC
Full SQL-style aggregation makes CDC SODA the most flexible for ad-hoc analysis.
CMS has limited aggregation in most endpoints. For complex analysis, download the bulk file and process locally.
Pagination and data limits
| API | Max per request | Max offset | Total accessible via API |
|---|---|---|---|
| openFDA | 1,000 | 25,000 | 26,000 records |
| CDC SODA | 50,000 | Unlimited | Full dataset |
| CMS | Varies (100-1000) | Varies | Usually full dataset |
openFDA's 26,000-record limit is the most restrictive. For larger datasets, you must partition by date range or use bulk downloads. CDC SODA has no practical limit on pagination depth.
Error handling
Each API returns errors differently:
openFDA returns structured error objects:
{"error": {"code": "NOT_FOUND", "message": "No matches found!"}}
CDC SODA returns standard HTTP status codes with messages:
{"message": "query.soql.type-mismatch", "errorCode": "query.soql.type-mismatch"}
CMS responses vary by endpoint. Some return empty arrays, others return error objects.
For production code, handle:
- 429 (rate limited) with exponential backoff
- 404 (no results) gracefully
- 500 (server error) with retry logic
- Empty result sets (valid query, no matching data)
When to use which
Use openFDA when you need:
- Drug adverse event data (FAERS)
- Recall/enforcement information
- Drug labeling (package inserts)
- Quick aggregations on drug-related data
Use CDC SODA when you need:
- Disease surveillance data
- Mortality statistics
- Vaccination coverage
- Geospatial health data
- SQL-like query flexibility
Use CMS when you need:
- Hospital quality scores
- Provider information
- Drug pricing
- Medicare utilization data
Building across multiple APIs
Most real-world health data applications pull from more than one source. Common combinations:
- Drug safety dashboard: openFDA (adverse events + recalls) + DailyMed (labeling)
- Provider directory: NPI Registry (identity) + CMS (quality scores) + insurance network data
- Outbreak tracker: CDC SODA (surveillance) + state health department data
- Pricing tool: CMS NADAC (pharmacy cost) + openFDA NDC (drug identity)
The challenge is joining across APIs. Each uses different identifiers. NDC connects openFDA to CMS pricing. NPI connects CMS to provider identity. FIPS codes connect CDC geographic data to census demographics.
FAQ
Which API is easiest for beginners? CDC SODA, because SoQL is similar to SQL. If you know SQL, you can write useful queries in minutes.
Can I use all three in a single application? Yes. They are independent systems with no authentication conflicts. Many health data applications query two or three of them.
Which has the best documentation? openFDA has the most polished developer documentation with interactive examples. CDC SODA auto-generates API docs per dataset. CMS documentation is the least developer-friendly.
Are there rate limits I should worry about? For typical development and small-scale production (under 100K requests/day), rate limits are not a concern for any of the three. At scale, consider caching and bulk downloads.
Do any of these APIs support webhooks or streaming? No. All three are request-response only. For real-time monitoring, you need to poll on a schedule (daily for most datasets, weekly for enforcement reports).
Published on 2026-07-14 · 5 min read
← Back to all articles