FDA Medical Device Recall Search avatar

FDA Medical Device Recall Search

Pricing

from $2.00 / 1,000 recall fetcheds

Go to Apify Store
FDA Medical Device Recall Search

FDA Medical Device Recall Search

FDA Medical Device Recall Search queries the U.S. Food and Drug Administration's openFDA device enforcement endpoint to retrieve detailed, structured data about medical device recalls.

Pricing

from $2.00 / 1,000 recall fetcheds

Rating

0.0

(0)

Developer

Ryan Clinton

Ryan Clinton

Maintained by Community

Actor stats

0

Bookmarked

6

Total users

2

Monthly active users

5 days ago

Last modified

Share

FDA Medical Device Recall Search — know which recalls actually matter

Medical device recall monitoring, supplier risk scoring, and inventory exposure intelligence. Powered by FDA recall and adverse-event data. Know which recalls matter, which suppliers are getting riskier, and whether your inventory is affected, in a single API call.

Most recall tools tell you a recall happened. This actor tells you what to do about it -- is it high risk, is it part of a recurring failure pattern, is the manufacturer deteriorating, does it affect your inventory, what changed since yesterday, and what action to take. Every recall arrives as a decision, not a row:

{
"attentionScore": 94,
"riskTier": "extreme",
"alertLevel": "cluster",
"inventoryMatches": [{ "item": "CRT-D DTBA2D1", "matchType": "model", "confidence": "high" }],
"recommendedAction": "act-immediately"
}

Why teams switch from FDA search tools

QuestionFDA Database / openFDATypical recall feedThis actor
Was there a recall?YesYesYes
How dangerous is it?NoNoYes
How big is it (blast radius)?NoNoYes
Is it part of a recurring failure pattern?NoNoYes
Is the manufacturer deteriorating?NoNoYes
Does it affect my inventory?NoNoYes
What changed since yesterday?NoPartialYes
What should I do?NoNoYes

Everyone else gives you recall data. This actor gives you recall decisions. All deterministic -- no LLM, no API key.

What a raw FDA query returns vs what this returns

A raw openFDA query (or a generic recall feed) hands you fields to interpret yourself:

{
"recalling_firm": "Medtronic, Inc.",
"classification": "Class I",
"status": "Ongoing",
"product_description": "Cardiac Resynchronization Therapy Defibrillator, Model DTBA2D1",
"reason_for_recall": "Firmware may cause an unexpected device reset, potentially resulting in loss of pacing therapy."
}

This actor returns the same recall already scored, routed, and contextualised:

{
"riskScore": 95, "riskTier": "extreme",
"attentionScore": 94,
"blastRadius": { "unitsAffected": 45230, "distributionScope": "worldwide", "reachTier": "large" },
"reasonCategory": "software",
"alertLevel": "cluster", "clusterId": "medtronic-inc-software", "clusterSize": 4,
"recommendedAction": "act-immediately",
"summary": "Class I (critical) recall — Medtronic, Inc.: firmware may cause unexpected device reset… Initiated 2024-06-15; status Ongoing."
}

You stop reading recall records and start working a ranked queue.

The four questions it answers

  • Am I affected? Match recalls against your own device inventory and get a prioritized worklist (inventory -> actionQueue + exposureSummary).
  • Is this systemic or isolated? Cluster detection groups repeat firm + failure-mode recalls (clusterId, largestActiveCluster).
  • Which manufacturer is getting riskier? Manufacturer profiles + manufacturerHealth (supplier risk rating, with an all-firms industryPercentile) + a firm-wide MAUDE adverse-event trend rank suppliers by 12-month behaviour.
  • What changed since yesterday? Watchlist monitoring tags every recall NEW / ESCALATED / RISK_INCREASED / RESOLVED and surfaces newly-formed clusters.

Who uses this

  • Hospital risk teams -- "Which devices in our inventory have active recalls?" -> upload inventory, get a ranked actionQueue.
  • Procurement teams -- "Which manufacturers are becoming riskier?" -> manufacturerHealth + industryPercentile rank suppliers by recall performance.
  • Compliance teams -- "What changed since our last review?" -> watchlistName surfaces only NEW / ESCALATED / RESOLVED.
  • Device safety analysts -- "Which failure modes are increasing?" -> reasonCategory clusters + trendSignals.
  • AI agents -- "Give me structured recall decisions, not raw FDA data." -> every record carries recommendedAction, riskTier, and attentionScore to branch on.

Why this exists

The FDA already provides recall data. Regulatory, procurement, and hospital-risk teams don't need more data -- they need answers: which recalls matter, which suppliers are getting worse, what changed since yesterday, which devices affect them, and what action to take. This actor converts raw FDA recall records into operational intelligence. That is the difference between "we query openFDA" and "here is your worklist."

Four things it does

Inventory exposure -- upload your device inventory, get the affected recalls ranked into a worklist (exposureSummary + actionQueue).

Supplier risk -- rank manufacturers by 12-month recall performance, with a real all-firms percentile and an opt-in MAUDE adverse-event trend.

Recall monitoring -- a scheduled watchlistName run tells you only what changed since yesterday, including newly-forming clusters.

Executive intelligence -- outputMode: "executive" returns a decision-ready brief (headline risk, worsening suppliers, recommended actions) for directors and procurement leads.

Example executive brief

This is what outputMode: "executive" returns from thousands of FDA recall records in one call:

{
"headlineRisk": "high",
"newCriticalRecalls": 11,
"riskTrajectory": { "signal": "worsening", "reasons": ["Class I recalls up 18.2% year-over-year", "2 new failure-mode cluster(s) forming"] },
"worseningManufacturers": ["Medtronic, Inc."],
"recommendedActions": ["Review 12 active Class I recall(s) immediately.", "Reassess suppliers with worsening trend: Medtronic, Inc."]
}

Every recall is also scored two ways -- riskScore (intrinsic danger) and attentionScore (how much you should look, given clusters + your inventory) -- so you can sort straight to "the 10 that matter," and routed with recommendedAction. The implementation details (risk model, watchlists, clusters, MAUDE signals, dashboards) follow below; the decisions above are what you actually consume.

What does FDA Medical Device Recall Search do?

FDA Medical Device Recall Search queries the U.S. Food and Drug Administration's openFDA device enforcement endpoint to retrieve detailed, structured data about medical device recalls. The FDA issues recalls when devices -- from pacemakers and insulin pumps to surgical robots and diagnostic imaging systems -- are found to be defective, mislabeled, or potentially harmful. Four output modes: records for individual triaged recalls, aggregation for top-N leaderboards (firms, product codes, countries, years), dashboard for a single compact digest, and executive for a curated decision brief.

