openFDA Enforcement (Recall) Monitor
Pricing
from $10.00 / 1,000 recall returneds
openFDA Enforcement (Recall) Monitor
Monitor FDA recall (enforcement) reports across drug, device and food. One normalized record per recall (number, Class I/II/III, status, firm, product, reason, dates), with type/class filters, a new-since-last-run mode, and change-detection flagging classification escalations. openFDA, CC0.
Pricing
from $10.00 / 1,000 recall returneds
Rating
0.0
(0)
Developer
ByteHaven Studios
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Monitor FDA recall (enforcement) reports across drug, device and food categories in a single run. Give it categories, classifications and/or a date window; it returns one normalized record per recall, with a new-since-last-run mode and change-detection that flags classification escalations (Class III→II→I) and termination events.
Clean REST/JSON — no browser, no proxy, no login, no API key required (an optional free key raises rate limits). Data source: FDA openFDA (U.S. public domain, CC0 1.0).
Status: scaffold (v0.1, in progress). This Actor is being built in slices; the runtime logic (
src/openfda.js,src/filters.js,src/main.js) is landing incrementally. This README documents the intended product surface. SeeCHANGELOG.mdfor what's implemented so far.
What it does
For each run it queries the openFDA enforcement endpoints — /drug/enforcement.json,
/device/enforcement.json, /food/enforcement.json — for the categories you select, filtered by a
report_date window, normalizes all three schemas into one record shape, applies your filters,
dedupes on recall_number, and pushes one dataset item per recall.
- Recent recalls (default): recalls whose
report_dateis on/afterreportedSince(or a recent trailing window if unset), across every selected category in one pass. - Cross-category edge: watching drug and device and food recalls together — normalized to one schema — is the moat. Incumbents grab the glamorous drug-label / adverse-event endpoints and leave the boring, weekly-lagged enforcement feeds un-normalized and un-joined.
- New-recall monitor:
monitorNewOnlypersists the set of already-reportedrecall_numbers (in the Actor's key-value store) and, on the next scheduled run, returns only recalls not seen before. - Change-detection:
detectChangespersists each recall's priorclassificationandstatusand, on later runs, flags recalls that escalated (Class III→II→I) or whose status changed (e.g.On-Going→Terminated). Change-detection over a weekly-refreshed corpus nobody else timestamps for first-seen. - Filters: by
recallCategories(drug / device / food),classifications(Class I / II / III), andstatuses.
Inputs
| Input | Type | Notes |
|---|---|---|
recallCategories | string[] | drug, device, food. Empty = all three |
classifications | string[] | Class I, Class II, Class III. Empty = all classes |
statuses | string[] | e.g. On-Going, Completed, Terminated. Empty = all statuses |
reportedSince | string | YYYY-MM-DD — report_date on/after. Empty = recent trailing window |
monitorNewOnly | boolean | Return only recall_numbers not seen in a previous run |
detectChanges | boolean | Flag classification escalations + status changes vs stored prior state (default on) |
fields | string[] | Override the kept output fields (empty = sensible default set) |
maxResults | integer | Cap total recalls returned (0 = no cap) |
apiKey | string | Optional openFDA api_key (raises daily rate limit; not required) |
proxyConfiguration | object | Optional; the API is open and needs no proxy. Default: none |
Output — one record per recall
{"recall_number": "D-1234-2026","category": "drug","status": "Ongoing","classification": "Class II","product_type": "Drugs","product_description": "Atorvastatin Calcium Tablets, 40 mg, 90-count bottle","reason_for_recall": "Failed dissolution specifications at the 12-month stability time point.","recalling_firm": "Example Pharma Inc.","city": "Trenton","state": "NJ","country": "United States","voluntary_mandated": "Voluntary: Firm initiated","initial_firm_notification": "Letter","event_id": "90210","recall_initiation_date": "2026-06-15","center_classification_date": "2026-07-01","report_date": "2026-07-08","termination_date": null,"isNew": true,"change": null,"fetchedAt": "2026-07-10T14:00:00.000Z"}
category marks which endpoint the recall came from (drug / device / food). Date fields are the
API's YYYYMMDD strings parsed best-effort to YYYY-MM-DD (null when absent). isNew is true when
a recall_number was not seen in a previous run (only meaningful with monitorNewOnly). change is
an object when detectChanges is on and the recall's classification escalated or status changed since
a prior run — e.g. { "type": "classification-escalation", "from": "Class III", "to": "Class II" } or
{ "type": "status-change", "from": "Ongoing", "to": "Terminated" } — otherwise null.
Control records (not charged)
Two non-recall records may be pushed to signal run state. Neither triggers a recall-returned charge:
| Record | When | Shape |
|---|---|---|
_noData | The API returned no recalls for the requested filters/window | { "_noData": true, "filters": {...}, "message": "...", "fetchedAt": "..." } |
_error | The fetch failed after retries, or normalization threw | { "_error": true, "filters": {...}, "message": "...", "fetchedAt": "..." } |
_noData keeps a zero-result run green and auditable rather than pushing a silent empty dataset.
Pricing (pay-per-event)
One recall-returned event is charged per record pushed to the dataset. Cost scales with results,
not runtime. Use recallCategories / classifications / statuses / maxResults / monitorNewOnly
to keep spend proportional to signal. (Live price shown on the Store page; see docs/PRICING.md.)
Data source & attribution
openFDA content and data are public domain under a Creative Commons CC0 1.0 Universal dedication — free to copy, modify and redistribute, including commercially, without asking permission. No key and no attribution are required; we credit the FDA / openFDA as a courtesy. Full compliance record: ./COMPLIANCE.md.
openFDA is a research/informational service; recall data may be incomplete or lag the FDA's own systems and is not a substitute for the official recall notices. This Actor relays the data as published; it does not certify accuracy.
Maintenance notes
- Three schemas drift independently — drug / device / food enforcement records carry overlapping-but-not-identical fields; the normalizer is defensive and the kept-field set is documented.
YYYYMMDDstring dates — parsed best-effort toYYYY-MM-DD; the raw values are folded into the normalized fields, absent dates become null.- Weekly refresh — enforcement data updates weekly, so a monitoring schedule should overlap its
report_datewindow run-to-run to avoid missing a late-posted recall. - Change churn — recalls get re-classified and terminated over time;
detectChangesis what turns that churn into events. Theopenfda{}enrichment block is intermittently absent and is not relied on. - Rate limits — keyless access is 240 req/min and 1000/day per IP; large historical pulls should
narrow by category/date or supply an
apiKeyrather than paging past the cap.