# FDA Recalls & Enforcement Monitor: openFDA Reports (`cliqtomedia/fda-recalls-enforcement-monitor`) Actor

Track FDA food, drug and medical device recalls from the official openFDA enforcement reports. Filter by class, status, firm, product, reason and state; get all four dates and see which recalls are new or updated since your last run.

- **URL**: https://apify.com/cliqtomedia/fda-recalls-enforcement-monitor.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** Business, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.07 / 1,000 recall records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Recalls & Enforcement Monitor searches FDA recalls of food, drugs and medical devices in the official FDA Enforcement Reports, through the openFDA API. Filter by recall class, status, dates, firm, product, reason and firm state. You get one clean row per recalled product, with the four FDA dates kept apart, the recall number, the firm, the reason and a link to the record in openFDA.

It is made for food and pharma quality teams, compliance and supplier monitoring, retailers, journalists and researchers. Save a monitor key and the next run shows only new and updated recalls. No login and no API key are needed. The form example (20 Class I food recalls from the last 30 days) finishes in a few seconds and costs $0.004.

![FDA Recalls & Enforcement Monitor: category, class and date filters in, one row per recalled product out with four separate FDA dates, plus new and updated recalls since the last run](https://api.apify.com/v2/key-value-stores/9q2gWja9ajC4fbUl9/records/README-BANNER-20261012B.png)

### Contents

- [What it does](#what-it-does)
- [Quick start](#quick-start)
- [Use cases](#use-cases)
- [Input](#input)
- [Output](#output)
- [Pricing](#pricing)
- [Monitoring on a schedule](#monitoring-on-a-schedule)
- [API and integrations](#api-and-integrations)
- [Limits](#limits)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Data source and licence](#data-source-and-licence)
- [Related Actors](#related-actors)
- [Support](#support)

### What it does

The Actor reads the public [openFDA enforcement endpoints](https://open.fda.gov/apis/food/enforcement/) live: `food` (also cosmetics and dietary supplements), `drug` and `device`. These are the records of the FDA weekly **Enforcement Report**: every recall that FDA has classified or is about to classify.

- **One request per category.** Each category you pick is one search, newest records first. `maxResults` applies to each category.
- **Four dates, never mixed.** `recallInitiationDate` (the firm started the recall), `centerClassificationDate` (FDA set the class), `reportDate` (FDA published it in the Enforcement Report) and `terminationDate` (FDA closed it). You choose which date your range uses.
- **Not yet classified recalls.** The newest recalls appear before FDA gives them a class and a recall number. You can include or skip them. They get a stable `recallKey` anyway.
- **Monitoring.** With a `monitorKey`, the Actor saves the recalls it saw in your account. The next run marks each recall `new`, `updated` (for example the status changed to `Terminated`) or `unchanged`, and by default writes only new and updated ones.

This is FDA data as published. It is **not medical advice**. Do not use it to decide whether to use, take or stop a product. Follow the instructions of FDA, the firm and your doctor or pharmacist.

#### Good fit

- Get a weekly list of new Class I food recalls for your quality or safety team.
- Check if a supplier, brand or competitor had FDA recalls, by firm name.
- Find recalls by reason: `Listeria`, `undeclared peanut`, `sterility`, `mislabeling`.
- Watch medical device or drug recalls of one firm state, such as `CA` or `NJ`.
- Feed FDA recall rows into a spreadsheet, a dashboard or an AI agent.

#### Not a fit

- Official consumer alerts or a guarantee that you see every recall in time. FDA publishes Enforcement Reports weekly, and a recall can appear later than the firm's press release.
- Full recall lifecycle tracking. The Actor sees only what the Enforcement Report says on the day of the run.
- Cosmetics or tobacco as separate categories, animal food recall press releases, and device recall details from the separate device recall database.
- A full copy of all FDA recalls since 2004. Use the [openFDA downloads](https://open.fda.gov/data/downloads/) for that.

### Quick start

1. Open the **Input** tab. The form already has an example: food, Class I, last 30 days, 20 recalls.
2. Click **Start**.
3. Open the **Recalls** view in the Output tab. Check `recallNumber`, `recallingFirm`, `productDescription`, `reasonForRecall` and `reportDate`.
4. Change the categories, classes or filters to your own. To get only changes next time, add a `monitorKey` such as `food-class-1`.

Expected result: up to 20 recall rows in a few seconds, newest first.

### Use cases

| Buyer job | Input | Output | Key fields |
| --- | --- | --- | --- |
| Weekly food safety watch | `categories: ["food"]`, `classifications: ["I"]`, `monitorKey`, on a schedule | only new and updated Class I recalls | `changeType`, `reasonForRecall`, `distributionPattern` |
| Supplier check | `firmNames`, all categories, a 90-day range | that firm's recalls | `recallingFirm`, `productDescription`, `status` |
| Allergen or pathogen research | `reasonQuery: "Listeria"` or `"undeclared peanut"` | matching recalls | `reasonForRecall`, `codeInfo`, `productQuantity` |
| Medical device recall search | `categories: ["device"]`, `productQuery`, `firmStates` | device recall rows | `recallNumber`, `classification`, `centerClassificationDate` |
| Drug recall list with NDCs | `categories: ["drug"]` | drug rows | `drugBrandNames`, `drugGenericNames`, `drugProductNdcs` |
| Closed recalls | `dateField: "termination_date"` | recalls FDA terminated in the range | `terminationDate`, `status` |

### Input

All filters are optional and combine with AND. Values inside one list combine with OR.

| Field | Type | Default | Allowed values | What it does |
| --- | --- | --- | --- | --- |
| `categories` | array | `["food"]` | `food`, `drug`, `device` | Which openFDA endpoints to search. `food` also has cosmetics and dietary supplements. |
| `classifications` | array | all | `I`, `II`, `III`, `unclassified` | FDA recall class. Class I is the most serious. `unclassified` = not yet classified. Empty = all. |
| `statuses` | array | all | `Ongoing`, `Completed`, `Terminated` | Recall status. Empty = all. |
| `lookbackDays` | integer | 30 | 1–90 | Days back from `dateTo`. Ignored when `dateFrom` is set. |
| `dateField` | string | `report_date` | `report_date`, `recall_initiation_date`, `center_classification_date`, `termination_date` | Which FDA date the range uses. |
| `dateFrom`, `dateTo` | date | `dateTo` = today (UTC) | `YYYY-MM-DD`, from 2004 | Exact range, at most 90 days. Split longer periods into several runs. |
| `firmNames` | array of strings | none | up to 10; 2–120 characters | Phrase in the recalling firm name. `Whole Foods` matches `Whole Foods Market Group Inc.` |
| `productQuery` | string | none | 2–120 characters | Phrase in the product description, like `ice cream` or `insulin pump`. |
| `reasonQuery` | string | none | 2–120 characters | Phrase in the reason for recall, like `Listeria` or `undeclared milk`. |
| `firmStates` | array of strings | none | up to 20 two-letter codes | State of the recalling firm, like `CA`. It is **not** where the product was sold; see `distributionPattern`. |
| `maxResults` | integer | 100 | 1–1000 | Maximum recalls **per category**, newest first. |
| `monitorKey` | string | none | 1–40 letters, digits or dashes | Saves this run's recalls and compares the next run with them. One key per saved search. |
| `previousDatasetId` | string | none | dataset ID | Compares with the dataset of an earlier run of this Actor. Use this or `monitorKey`, not both. |
| `onlyChanges` | boolean | `true` | | With a comparison, skip unchanged recalls. You do not pay for skipped recalls. |
| `openFdaApiKey` | string (secret) | none | your free openFDA key | Optional. Gives you your own openFDA quota. Never written to output or logs. |

Text filters search FDA's English text. Letters with accents are changed to plain Latin letters, and symbols such as `;`, `#` or `|` are removed, because openFDA rejects them. A filter with no Latin letters or digits stops the run with `INVALID_INPUT`.

#### Input examples

Drug and device recalls of one firm, last 90 days:

```json
{
  "categories": ["drug", "device"],
  "firmNames": ["Baxter"],
  "lookbackDays": 90,
  "maxResults": 200
}
```

Weekly watch of Listeria recalls in food, only changes:

```json
{
  "categories": ["food"],
  "reasonQuery": "Listeria",
  "lookbackDays": 30,
  "maxResults": 300,
  "monitorKey": "food-listeria"
}
```

### Output

Each Dataset row is **one recalled product** (one FDA recall number). One recall event (`eventId`) can have several products. Use the **Recalls** view for the main fields and the **Changes** view for monitoring. The key-value store has a `RUN_SUMMARY` record with the run status and counts.

#### Output example

A real row from the form example (trimmed):

```json
{
  "recallKey": "food:H-1395-2026",
  "recallNumber": "H-1395-2026",
  "eventId": "99874",
  "category": "food",
  "classification": "Class I",
  "recallClass": "I",
  "status": "Ongoing",
  "recallingFirm": "WFM Purchasing, LP",
  "productDescription": "Fromagerie Coop de Mean Cabricharme and Belgium Cabricharme ...",
  "productQuantity": "21 Wheels",
  "reasonForRecall": "Undeclared Egg Allergen",
  "distributionPattern": "CA, AZ, NJ, MA, RI, CT, NY",
  "recallInitiationDate": "2026-09-08",
  "centerClassificationDate": "2026-09-22",
  "reportDate": "2026-09-30",
  "terminationDate": null,
  "city": "Austin",
  "state": "TX",
  "changeType": null,
  "sourceUrl": "https://api.fda.gov/food/enforcement.json?search=recall_number%3A%22H-1395-2026%22",
  "provider": "openFDA (U.S. Food and Drug Administration)",
  "sourceUpdatedAt": "2026-09-30",
  "fetchedAt": "2026-10-12T10:54:50.382Z"
}
```

#### Fields

| Field | Meaning | Example |
| --- | --- | --- |
| `recallKey` | Stable key: `category:recallNumber`. For not yet classified recalls: `category:unclassified:eventId:hash`. Use it to join and compare. | `"food:H-1395-2026"` |
| `recallNumber` | FDA recall number. `null` while FDA has not classified the recall. | `"D-0860-2026"` |
| `eventId` | FDA recall event. One event can cover several products. | `"99874"` |
| `category`, `productType` | Searched category, and the product type as FDA writes it | `"food"`, `"Food"` |
| `classification`, `recallClass` | FDA class text and short form (`I`, `II`, `III`, or `null` if not classified yet) | `"Class I"`, `"I"` |
| `status` | `Ongoing`, `Completed` or `Terminated` | `"Ongoing"` |
| `recallingFirm` and `address1`, `address2`, `city`, `state`, `postalCode`, `country` | Firm that recalls the product, and its address | `"WFM Purchasing, LP"` |
| `productDescription`, `productQuantity` | What is recalled and how much | `"21 Wheels"` |
| `codeInfo`, `moreCodeInfo` | Lot numbers, dates, UPCs, as the firm gave them | `"Lot 12345"` |
| `reasonForRecall` | Why FDA lists the recall | `"Undeclared Egg Allergen"` |
| `distributionPattern` | Where the product was distributed, free text | `"Nationwide"` |
| `voluntaryMandated`, `initialFirmNotification` | Who started the recall and how the firm told customers | `"Voluntary: Firm initiated"` |
| `recallInitiationDate`, `centerClassificationDate`, `reportDate`, `terminationDate` | The four FDA dates, `YYYY-MM-DD`, no time zone shift | `"2026-09-30"` |
| `drugBrandNames`, `drugGenericNames`, `drugProductNdcs` | Drug rows only, from openFDA's drug data. `null` for food and devices. | `drugGenericNames: ["SODIUM CHLORIDE"]` |
| `changeType` | `initial` (first monitor run), `new`, `updated`, `unchanged`, or `null` without a comparison | `"updated"` |
| `changedFields`, `previousValues` | For `updated`: which fields changed and their old values | `["status", "terminationDate"]` |
| `sourceUrl` | This record in the openFDA API | `"https://api.fda.gov/..."` |
| `provider`, `sourceUpdatedAt`, `fetchedAt` | Data provider, openFDA's last update date, and our read time | `"2026-09-30"` |

`null` means FDA has no value. It never means zero, and an empty list is never shown as a value.

A recall is `updated` when one of these fields changes: `status`, `classification`, the four dates, `recallingFirm`, `productDescription`, `productQuantity`, `codeInfo`, `reasonForRecall`, `distributionPattern`, `voluntaryMandated`.

#### Run summary

`RUN_SUMMARY.status` is one of:

| Status | Meaning | Run result |
| --- | --- | --- |
| `COMPLETE` | Rows were written. `truncated: true` means openFDA has more recalls than `maxResults`. | succeeded |
| `NO_RESULTS` | openFDA answered, and no recall matches your filters. This is not an error. | succeeded |
| `NO_CHANGES` | Comparison run: no new or updated recalls. | succeeded |
| `PARTIAL` | Some categories failed or time ran out. The rows you got are correct. | succeeded |
| `CAPPED` | Your maximum cost per run was reached. | succeeded |
| `ERROR` | openFDA was not available, refused the request (rate limit) or changed its format. This is not an empty result. | failed |
| `INVALID_INPUT` | The input is wrong, or `previousDatasetId` was not found. `message` explains why. | failed |

`RUN_SUMMARY` also has `counts` (fetched, written, charged, initial, new, updated, unchanged), one `categories` entry per category with its own status and `matchedAtSource`, the filters used, the comparison baseline, `warnings`, and the data source with licence and attribution.

### Pricing

Pay per event. Platform usage is included.

| Event | Price | When |
| --- | ---: | --- |
| Actor start | $0.002 | Once per run (per GB of memory; the default 256 MB counts once) |
| Recall record | $0.0001 | Each recall row written to the Dataset (a bit less on higher Apify plans) |

Unchanged recalls hidden by `onlyChanges` are free. A run with no results, no changes, an input error or an openFDA error costs only the start.

| Run | Example cost |
| --- | ---: |
| 10 recalls | $0.003 |
| 20 recalls (form example) | $0.004 |
| 100 recalls | $0.012 |
| 1,000 recalls | $0.102 |
| up to 3,000 recalls (3 categories × 1,000) | up to $0.302 |
| Weekly monitor run with 5 changes | $0.0025 |
| No results or no changes | $0.002 |

Set a maximum cost per run in the run options to cap your spend. The Actor stops before a row that does not fit and reports `CAPPED`.

### Monitoring on a schedule

1. Save your input as a **task** and add a `monitorKey`, for example `food-class-1`.
2. Add an Apify **schedule** to the task, for example every Monday (FDA publishes the Enforcement Report weekly, usually on Wednesday).
3. The first run marks all rows `initial`. Each later run writes only `new` and `updated` recalls.
4. Send the rows to email, Slack, Google Sheets or a webhook with Apify integrations.

The range moves with the run date. A recall that later changes but is now outside your range is not seen. To catch recalls that FDA closed, run a second task with `dateField: "termination_date"`. This is a convenience tool, not an official FDA alert service, and it does not promise that you get every recall or get it in time.

### API and integrations

Start a run with the same JSON input through the Apify API (`POST /v2/acts/cliqtomedia~fda-recalls-enforcement-monitor/runs`), then read the Dataset. Export to CSV, Excel or JSON, or send rows to Google Sheets, Slack or a webhook with Apify integrations. Join rows on `recallKey`.

#### Use with AI agents (MCP)

AI agents can call this Actor through the Apify MCP server: add `https://mcp.apify.com?tools=cliqtomedia/fda-recalls-enforcement-monitor` to your MCP client (Claude, Cursor, VS Code and others). The MCP server needs your Apify account (OAuth sign-in or an Apify API token); openFDA itself needs no key. The agent builds the input from the input schema. The smallest useful input:

```json
{ "categories": ["drug"], "classifications": ["I"], "maxResults": 10 }
```

Key output fields for an agent: `recallNumber`, `classification`, `status`, `recallingFirm`, `productDescription`, `reasonForRecall`, `reportDate`, `sourceUrl`, and `RUN_SUMMARY.status`. A call with 10–1,000 recalls usually finishes in under 10 seconds and costs $0.003–$0.102.

### Limits

- Up to 1,000 recalls per category and 3 categories, so up to 3,000 rows per run. In our test, 2,541 rows took about 4 seconds.
- The date range is at most 90 days. Enforcement Reports start in 2004.
- Without a key, openFDA limits requests per IP address per day, and the IP can be shared with other users. Each category is one request. If openFDA refuses with a rate limit, the run stops with `ERROR` and a hint. Add your free `openFdaApiKey` to get your own quota.
- If openFDA does not answer (up to 30 seconds per try, at most 3 tries and 2 timeouts), the run stops early and does not ask for the other categories. You get the rows found so far. The internal time budget is 240 seconds.
- Monitor snapshots keep up to 20,000 recalls per `monitorKey`. `previousDatasetId` reads up to 20,000 rows.
- Not yet classified recalls have no recall number. When FDA classifies them, they come back with a recall number as a `new` row with a new `recallKey`.
- `firmStates` is the firm's address, not where the product was sold.
- openFDA updates the enforcement data about once a week. `sourceUpdatedAt` shows the last update.

### Troubleshooting

| Symptom | Check | Action |
| --- | --- | --- |
| `NO_RESULTS` | `RUN_SUMMARY.filters` | Widen the dates, remove a class or a filter, or try another `dateField`. |
| `ERROR` with a rate limit message | `RUN_SUMMARY.message` | Add your free `openFdaApiKey`, or run again later. |
| `ERROR`, openFDA unavailable | `RUN_SUMMARY.message` | Run again later. A failed run does not remove recalls from your monitor snapshot; it only adds the rows it reported. |
| `INVALID_INPUT` | `RUN_SUMMARY.message` | Fix the field named in the message. The range is at most 90 days. |
| `truncated: true` | `categories[].matchedAtSource` | Raise `maxResults` (up to 1,000) or narrow the filters or dates. |
| A recent recall is missing | `sourceUpdatedAt`, `reportDate` | FDA adds recalls to the weekly report after classification. Try `dateField: "recall_initiation_date"` and include `unclassified`. |
| Warning about different filters | `RUN_SUMMARY.warnings` | You changed filters but kept the same `monitorKey`. Use one key per saved search. |

### FAQ

#### Is this medical advice?

No. It is FDA data as published. For decisions about a product you use, follow FDA, the firm, and your doctor or pharmacist.

#### Where does the data come from?

From openFDA, the official open data API of the U.S. Food and Drug Administration. The records are the FDA Enforcement Reports.

#### Do I need an API key?

No. A free openFDA key is optional and only gives you your own request quota.

#### What are Class I, II and III?

Class I: a reasonable chance of serious health problems or death. Class II: temporary or reversible health problems. Class III: unlikely to cause health problems. "Not yet classified" means FDA has not set the class yet.

#### How fresh is the data?

Each run reads openFDA live. openFDA updates the enforcement data about once a week, after FDA publishes the Enforcement Report. Firm press releases can come earlier.

#### Does monitoring cost more?

No. Unchanged recalls are not written and not charged when `onlyChanges` is on.

#### Why are there no device codes like GMDN?

GMDN terms have their own licence, so the Actor does not output openFDA device classification data. If a firm wrote a code into its own `codeInfo` text, it stays as FDA published it.

### Data source and licence

Data provided by the U.S. FDA ([open.fda.gov](https://open.fda.gov/)). openFDA data is in the public domain under [CC0 1.0](https://open.fda.gov/license/); GMDN device terms are excluded and never output. This Actor is independent and not affiliated with or endorsed by the U.S. Food and Drug Administration. Do not rely on it for medical decisions.

### Related Actors

- [VIN Decoder & Vehicle Recalls](https://apify.com/cliqtomedia/vin-decoder-vehicle-recalls) — NHTSA vehicle recalls by VIN.
- [USAspending Federal Awards & Recipient Monitor](https://apify.com/cliqtomedia/usaspending-federal-awards-monitor) — federal contracts and grants, with change monitoring.

### Support

Use the **Issues** tab of this Actor. Add the run ID, your input (without private data or your openFDA key) and `RUN_SUMMARY.status` and `message`. Do not send API tokens.

# Changelog

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

# Actor input Schema

## `categories` (type: `array`):

Which openFDA enforcement reports to search: food (also cosmetics and dietary supplements), drug, device. Each category is one request. Default: food.

## `classifications` (type: `array`):

FDA recall class. Class I: reasonable probability of serious health consequences or death. Class II: temporary or medically reversible consequences. Class III: unlikely to cause adverse health consequences. Not yet classified: newest recalls FDA has listed before assigning a class and a recall number. Empty = all.

## `statuses` (type: `array`):

Ongoing, Completed or Terminated. Empty = all statuses.

## `lookbackDays` (type: `integer`):

Date range ending today (or dateTo), 1–90 days. Ignored when dateFrom is set. Default 30.

## `dateField` (type: `string`):

report_date: when FDA published the recall in its weekly Enforcement Report (default, best for monitoring). recall_initiation_date: when the firm started the recall. center_classification_date: when FDA classified it. termination_date: when FDA terminated it (use to catch closed recalls).

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

Optional start date (YYYY-MM-DD). The whole range may span at most 90 days; split longer periods into several runs.

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

Optional end date (YYYY-MM-DD). Default: today (UTC).

## `firmNames` (type: `array`):

Up to 10 firm names, matched as a phrase in the recalling firm name, e.g. Whole Foods matches Whole Foods Market Group Inc.

## `productQuery` (type: `string`):

Optional phrase searched in the product description, e.g. ice cream or insulin pump. 2–120 characters.

## `reasonQuery` (type: `string`):

Optional phrase searched in the reason for recall, e.g. Listeria, undeclared peanut, sterility. 2–120 characters.

## `firmStates` (type: `array`):

Up to 20 two-letter US state codes of the recalling firm, e.g. CA, TX. This is where the firm is, not where the product was distributed.

## `maxResults` (type: `integer`):

Newest first, 1–1000 per category. Each recall row is one charged result. Default 100.

## `monitorKey` (type: `string`):

Optional name, 1–40 letters, digits or dashes, e.g. food-class-1. The Actor stores the recalls it saw under this key in your account, and the next run with the same key marks each recall new, updated (for example a status change) or unchanged. The first run marks rows initial. Use one key per saved search.

## `previousDatasetId` (type: `string`):

Alternative to monitorKey: ID of an earlier run's default Dataset from this Actor. Rows are compared with it.

## `onlyChanges` (type: `boolean`):

With a monitorKey or previousDatasetId, skip unchanged recalls (they are not written and not charged). Default true.

## `openFdaApiKey` (type: `string`):

Optional free key from open.fda.gov/apis/authentication. Without it openFDA allows a limited number of requests per IP address per day, shared with other users of the same IP. The key is never written to the output or logs.

## Actor input object example

```json
{
  "categories": [
    "food"
  ],
  "classifications": [
    "I"
  ],
  "statuses": [
    "Ongoing",
    "Completed",
    "Terminated"
  ],
  "lookbackDays": 30,
  "dateField": "report_date",
  "maxResults": 20,
  "onlyChanges": true
}
```

# Actor output Schema

## `recalls` (type: `string`):

One row per recall: firm, product, reason, class, status, distribution, four dates, location and openFDA link.

## `changes` (type: `string`):

Change monitoring view: change type, changed fields and previous values.

## `runSummary` (type: `string`):

Status, counts, matches at source per category, filters used, baseline and source attribution.

# 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 = {
    "categories": [
        "food"
    ],
    "classifications": [
        "I"
    ],
    "lookbackDays": 30,
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/fda-recalls-enforcement-monitor").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 = {
    "categories": ["food"],
    "classifications": ["I"],
    "lookbackDays": 30,
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/fda-recalls-enforcement-monitor").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 '{
  "categories": [
    "food"
  ],
  "classifications": [
    "I"
  ],
  "lookbackDays": 30,
  "maxResults": 20
}' |
apify call cliqtomedia/fda-recalls-enforcement-monitor --silent --output-dataset

```

## MCP server setup

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

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/qCQeEYdUeein7PqQG/builds/5vVEl1wtlj9uDjH4N/openapi.json