You can search by keyword (matched across product descriptions and recall reasons), recalling company, recall severity classification (Class I/II/III), recall status (Ongoing/Completed/Terminated), U.S. state, and recall initiation date range. Results are always sorted newest first. Each record includes recall identification, severity, company details, product description, reason for recall, distribution scope, lot/serial code information, and four distinct dates covering the full recall lifecycle.

Unlike a raw API dump, every record arrives triaged and scored: a deterministic riskScore (0-100) and riskTier, a normalised severity, an isActive flag, a reasonCategory (failure mode), an exposureIndex (how long an active recall has been live and how widely distributed), a repeatSignal (is this a recurring firm + failure-mode issue), a recommendedAction decision scalar, and a one-line summary an agent can quote verbatim. A run-level summary row mirrors the headline numbers (active Class I count, risk-tier breakdown, recall clusters, top firms) so a downstream node never has to scan the dataset.

It is also a monitoring platform: set a watchlistName and the actor tracks recalls across scheduled runs, tagging each one NEW / ESCALATED / RISK_INCREASED / RESOLVED so you are alerted only on what changed. Opt into manufacturer profiles (a 12-month recall record per firm) and year-over-year trend signals, filter by risk tier / failure mode / active status, match recalls against your own device inventory, or switch to dashboard mode for a single compact digest object built for BI tools and AI agents.

Why use FDA Medical Device Recall Search on Apify?

  • No API complexity -- The openFDA query syntax uses bracket-delimited date ranges, +AND+ joins, and quoted field searches. This actor builds the correct query from simple input fields.
  • Automatic pagination -- openFDA limits responses to 100 records per page with a 25,000 skip ceiling. The actor handles all pagination transparently, fetching up to 5,000 results across multiple API calls.
  • Clean date formatting -- Raw openFDA dates (YYYYMMDD) are converted to standard YYYY-MM-DD format in every output record.
  • Schedule for monitoring -- Run daily or weekly on Apify to catch new device recalls as they are published, with webhook alerts to Slack, email, or any endpoint.
  • No API key required -- The openFDA API is completely free and open. The only cost is minimal Apify platform compute time.

What you also get: risk + attention scoring, inventory exposure, supplier risk ranking, watchlist monitoring

Key features

  • Three output modes -- Records mode returns one triaged row per recall. Aggregation mode returns top-N count buckets so you can answer "which firms had the most recalls last year?" in a single call. Dashboard mode returns one compact digest object (headline risk, active counts, risk-tier breakdown, clusters, top firms, trends) for Power BI / Grafana / Looker / Dify / n8n.
  • Aggregation grouping fields -- group by recalling_firm.exact, product_code.exact, or event_date_initiated.year. Each bucket includes rank, count, share of total, and the filters that produced it.
  • Multi-field keyword search -- Keywords are matched across both product_description and reason_for_recall using OR logic, so you catch recalls whether the term appears in the device name or the defect explanation.
  • Six combinable filters -- Keyword, recalling firm, classification, status, state, and date range can be used in any combination.
  • Date range filtering -- Filter by recall initiation date (the date the firm started the recall), not report date. This gives you the actual timeline of when recalls began.
  • Structured output with a triage layer -- Every record carries the raw FDA fields (recall number, event ID, classification, status, company, product, quantity, reason, distribution, notification, code info, four dates) plus a deterministic intelligence block: severity, isActive, reasonCategory, recommendedAction, and a quotable summary.
  • Deterministic risk scoring -- Every recall gets a riskScore (0-100) and riskTier (extreme / high / moderate / low) from a transparent weighted model (FDA class + active status + worldwide distribution + failure mode + harm language). Sort or filter on it directly — no interpretation needed.
  • Attention score (recall-fatigue cure) -- attentionScore (0-100) layers operational relevance — does it hit your inventory, is it part of a cluster, is it active — on top of intrinsic risk, with attentionReasons. Sort by it to get "show me the 10 that matter" instead of drowning in alerts.
  • Inventory exposure worklist -- With an inventory list, the run returns an exposureSummary (affectedDevices / highRiskAffected / activeAffected / manufacturersAffected) and a prioritized actionQueue — upload inventory, get a worklist.
  • Manufacturer health + supplier risk -- Firm profiles carry a decomposed manufacturerHealth (score, trend, within-cohort rankPercentile, Class I weight, closure performance, repeat-failure weight) and, opt-in, a firm-wide MAUDE adverse-event trend (adverseEventSignal). Answers "should we keep buying from this company?".
  • Executive mode -- outputMode: "executive" returns one curated brief — headline risk, riskTrajectory, top threats, affected and worsening manufacturers, recommended actions — for directors and procurement leads, not analysts.
  • Recall triage intelligence -- severity normalises the FDA class, reasonCategory classifies the failure mode (software, sterility, mechanical, electrical, labeling, …), exposureIndex flags long-running, widely-distributed active recalls, repeatSignal flags recurring firm + failure-mode issues, and recommendedAction (act-immediately / assess-exposure / monitor / informational) is a stable decision scalar that Dify / Zapier / n8n nodes branch on without parsing prose.
  • Manufacturer profiles -- Opt in with includeFirmProfiles to get a kind: "firm-profile" record per top firm: 12-month total / Class I / active recall counts, a riskTrend (worsening / improving / stable), and the failure modes they repeat.
  • Year-over-year trends -- Opt in with includeTrendAnalysis for trendSignals (total and Class I recall counts, last 365 days vs prior 365 days) in the summary / dashboard.
  • Filters that drop from billing -- activeOnly, minimumRiskScore, riskTierFilter, reasonCategoryFilter, country, and distributionContains narrow the output; filtered-out records are excluded from both the dataset and per-record charges.
  • Device inventory matching -- Pass an inventory list of device names / models / lot codes; each recall is tagged with the items it matches, with a deterministic token match (no AI).
  • Run summary row + KV mirror -- A final kind: "summary" record carries coverage, class/status/severity/risk-tier/failure-mode breakdowns, active and active-Class-I counts, recall clusters, top firms (by count and by summed risk), and date range. The same digest is pinned to the SUMMARY key-value store key for agents and MCP clients.
  • Watchlist change tracking -- Set watchlistName to remember recalls across runs. Each record then carries a temporalSignals.changeFlag (NEW, ESCALATED, RISK_INCREASED, RESOLVED, STATUS_CHANGED, REINSTATED, UNCHANGED) plus the previous status / class / risk score, so scheduled monitoring surfaces only what changed.
  • Sorted by recency -- Results always come back with the most recent recalls first (recall_initiation_date:desc).
  1. Navigate to the FDA Medical Device Recall Search actor page on Apify.
  2. Click Try for free to open the actor in Apify Console.
  3. Enter your search parameters. At minimum, provide a keyword like "pacemaker" or a company name like "Medtronic". You can also leave all filters blank to retrieve the most recent recalls across all categories.
  4. Set Max Results to control how many records you want (default 100, maximum 5,000).
  5. Click Start to run the actor.
  6. When the run finishes, view results in the Dataset tab. Export as JSON, CSV, Excel, or access via the Apify API.

