# FDA Enforcement History Research (`ledgerstar/fda-enforcement-research`) Actor

Historical corporate research across FDA food, drug, and device enforcement index records. Not for safety alerts or recall lifecycle tracking.

- **URL**: https://apify.com/ledgerstar/fda-enforcement-research.md
- **Developed by:** [Ledger Star](https://apify.com/ledgerstar) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 fda research results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## FDA Enforcement History Research

Research FDA food, drug, and device enforcement history for corporate supplier intelligence.

![FDA enforcement research overview](https://raw.githubusercontent.com/ledgerstar/assets/main/fda-enforcement-research/cover-v1.png)

### What you get

- One structured row for a qualifying family-specific corporate enforcement record.
- The report date, source classification, product family, and direct FDA record link.
- Optional family, report-date, classification, state, company, and alert filters.

### What data you get

| Field | What it means |
|---|---|
| recallNumber | FDA recall number, unique within its product family. |
| eventId | FDA event identifier, when supplied. |
| businessName | Corporate recalling firm named in the source. |
| productFamily | Food, drug, or device dataset. |
| classification | Source classification such as Class II, when available. |
| reportDate | Source report date. |
| initiationDate | Source recall initiation date. |
| reportedRecallStatus | Historical status as reported in that indexed row. It may be stale. |
| productType | Source product type, when available. |
| voluntaryMandated | Source voluntary or mandated code, when available. |
| state | Source two-letter state, when available. |
| country | Country name from the source, when available. |
| status | `ok` for a mapped source record. |
| sourceRecordId | Product family and recall number. |
| dedupeId | Stable identifier used to avoid repeat delivery. |
| source | Name of the FDA enforcement dataset. |
| sourceUrl | Direct FDA API lookup for this family and recall number. |
| retrievedAt | When the source page was fetched. |
| scrapedAt | When the result was mapped. |
| sourceUpdatedAt | FDA index date, not the record update date. |
| freshnessDays | Calendar days between retrieval and source index date. |

### Quick start

1. Choose one or more product families and a report-date window or company name.
2. Set maximum results and source requests for your budget.
3. Run the Actor and inspect the returned dataset and source links.

The September 29, 2026 cloud canary used the exact `families: ["food"]` filter and a report-date window from August 30 through September 29, 2026. It scanned the first 20 source rows and saved all 20. FDA metadata reported 95 matches for that selected query and an index date of September 23, 2026. The run stopped at the result cap, so this is a partial food-only sample; it does not cover the drug or device families or represent a complete current recall list. At the listed $0.003 event price, the 20 saved results correspond to $0.060 in result events.

### Who uses it

- Medtech supplier-quality researchers reviewing historical enforcement records across relevant product families.
- Contract manufacturers building company lists for a supplier portfolio.
- Market researchers checking a historical event's dates and basic source classification.

### Input

| Input | Use |
|---|---|
| dateFrom | Inclusive lower report-date limit in real `YYYY-MM-DD` format. |
| dateTo | Inclusive upper report-date limit in real `YYYY-MM-DD` format. |
| families | An array containing food, drug, device, or any combination. |
| classification | Exact source class: Class I, Class II, or Class III. |
| state | Exact two-letter source state code. |
| businessName | Bounded substring of a corporate recalling-firm name. |
| newSince | Optional alert date or `lastRun` for technical change monitoring; `off` disables alerts. |
| alertLookbackDays | Alert lookback window from 1 to 30 days. |
| maxItems | Maximum delivered rows, 1 to 1,000; default 20. |
| maxRequests | Maximum FDA pages, 1 to 20; default 5. |

#### Tips for good input

- Good: `2026-01-01` as `dateFrom`. Bad: `01/01/26`, which is ambiguous.
- Good: `["food", "device"]` for two families. Bad: `Devices`, which is not a supported family code.
- Good: `CA` as a state. Bad: `California`, because the source uses two-letter codes.
- Good: `Medical` in the company substring. Bad: a person's name or contact details.

<details><summary>Advanced options</summary>

The source request count and delivered-row count are separate limits. A page can contain records that are excluded because they are not confidently corporate, or because they do not match the selected filters. FDA index pages are capped by the source API. The Actor reports a partial scan when it reaches a configured cap and resumes a frozen pending window for alert runs. Use a narrow report-date range, one family, or a corporate-name phrase when you need a focused list. The Actor sends only fixed FDA search clauses built from validated inputs; it does not accept arbitrary endpoints, source keys, or raw query strings. The default window covers the most recent 30 days. You can set explicit dates for historical research.

</details>

### Sample output

![Example table of corporate enforcement research fields](https://raw.githubusercontent.com/ledgerstar/assets/main/fda-enforcement-research/table.png)

![Chart for FDA enforcement source research](https://raw.githubusercontent.com/ledgerstar/assets/main/fda-enforcement-research/chart.png)

The table and chart below use the actual cloud canary output. The table shows 8 of 20 saved food-family records; the chart counts FDA-reported classification labels across all 20. This exact food-only first-page sample says nothing about drug or device results. The classification and reported status are historical source values, not current safety guidance.

<details><summary>Full JSON example</summary>

```json
{
  "recallNumber": "H-1339-2026",
  "eventId": "99737",
  "businessName": "Everything Sprouts, LLC",
  "productFamily": "Food",
  "classification": "Class I",
  "reportDate": "2026-09-23",
  "initiationDate": "2026-08-22",
  "reportedRecallStatus": "Ongoing",
  "productType": "Food",
  "voluntaryMandated": "Voluntary: Firm initiated",
  "state": "MN",
  "country": "United States",
  "status": "ok",
  "sourceRecordId": "food:H-1339-2026",
  "dedupeId": "openfda:enforcement:food:H-1339-2026",
  "source": "openFDA Food Enforcement",
  "sourceUrl": "https://api.fda.gov/food/enforcement.json?search=recall_number%3A%22H-1339-2026%22&limit=1",
  "retrievedAt": "2026-09-29T21:33:51.112Z",
  "scrapedAt": "2026-09-29T21:33:51.112Z",
  "sourceUpdatedAt": "2026-09-23",
  "freshnessDays": 6
}
```

</details>

### Alert mode: only new records

Set `newSince` to a date or `lastRun` to filter delivery by report date for historical research. This technical feature is not a safety alert and does not track a recall lifecycle. Alert mode stores delivered version identifiers so scheduled runs can avoid charging the same record version again. The enforcement source datasets are updated weekly according to FDA documentation, but individual families or filtered runs may return no matching rows. The cursor keeps a pending bounded scan across migrations and alert runs. If FDA changes its index during a scan, the Actor stops rather than combining pages from different index versions. An interrupted process can still leave uncertainty at the boundary; this is not an exactly-once delivery guarantee. Omit `newSince` or set it to `off` for a repeatable snapshot without alert tracking.

### Pricing

Proposed price: **$0.003 per successfully delivered result.**

That equals **$3.00 per 1,000 results** when every result is delivered.

| Results | Cost |
|---:|---:|
| 100 | $0.30 |
| 1,000 | $3.00 |
| 10,000 | $30.00 |

These examples assume every requested record qualifies and is delivered. Empty searches, failed runs, and excluded rows are not successful result events. Platform configuration and charges should be checked on the Actor listing before use.

### Use it through the API

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("ledgerstar/fda-enforcement-research").call(run_input={"families": ["device"], "dateFrom": "2026-09-01", "dateTo": "2026-09-30", "maxItems": 20})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('ledgerstar/fda-enforcement-research').call({ families: ['device'], dateFrom: '2026-09-01', dateTo: '2026-09-30', maxItems: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Integrations

Send dataset rows to Google Sheets for review, schedule a run in Zapier or Make, or use Slack to notify a team when an alert-mode run delivers a new version. Apify API clients can start runs and retrieve datasets from your own systems. Keep your API token private and apply your organization's access controls to downstream copies.

### Data source and compliance

The sources are the U.S. FDA openFDA food, drug, and device enforcement endpoints. FDA explicitly says this data must not be used for public recall alerts or recall lifecycle tracking. Reported status is historical and may be stale. The product is for business research only. FDA's index may be incomplete or change. Verify important facts directly with FDA and the manufacturer. The Actor applies a conservative corporate-name filter and does not return people, contact information, street addresses, raw narratives, third-party documents, or licensed GMDN material. It is for business research, not clinical, purchasing, safety, or regulatory decisions. Check FDA terms and the source documentation for your intended use.

### FAQ

**Is it legal to use this data?**

The Actor uses FDA's public openFDA API. You are responsible for following the source terms, applicable law, and your own organization's policies.

**How often is the data updated?**

FDA describes the food, drug, and device enforcement indexes as weekly classified data. Source updates do not make the reported status current. Check `sourceUpdatedAt` on each run for the index date.

**How do I get only new records?**

Set `newSince` to an ISO date or `lastRun` and schedule runs. This is technical change monitoring, not a safety alert.

**Can this Actor issue public recall alerts?**

No. FDA explicitly prohibits using these datasets for public recall alerts or recall lifecycle tracking. Use official safety communications for those purposes.

**Does the Actor show all FDA enforcement history records?**

No. Runs are bounded by date filters, request limits, and result limits. Corporate-name filtering excludes uncertain entities.

**Why did my search return no rows?**

Your family, report dates, classification, state, or firm filters may not match a corporate record in the selected window.

**Can I search several product families at once?**

Yes. Choose any combination of food, drug, and device. Family-specific IDs remain distinct in the results.

**Are results updated when an old record changes?**

Changes to mapped business historical event fields create a new record version. Changes to fields outside the output contract are not versioned.

**Can I use this for clinical or safety decisions?**

No. FDA warns against public alert or lifecycle uses. This Actor is for historical supplier research only.

**What does `freshnessDays` measure?**

It is the number of calendar days between retrieval and the source index date, not the age or current state of an individual enforcement record.

**Why do rows omit contact and address fields?**

The output is limited to selected business and historical event fields and excludes personal and contact data.

**What happens when the source changes during a scan?**

The Actor stops the pending scan so it does not silently combine pages from different source-index versions.

### More from Ledgerstar

Related research Actors include FDA Drug Application Decisions, FDA 510(k) Device Clearances, and FDA PMA Supplement Decisions. Check each listing for its current availability and source scope.

### Support

Support: open an issue on this Actor's Issues tab in Apify Console.

# Changelog

This Actor's version history is a separate document: https://apify.com/ledgerstar/fda-enforcement-research/changelog.md

# Actor input Schema

## `families` (type: `array`):

FDA product families

## `dateFrom` (type: `string`):

Report date from

## `dateTo` (type: `string`):

Report date to

## `classification` (type: `string`):

FDA classification

## `state` (type: `string`):

Two-letter state code

## `businessName` (type: `string`):

Corporate recalling firm contains

## `newSince` (type: `string`):

Technical delivery mode only. This dataset is not for public safety alerts or lifecycle tracking. Use `off` or leave blank to disable alert state.

## `alertLookbackDays` (type: `integer`):

Alert lookback days

## `maxItems` (type: `integer`):

Maximum delivered results

## `maxRequests` (type: `integer`):

Maximum source requests

## Actor input object example

```json
{
  "families": [
    "food",
    "drug",
    "device"
  ],
  "alertLookbackDays": 7,
  "maxItems": 20,
  "maxRequests": 5
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("ledgerstar/fda-enforcement-research").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("ledgerstar/fda-enforcement-research").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call ledgerstar/fda-enforcement-research --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ledgerstar/fda-enforcement-research"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HOa70eAmGbBnHMk1H/builds/rrTLE1FOiiTO4QWiv/openapi.json