Input parameters

ParameterTypeRequiredDefaultDescription
outputModeselectNorecordsrecords (one triaged row per recall), aggregation (top-N buckets), dashboard (single compact digest), or executive (curated decision brief).
aggregateByselectNorecalling_firm.exactWhen outputMode=aggregation: recalling_firm.exact, product_code.exact, event_date_initiated.year, or country.
keywordstringNo"pacemaker" (prefill)Search term matched against product descriptions and recall reasons. Examples: "pacemaker", "insulin pump", "hip implant", "ventilator".
recallingFirmstringNo--Filter by company name. Examples: "Medtronic", "Abbott", "Philips", "Baxter".
classificationselectNo--Recall severity: "Class I" (most serious), "Class II" (moderate), or "Class III" (least serious).
statusselectNo--Recall status: "Ongoing", "Completed", or "Terminated".
statestringNo--Two-letter U.S. state code where the recalling firm is located (e.g., CA, MN, MA). Automatically uppercased.
dateFromstringNo--Start of recall initiation date range (YYYY-MM-DD format).
dateTostringNo--End of recall initiation date range (YYYY-MM-DD format).
maxResultsintegerNo100Maximum recalls (records mode) or buckets (aggregation mode) to return (1--5,000).
watchlistNamestringNo--Records / dashboard mode. Set a name to enable cross-run change tracking (each name keeps its own independent history). Blank = stateless one-off search.
countrystringNo--Filter by recalling firm's country (server-side, e.g. "United States").
activeOnlybooleanNofalseEmit only Ongoing (unresolved) recalls.
minimumRiskScoreintegerNo--Drop recalls below this 0-100 risk score from output and billing.
riskTierFilterarrayNo--Keep only these risk tiers: extreme, high, moderate, low.
reasonCategoryFilterarrayNo--Keep only these failure modes (e.g. software, sterility).
distributionContainsstringNo--Keep only recalls whose distribution pattern contains this substring (e.g. "worldwide").
inventoryarrayNo--Records mode: device names / models / lot codes to match against recalls (inventoryMatches per record).
includeFirmProfilesbooleanNofalseEmit a 12-month manufacturer profile per top firm (a few extra openFDA count queries).
includeTrendAnalysisbooleanNofalseAdd year-over-year trendSignals to the summary / dashboard.
includeAdverseEventsbooleanNofalseWith manufacturer profiles, add a firm-wide MAUDE adverse-event trend (adverseEventSignal) per profile.

Templates (copy-paste use cases)

Hospital inventory monitoring -- which of your devices have active recalls, ranked into a worklist:

{
"inventory": ["CRT-D DTBA2D1", "Alaris 8100 infusion pump", "Synchromed II"],
"activeOnly": true,
"watchlistName": "our-inventory",
"maxResults": 1000
}

Procurement supplier risk review -- rank a manufacturer's recall behaviour with peer percentile and adverse-event trend:

{
"recallingFirm": "Medtronic",
"includeFirmProfiles": true,
"includeAdverseEvents": true,
"includeTrendAnalysis": true,
"outputMode": "executive"
}

Pacemaker recall watchlist -- scheduled cohort monitor, alert only on what changed:

{
"keyword": "pacemaker",
"watchlistName": "pacemakers",
"includeTrendAnalysis": true,
"maxResults": 500
}

Infusion pump safety monitoring -- Class I + active only, executive brief:

{
"keyword": "infusion pump",
"classification": "Class I",
"status": "Ongoing",
"outputMode": "executive"
}

Input examples

Basic keyword search (pacemaker):

{
"keyword": "pacemaker",
"maxResults": 100
}

Company + Class I recalls:

{
"recallingFirm": "Medtronic",
"classification": "Class I",
"maxResults": 500
}

Date range + state filter:

{
"keyword": "insulin pump",
"state": "CA",
"dateFrom": "2024-01-01",
"dateTo": "2024-12-31",
"maxResults": 200
}

All recent recalls (no filters):

{
"maxResults": 100
}

Aggregation mode -- top recalling firms for Class I recalls in 2024:

{
"outputMode": "aggregation",
"aggregateBy": "recalling_firm.exact",
"classification": "Class I",
"dateFrom": "2024-01-01",
"dateTo": "2024-12-31",
"maxResults": 25
}

Aggregation mode -- year-over-year recall trend for Medtronic:

{
"outputMode": "aggregation",
"aggregateBy": "event_date_initiated.year",
"recallingFirm": "Medtronic",
"maxResults": 20
}

Tips for best results

  • Be specific with keywords. Terms like "insulin pump" or "cardiac defibrillator" return more targeted results than generic terms like "device" or "medical".
  • Combine filters for precision. Use keyword plus classification together to find, for example, all Class I recalls related to surgical robots.
  • Date ranges use recall initiation date. This is the date the firm initiated the recall -- not the date FDA classified it or the date it was reported to the FDA.
  • State codes are auto-uppercased. You can enter "ca" or "CA" -- both work.
  • Leave all filters blank to get the most recent recalls across all device categories, useful for general monitoring dashboards.
  • Use date ranges for trend analysis. Split long time periods into smaller windows if you need more than 5,000 results for a given query.

Output example

Sample output: recalling firm, risk tier, attention score, failure mode, alert level, recommended action

Every row carries a kind discriminator: "record" for individual recalls, "aggregation" for count buckets. Filter kind === "aggregation" downstream to isolate leaderboard rows.

Records mode

{
"kind": "record",
"recallNumber": "Z-0839-2024",
"eventId": "92134",
"classification": "Class I",
"status": "Ongoing",
"recallingFirm": "Medtronic, Inc.",
"city": "Minneapolis",
"state": "MN",
"country": "United States",
"productDescription": "Cardiac Resynchronization Therapy Defibrillator (CRT-D), Model DTBA2D1, used for the treatment of heart failure in patients who also have ventricular arrhythmias.",
"productQuantity": "45,230",
"reasonForRecall": "The firmware in the device may cause an unexpected device reset during normal operation, potentially resulting in loss of pacing therapy.",
"distributionPattern": "Worldwide Distribution -- US (nationwide) and international including EU, Canada, Japan, Australia.",
"voluntaryMandated": "Voluntary: Firm Initiated",
"initialNotification": "Letter",
"codeInfo": "Serial numbers: PXR1000001 through PXR1045230, manufactured between January 2022 and March 2024.",
"recallDate": "2024-06-15",
"classificationDate": "2024-07-02",
"reportDate": "2024-06-28",
"terminationDate": null,
"severity": "critical",
"isActive": true,
"reasonCategory": "software",
"riskScore": 95,
"riskTier": "extreme",
"exposureIndex": { "level": "high", "daysActive": 540, "worldwide": true },
"repeatSignal": { "isRepeatIssue": true, "occurrencesInResultSet": 4, "category": "software" },
"recallDurationDays": null,
"closureSpeed": null,
"alertLevel": "cluster",
"clusterId": "medtronic-inc-software",
"clusterSize": 4,
"clusterType": "firm_failure_mode",
"blastRadius": { "unitsAffected": 45230, "distributionScope": "worldwide", "reachTier": "large" },
"attentionScore": 92,
"attentionReasons": ["extreme intrinsic risk", "part of a recall cluster", "recall is active"],
"recommendedAction": "act-immediately",
"summary": "Class I (critical) recall — Medtronic, Inc.: The firmware in the device may cause an unexpected device reset during normal operation, potentially resulting in loss of pacing therapy. Initiated 2024-06-15; status Ongoing.",
"extractedAt": "2025-01-15T14:32:08.123Z"
}

When watchlistName is set, each record additionally carries a temporalSignals block:

{
"temporalSignals": {
"changeFlag": "ESCALATED",
"previousStatus": "Ongoing",
"previousClassification": "Class II",
"firstSeenAt": "2026-05-01T09:00:00.000Z",
"runsSeen": 3
}
}

Summary row

The final record in every records-mode run is a kind: "summary" digest (also mirrored to the SUMMARY key-value store key):

{
"kind": "summary",
"coverage": { "totalMatching": 3510, "returned": 100, "truncated": true },
"classBreakdown": { "Class I": 18, "Class II": 71, "Class III": 11 },
"statusBreakdown": { "Ongoing": 42, "Terminated": 58 },
"severityBreakdown": { "critical": 18, "moderate": 71, "low": 11, "unknown": 0 },
"reasonCategoryBreakdown": { "software": 22, "mechanical": 19, "labeling": 14, "sterility": 9, "other": 36 },
"activeCount": 42,
"criticalActiveCount": 7,
"dominantRisk": "critical",
"topFirms": [{ "firm": "Medtronic, Inc.", "count": 12 }, { "firm": "Abbott", "count": 8 }],
"dateRange": { "earliest": "2026-01-04", "latest": "2026-04-22" },
"watchlist": null,
"summary": "100 device recall(s) returned of 3,510 matching. 42 active, 7 active Class I (critical). Top firm: Medtronic, Inc. (12).",
"extractedAt": "2026-05-08T10:00:00.000Z"
}

Aggregation mode

Top recalling firms for Class I recalls in 2024 (aggregateBy: "recalling_firm.exact"):

[
{ "kind": "aggregation", "aggregateBy": "recalling_firm.exact", "rank": 1, "term": "Medtronic, Inc.", "count": 142, "share": 0.0834, "totalMatching": 1703, "queryFilters": { "keyword": null, "recallingFirm": null, "classification": "Class I", "status": null, "state": null, "dateFrom": "2024-01-01", "dateTo": "2024-12-31" }, "extractedAt": "2026-05-08T10:00:00.000Z" },
{ "kind": "aggregation", "aggregateBy": "recalling_firm.exact", "rank": 2, "term": "Baxter Healthcare Corporation", "count": 98, "share": 0.0575, "totalMatching": 1703, "queryFilters": { "keyword": null, "recallingFirm": null, "classification": "Class I", "status": null, "state": null, "dateFrom": "2024-01-01", "dateTo": "2024-12-31" }, "extractedAt": "2026-05-08T10:00:00.000Z" }
]

Year-over-year recall trend for Medtronic (aggregateBy: "event_date_initiated.year"):

[
{ "kind": "aggregation", "aggregateBy": "event_date_initiated.year", "rank": 1, "term": "2024", "count": 87, "share": 0.0412, "totalMatching": 2113, "queryFilters": { "keyword": null, "recallingFirm": "Medtronic", "classification": null, "status": null, "state": null, "dateFrom": null, "dateTo": null }, "extractedAt": "2026-05-08T10:00:00.000Z" },
{ "kind": "aggregation", "aggregateBy": "event_date_initiated.year", "rank": 2, "term": "2023", "count": 74, "share": 0.0350, "totalMatching": 2113, "queryFilters": { "keyword": null, "recallingFirm": "Medtronic", "classification": null, "status": null, "state": null, "dateFrom": null, "dateTo": null }, "extractedAt": "2026-05-08T10:00:00.000Z" }
]

Output fields reference

FieldTypeDescription
recallNumberstringUnique FDA recall identification number (e.g., "Z-0839-2024")
eventIdstringFDA event ID grouping related recall records
classificationstringSeverity level: "Class I", "Class II", or "Class III"
statusstringCurrent recall status: "Ongoing", "Completed", or "Terminated"
recallingFirmstringName of the company responsible for the recall
citystringCity where the recalling firm is located
statestringU.S. state where the recalling firm is located (two-letter code)
countrystringCountry where the recalling firm is located
productDescriptionstringDetailed description of the recalled medical device
productQuantitystringNumber or description of units affected
reasonForRecallstringThe specific defect or issue that triggered the recall
distributionPatternstringGeographic scope of where the device was distributed
voluntaryMandatedstringWhether the recall was voluntary or FDA-mandated
initialNotificationstringHow the firm initially notified customers (e.g., "Letter", "Press Release")
codeInfostringLot numbers, serial numbers, or other identifying codes for affected units
recallDatestringDate the firm initiated the recall (YYYY-MM-DD)
classificationDatestringDate the FDA classified the recall severity (YYYY-MM-DD)
reportDatestringDate the recall was reported to the FDA (YYYY-MM-DD)
terminationDatestring or nullDate the recall was terminated (YYYY-MM-DD), or null if still active
severitystringNormalised severity: critical (Class I), moderate (Class II), low (Class III), unknown
isActivebooleantrue when status is Ongoing (recall unresolved)
reasonCategorystringFailure-mode category from the recall text: software, sterility, contamination, biocompatibility, electrical, mechanical, measurement, material, packaging, labeling, manufacturing, design, other
riskScoreintegerDeterministic 0-100 risk score (class + active + worldwide + failure mode + harm language)
riskTierstringextreme (≥80), high (≥60), moderate (≥35), low (<35)
exposureIndexobject{ level (high/medium/low/none), daysActive, worldwide } — live exposure of an unresolved recall
repeatSignalobject{ isRepeatIssue, occurrencesInResultSet, category } — recurrence of this firm + failure mode within this query's result set (varies with maxResults; for stable firm history use includeFirmProfiles)
recallDurationDaysinteger or nullDays from initiation to termination; null while active
closureSpeedstring or nullfast (<90d) / average (90-270d) / slow (>270d); null while active
alertLevelstringcluster (in a firm + failure-mode cluster) / elevated (extreme/high tier) / normal
blastRadiusobject"How big is this problem?" — { unitsAffected (parsed, null if unclear), distributionScope, reachTier }
clusterIdstring or nullStable id of the firm + failure-mode cluster (3+ in the result set); null when not clustered
clusterSizeinteger or nullRecalls in this recall's cluster
clusterTypestring or nullfirm_failure_mode when clustered
attentionScoreintegerContextual triage 0-100 (risk + cluster + inventory + active). Sort by this to cut alert fatigue
attentionReasonsarrayWhy the attention score is what it is
inventoryMatchesarray or absentPresent only when inventory is set: [{ item, matchType (model/name/generic), confidence (high/medium/low) }]
inventoryConfidencestring or absentHighest match confidence among this recall's inventory matches
recommendedActionstringDecision scalar: act-immediately, assess-exposure, monitor, informational
summarystringQuotable one-line summary (≤280 chars) for LLM/agent use
temporalSignalsobject or absentPresent only when watchlistName is set: { changeFlag, previousStatus, previousClassification, firstSeenAt, runsSeen }
extractedAtstringISO 8601 timestamp of when the data was extracted
kindstring"record" for recalls, "summary" for the run digest, "aggregation" for leaderboard rows

Output fields -- aggregation mode

FieldTypeDescription
kindstringAlways "aggregation" in aggregation mode
aggregateBystringField used for grouping (e.g., "recalling_firm.exact", "pathway")
rankinteger1-based bucket position (sorted by count descending)
termstringBucket value (e.g., a firm name, a year "2024", or "PMA"/"non-PMA")
countintegerNumber of recalls in this bucket
sharenumbercount / totalMatching (0--1)
totalMatchingintegerTotal recalls matching the query filters
queryFiltersobjectEcho of the filters that produced this aggregation, for traceability
extractedAtstringISO 8601 timestamp of when the aggregation was computed

Recall triage and watchlist intelligence

The actor adds a deterministic decision layer on top of the raw FDA fields. Nothing here uses an LLM or randomness — the same recall always produces the same severity, category, and action, so the output is reproducible and auditable.

Per-record triage

FieldHow it is derivedWhat to branch on
attentionScoreriskScore + cluster + inventory hit + activeSort by this for "the N that matter to me"; cuts recall fatigue
riskScoreWeighted model (see below)Sort the whole dataset by intrinsic risk; threshold with minimumRiskScore
riskTierriskScore bandextreme / high / moderate / low badge for UI + Slack
severityFDA class → critical (I) / moderate (II) / low (III)Filter or sort by class without parsing "Class I/II/III" strings
isActivestatus === "Ongoing"Surface only unresolved recalls
reasonCategoryKeyword match over reasonForRecall + productDescription against a fixed failure-mode lexicon"Show me every software / sterility / mechanical recall"
exposureIndexactive status + days since recall + worldwide distributionFind long-running, widely-distributed open recalls
repeatSignalfirm + failure-mode recurrence in the result setSpot chronic engineering failures
blastRadiusunits affected + distribution scope"How big is this problem?" — sort by reachTier
alertLevelcluster membership + risk tiercluster / elevated / normal one-glance badge
clusterId / clusterSize3+ same firm + failure mode in the setTell a systemic problem from an isolated recall
recallDurationDays / closureSpeedtermination date − recall dateSpot firms that close recalls slowly (slow >270d)
recommendedActionseverity × isActiveRoute the record: act-immediately, assess-exposure, monitor, informational
summaryTemplated one-linerQuote directly in an LLM prompt, Slack message, or email

Risk score model (deterministic, capped at 100): Class I +40 / Class II +15 / Class III +5; active (Ongoing) +20; worldwide/nationwide distribution +10; sterility or contamination failure +15; software / electrical / mechanical failure +5; explicit harm language (death, injury, life-threatening, loss of therapy) +20. Tiers: extreme ≥80, high ≥60, moderate ≥35, low <35.

recommendedAction mapping: a critical + active recall is act-immediately; critical but resolved is assess-exposure; moderate + active is assess-exposure; moderate + resolved is monitor; low is monitor (active) or informational (resolved).

Watchlist mode (cross-run change tracking)

Set watchlistName to turn a one-off search into a monitored feed. The actor stores a snapshot of every recall it sees (keyed by the stable FDA recallNumber) in a named key-value store unique to that watchlist name, then diffs the current run against the last one:

  • NEW -- not seen in any prior run under this name.
  • ESCALATED -- the recall was re-classified to a more severe class (e.g. Class II → Class I).
  • RISK_INCREASED -- the riskScore rose by 10+ points since last run without a class change (e.g. it went active, or distribution widened).
  • RESOLVED -- was Ongoing, now Terminated/Completed.
  • REINSTATED -- was Terminated, now Ongoing again.
  • STATUS_CHANGED -- status changed in some other way.
  • UNCHANGED -- identical to last run.

The first run under a new name tags everything NEW (logged explicitly). Schedule the same watchlistName daily or weekly and filter temporalSignals.changeFlag in (NEW, ESCALATED, RISK_INCREASED, REINSTATED) to alert only on what actually changed. Each record also carries previousStatus, previousClassification, and previousRiskScore. Each watchlist name keeps its own independent, bounded history (most recent 25,000 recalls).

Monitor a device cohort, not individual recalls. Set a keyword (e.g. "infusion pump", "pacemaker", "imaging system") plus a watchlistName and includeTrendAnalysis, and a scheduled run becomes a cohort monitor: the summary gives the cohort's active and Class I counts, trendSignals shows whether that category's recall rate is rising, and the watchlist surfaces only what changed. One actor, one schedule, per device family.

Run summary record

Every records-mode run ends with one kind: "summary" row carrying coverage, the class/status/severity/risk-tier/failure-mode breakdowns, active and active-Class-I counts, recall clusters, top firms (by count and by summed risk), and the date range of the returned set. The identical object is written to the SUMMARY key-value store key, so an agent or MCP client can read the run's headline risk picture with a single KV fetch instead of paging the dataset.

Dashboard mode

Set outputMode: "dashboard" to skip the per-recall rows and emit a single compact kind: "dashboard" digest, also pinned to the SUMMARY KV key:

{
"kind": "dashboard",
"headlineRisk": "extreme",
"totalReturned": 200,
"activeRecalls": 84,
"classIActive": 12,
"riskTierBreakdown": { "extreme": 14, "high": 31, "moderate": 96, "low": 59 },
"reasonCategoryBreakdown": { "software": 41, "mechanical": 33, "sterility": 12, "other": 114 },
"topFirms": [{ "firm": "Medtronic, Inc.", "count": 18 }],
"riskWeightedTopFirms": [{ "firm": "Medtronic, Inc.", "riskTotal": 1240, "riskAverage": 69 }],
"clusters": [{ "firm": "Medtronic, Inc.", "category": "software", "count": 6 }],
"newClusters": [{ "firm": "Abbott", "category": "electrical", "count": 3 }],
"mostDangerousFirm": "Medtronic, Inc. (risk 1240)",
"mostCommonFailureMode": "software",
"largestActiveCluster": "Medtronic, Inc. — software (6)",
"largestRiskIncrease": "New cluster: Abbott — electrical (3)",
"newThisRun": 11,
"escalatedThisRun": 2,
"riskIncreasedThisRun": 4,
"trendSignals": { "classITrendPct": 18.2, "totalTrendPct": 6.4, "window": "last 365 days vs prior 365 days", "note": "Total recalls: 3120 → 3320. Class I: 412 → 487." }
}

It is the ideal shape for a BI tile, a Dify/n8n variable, or an exec alert: one object, the four "15-second" answers (mostDangerousFirm, mostCommonFailureMode, largestActiveCluster, largestRiskIncrease), all the headline numbers, no dataset paging. riskWeightedTopFirms carries both riskTotal and riskAverage so a firm with many low-risk recalls doesn't outrank one with fewer severe ones. trendSignals is populated when includeTrendAnalysis is set; the watchlist deltas (newThisRun, escalatedThisRun, riskIncreasedThisRun, newClusters) are populated when watchlistName is set.

Executive mode

Set outputMode: "executive" for a single curated kind: "executive" brief aimed at directors and procurement leads — not analysts. It auto-builds manufacturer profiles to surface worsening suppliers:

{
"kind": "executive",
"headlineRisk": "high",
"activeRecalls": 84,
"classIActive": 12,
"riskTrajectory": { "signal": "worsening", "reasons": ["Class I recalls up 18.2% year-over-year", "2 new failure-mode cluster(s) forming"] },
"topThreats": [{ "device": "Cardiac Resynchronization Therapy Defibrillator", "recallNumber": "Z-0839-2024", "recallingFirm": "Medtronic, Inc.", "priority": "urgent", "attentionScore": 92, "riskTier": "extreme", "recommendedAction": "act-immediately", "matchedInventory": [] }],
"affectedManufacturers": [{ "firm": "Medtronic, Inc.", "count": 18 }],
"worseningManufacturers": ["Medtronic, Inc."],
"newCriticalRecalls": 11,
"exposureSummary": null,
"recommendedActions": ["Review 12 active Class I recall(s) immediately.", "Reassess suppliers with worsening trend: Medtronic, Inc."]
}

riskTrajectory is a deterministic "is this getting worse?" read built from trends + new clusters + risk movement; recommendedActions are templated next steps (no LLM). Pair with includeTrendAnalysis for the trajectory and watchlistName for newCriticalRecalls.

Manufacturer profiles

Set includeFirmProfiles: true to emit a kind: "firm-profile" record for each of the top firms in the result set, built from openFDA count queries:

{
"kind": "firm-profile",
"firm": "Medtronic, Inc.",
"totalRecalls12m": 42,
"classIRecalls12m": 7,
"activeRecalls": 9,
"riskTrend": "worsening",
"manufacturerScore": 62,
"manufacturerTier": "elevated",
"manufacturerHealth": { "score": 62, "trend": "worsening", "trend3y": "worsening", "rankPercentile": 88, "industryPercentile": 99, "confidence": "high", "classIWeight": 28, "closurePerformance": 34, "repeatFailureWeight": 10 },
"adverseEventSignal": { "manufacturerLevel": true, "adverseEventsRecent": 4120, "adverseEventsPrior": 3110, "trendPct": 32.5, "signalStrength": "rising", "window": "two 180-day windows ending 90 days ago (MAUDE reporting lag buffer)", "note": "Firm-wide MAUDE reports: 3110 → 4120. Manufacturer-level, not device-specific." },
"repeatFailureCategories": ["software", "electrical"],
"inResultSet": 18
}

This answers the question procurement and hospital risk teams actually ask — "should I trust this manufacturer?" — not just "was this device recalled?". manufacturerScore (0-100) + manufacturerTier let you rank firms; manufacturerHealth decomposes the score so the number is auditable: trend (6mo) and trend3y (3-year horizon), rankPercentile (vs the firms profiled this run), industryPercentile (the firm's standing by 12-month recall volume among all recalling firms, a real peer comparison, not a within-run one), a confidence (high / medium / low, from how many recalls the score rests on, so a 99th-percentile ranking off 2 recalls reads low not signal), classIWeight, closurePerformance (% of closed recalls that closed slowly), and repeatFailureWeight. With includeAdverseEvents, adverseEventSignal adds a firm-wide MAUDE adverse-event trend — manufacturer-level, not device-specific (enforcement records carry no reliable device join key), and lag-buffered because MAUDE data publishes ~3-6 months behind.

Device inventory matching

Pass an inventory list of device names, models, or lot/serial codes you own. Each returned recall is tagged with the inventory items it matches (inventoryMatches), with a matchType (model / name / generic) and confidence (high / medium / low) per match and a top-level inventoryConfidence for the strongest. The match is deterministic token matching against the product description, code info, and firm name — no AI.

The run also returns a worklist: an exposureSummary ({ affectedDevices, highRiskAffected, activeAffected, manufacturersAffected }) and a prioritized actionQueue of the matched recalls sorted by attention score, each with a priority (urgent / high / medium / low). Upload inventory → get a ranked list of what to act on. Both appear in the summary, dashboard, and executive records.

Cluster detection

When 3+ recalls in the result set share the same firm and failure mode, they form a cluster. Each clustered record carries clusterId, clusterSize, clusterType: "firm_failure_mode", and alertLevel: "cluster"; the summary and dashboard list every cluster (clusters). This is the difference between one recall = an issue and six recalls = a systemic problem. With watchlistName set, clusters that did not exist on the previous run are reported as newClusters — the alert a quality team wants the moment a manufacturer's failure mode starts repeating.

How it works

Intelligence stack: FDA device recalls through triage, risk scoring, blast radius, clustering, manufacturer health, inventory exposure, watchlist diff, to decision output

Input (keyword, recallingFirm, classification, status, state, dateFrom, dateTo, watchlistName)
|
v
+-----------------------------------------------------------+
| Query Builder |
| - Joins all filter clauses with +AND+ |
| - Keywords: OR across product_description |
| and reason_for_recall |
| - Dates: strip dashes, wrap in [FROM+TO+TO] |
| - Special chars (+, &, |, parens) stripped from keywords |
+----------------------------+------------------------------+
|
v
+-----------------------------------------------------------+
| Paginated Fetch |
| api.fda.gov/device/enforcement.json |
| ?limit=100&skip=N&sort=recall_initiation_date:desc |
| &search=<query> |
| |
| - 100 results per page (openFDA maximum) |
| - Stops at maxResults, end of data, or skip >= 25000 |
| - First-page 404 = no results found |
| - Later-page 404 = end of available data |
+----------------------------+------------------------------+
|
v
+-----------------------------------------------------------+
| Transform + Triage |
| - Raw FDA fields + dates YYYYMMDD -> YYYY-MM-DD |
| - severity / isActive / reasonCategory derived |
| - recommendedAction decision scalar |
| - summary one-liner |
| - temporalSignals (when watchlistName set) |
+----------------------------+------------------------------+
|
v
+-----------------------------------------------------------+
| Output & Summary |
| - Stream each triaged record to the dataset |
| - Diff against prior run (watchlist mode) |
| - Emit a kind:"summary" digest row |
| - Mirror the digest to the SUMMARY KV key |
+-----------------------------------------------------------+

openFDA query construction

The actor maps each input field to an openFDA query fragment, then joins all fragments with +AND+:

Input fieldQuery fragmentExample
keyword(product_description:"K"+reason_for_recall:"K")(product_description:"pacemaker"+reason_for_recall:"pacemaker")
recallingFirmrecalling_firm:"FIRM"recalling_firm:"Medtronic"
classificationclassification:"CLASS"classification:"Class I"
statusstatus:"STATUS"status:"Ongoing"
statestate:"ST" (uppercased)state:"CA"
dateFrom / dateTorecall_initiation_date:[FROM+TO+TO]recall_initiation_date:[20240101+TO+20241231]

The keyword field uses OR logic (the + between quoted field searches inside parentheses acts as OR in openFDA syntax). Special characters (+, &, |, (, )) in keyword input are stripped before querying to prevent malformed API calls.

Date handling

Input dates in YYYY-MM-DD format have their dashes stripped to produce the YYYYMMDD format required by the openFDA API. For example, an input of "2024-01-15" becomes 20240115 in the query. If only dateFrom is specified, the range extends to 20991231. If only dateTo is specified, the range starts from 19000101. The formatDate() function reverses this for output, converting raw YYYYMMDD responses back to YYYY-MM-DD using substring slicing.

Skip-based pagination and the 25,000 limit

The openFDA API uses skip-based pagination (not cursor-based). Each request specifies a skip offset and a limit (max 100). The actor increments skip by the number of results received after each page. Pagination stops when any of three conditions are met: the total number of collected results reaches maxResults, a page returns fewer results than requested (end of data), or skip reaches 25,000 (the hard ceiling imposed by the openFDA API). The page size is also optimized on the final page: Math.min(100, maxResults - collected) to avoid over-fetching.

404 handling

The openFDA API returns HTTP 404 when no records match a query -- not a 200 with an empty array. The actor distinguishes between two cases: if the 404 occurs on the first page (no results collected yet), it means the search matched nothing and outputs a diagnostic message. If the 404 occurs on a subsequent page, it simply means pagination has reached the end of available data, and the actor stops fetching.

Recall classification levels

FDA classifies every device recall into one of three severity levels based on the potential health risk:

  • Class I: Most serious. The device could cause serious adverse health consequences or death.
  • Class II: Moderate. The device may cause temporary or medically reversible adverse health consequences, or the probability of serious harm is remote.
  • Class III: Least serious. The device is unlikely to cause adverse health consequences but still violates FDA regulations.

Understanding the three date fields

Each recall record contains three (sometimes four) dates that represent different milestones in the recall lifecycle:

Date fieldMeaning
recallDateThe date the recalling firm initiated the recall. This is the primary date used for sorting and filtering.
reportDateThe date the recall was reported to the FDA. Typically the same day or shortly after the recall initiation date.
classificationDateThe date the FDA officially classified the recall severity (Class I, II, or III). This is unique to the device endpoint and provides insight into how quickly the FDA assessed severity. It often comes days or weeks after the recall initiation.
terminationDateThe date the recall was terminated (closed). This field is null for ongoing recalls and only populated when the recall has been completed and formally terminated.

How much does it cost to run?

ScenarioRecordsAPI callsApprox. timeEst. cost
Quick keyword search1001~5 sec~$0.002
Company monitoring200--5002--5~10 sec~$0.005
Date range trend analysis1,00010~30 sec~$0.008
Maximum extraction5,00050~90 sec~$0.02

The openFDA API is completely free with no API key required. Apify's free tier includes $5 of monthly platform credits, enough for hundreds of runs of this actor.

Limitations

  1. 25,000 skip ceiling -- The openFDA API stops returning results after a skip offset of 25,000. For very large result sets, use date range filters to split queries into smaller time windows.
  2. 5,000 result cap -- The actor limits output to 5,000 records per run for practical performance.
  3. Keyword searches three fields -- Keywords match product_description, reason_for_recall, and code_info (so model and lot numbers are searchable). Matching is phrase-based, not fuzzy; openFDA has no fuzzy-search operator.
  4. State filter is firm location -- The state filter matches where the recalling firm is headquartered, not where the device was distributed. Check the distributionPattern output field for geographic distribution scope.
  5. Date format required -- Dates must be entered in YYYY-MM-DD format. Other formats will produce incorrect API queries.
  6. Device recalls only -- This actor covers the /device/enforcement.json endpoint. For drugs, food, or other FDA data, use the corresponding specialized actors listed in the Related Actors section.

Responsible use

  • A recall does not always mean a device is dangerous. Class III recalls address regulatory violations that are unlikely to cause harm. Always check the classification and reason fields for context.
  • When publishing or sharing recall data, provide appropriate context about recall severity and status.
  • Consult healthcare professionals and the FDA directly for clinical decisions.
  • Follow the openFDA Terms of Service when using the data.

FDA recall classification reference

ClassSeverityDescription
Class IMost seriousCould cause serious health problems or death
Class IIModerateMay cause temporary or reversible health problems
Class IIILeast seriousUnlikely to cause adverse health effects

Programmatic access

Python:

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("ryanclinton/fda-device-recalls").call(run_input={
"keyword": "pacemaker",
"classification": "Class I",
"maxResults": 200,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"[{item['classification']}] {item['recallingFirm']}: {item['reasonForRecall'][:80]}")
print(f" Recall #{item['recallNumber']} | Date: {item['recallDate']} | Status: {item['status']}")

JavaScript:

import { ApifyClient } from "apify-client";
const client = new ApifyClient({ token: "YOUR_API_TOKEN" });
const run = await client.actor("ryanclinton/fda-device-recalls").call({
keyword: "pacemaker",
classification: "Class I",
maxResults: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const classI = items.filter((r) => r.classification === "Class I");
console.log(`Found ${classI.length} Class I pacemaker recalls`);

cURL:

# Start a run
curl "https://api.apify.com/v2/acts/ryanclinton~fda-device-recalls/runs" \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"keyword": "pacemaker",
"classification": "Class I",
"maxResults": 200
}'
# Fetch results (after run completes)
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=json" \
-H "Authorization: Bearer YOUR_API_TOKEN"

FAQ

Do I need an API key? No. The openFDA API is completely free and requires no authentication. You only need an Apify account to run the actor.

How current is the recall data? The openFDA database is updated regularly by the FDA. Most recalls appear within days of being officially announced.

What is the difference between Class I, II, and III recalls? Class I is the most serious -- the device could cause serious injury or death. Class II means the device may cause temporary or reversible health problems. Class III means the device is unlikely to cause harm but still violates FDA regulations.

What is the classificationDate field? This is the date the FDA officially classified the recall severity (Class I, II, or III). It typically comes after the recall initiation date and provides insight into how quickly the FDA assessed severity. This field is unique to the device enforcement endpoint.

Can I get more than 5,000 results? The actor caps at 5,000 for performance reasons, and the openFDA API limits pagination to 25,000 records. For larger datasets, use date range filters to split queries into smaller time windows and combine the results across multiple runs.

What happens if no results match my filters? The actor outputs a single record with error: true, failureType: "no-data", and a "No device recalls found" message, so you can tell "nothing matched" apart from "the API failed" (failureType is timeout, invalid-input, or api-error on genuine failures). The openFDA API returns a 404 when no results match, which the actor handles gracefully.

Use cases

  • Medical device safety monitoring -- Track recalls for specific device categories (pacemakers, insulin pumps, imaging systems) with scheduled daily or weekly runs and webhook alerts to Slack or email.
  • Supplier due diligence -- Investigate a device manufacturer's recall history before procurement decisions. Filter by company name to see all past enforcement actions.
  • Regulatory compliance -- Monitor Class I and Class II recalls in your product category for compliance reporting and risk management.
  • Healthcare facility risk management -- Track recalls for devices in your hospital or clinic inventory. Cross-reference recall numbers with your asset management system.
  • Insurance and liability analysis -- Analyze recall patterns by classification, company, and time period to assess medical device liability risk.
  • Journalism and public interest -- Investigate device safety trends, repeat offenders, or geographic patterns in FDA enforcement actions.
  • Post-market surveillance research -- Combine with the FDA Device Adverse Events (MAUDE) actor to correlate adverse event reports with recall actions for specific device types.

Use in Dify

Drop this actor into Dify workflows via the Apify plugin's Run Actor node. Each recall returns triaged, classified, and recommended as structured JSON — act-immediately / assess-exposure / monitor / informational plus the severity and reasonCategory enums your downstream node branches on. A scraper pointed at the FDA recall pages returns raw HTML; this returns decisions.

  • Actor ID: ryanclinton/fda-device-recalls
  • Sample input (monitor a device category and act only on critical, unresolved recalls):
{
"keyword": "infusion pump",
"classification": "Class I",
"status": "Ongoing",
"watchlistName": "infusion-pumps",
"maxResults": 200
}

A Dify if/else node routes each record on the stable recommendedAction enum without parsing any prose:

IF recommendedAction == "act-immediately" → page the on-call quality lead (Slack/PagerDuty)
ELIF recommendedAction == "assess-exposure" → open a review task with the recall number
ELIF recommendedAction == "monitor" → append to the weekly digest
ELSE (informational) → archive

Layer a second branch on riskTier == "extreme", sort by attentionScore for "only the recalls that matter to me", route on reasonCategory (every software or sterility recall to a specialist), or branch on temporalSignals.changeFlag in ("ESCALATED", "RISK_INCREASED") when watchlistName is set — so a scheduled Dify run alerts only when a recall gets more dangerous. For a dashboard tile set outputMode: "dashboard" and read headlineRisk / classIActive / newThisRun; for a director-level summary set outputMode: "executive" and read riskTrajectory / recommendedActions / topThreats straight off the single object. The per-record summary string is usable verbatim in the notification body; no LLM rewriting required.

FDA regulatory intelligence suite

ActorDescriptionUse together for
FDA 510(k) Device ClearancesPre-market 510(k) clearance searchPre-market clearance to post-market recall pipeline
FDA PMA Device ApprovalsClass III PMA approval searchHigh-risk device approval to recall correlation
FDA Device Adverse Events (MAUDE)Medical device adverse event reportsAdverse event signals leading to recall actions
FDA Drug Approval SearchNDA/ANDA/BLA drug approval searchCross-domain FDA approval monitoring
openFDA Drug Event MonitorFDA adverse drug event reports (FAERS)Full FDA safety monitoring across drugs and devices
FDA Drug Recall SearchFDA drug enforcement actionsComplete recall coverage across drugs and devices
FDA Food Recall MonitorFDA food enforcement actionsComplete FDA recall monitoring across all product types
FDA Food Adverse Events (CAERS)Food/supplement adverse event reportsFull adverse event coverage across FDA domains
FDA Product IntelligenceCross-domain FDA intelligence with risk assessmentSingle query across all 9 openFDA endpoints
FDA Intelligence MCPMCP server with 11 FDA toolsAI agent access to the full FDA intelligence suite

Other safety and regulatory actors

ActorDescriptionUse together for
CPSC Product Recall MonitorU.S. Consumer Product Safety Commission recallsMulti-agency product safety tracking
Clinical Trial TrackerClinicalTrials.gov clinical study dataDevice trials to post-market recall surveillance
NHTSA Vehicle Safety SearchVehicle recall and complaint dataComprehensive U.S. safety recall coverage