# openFDA API: FDA Recalls, Drug Labels & Device Reports (`yadroo/openfda-records`) Actor

Query the official openFDA API in one actor: drug, device and food recall enforcement reports, SPL drug labels by generic or brand name, and device adverse-event (MAUDE) reports with detail links that open. Filter by keyword, recall class, status, state, event type and date. No API key.

- **URL**: https://apify.com/yadroo/openfda-records.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** Developer tools, Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 fda record returneds

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

## openFDA API: FDA Recalls, Drug Labels & Device Reports

Pull four kinds of FDA record straight from the official openFDA API (`api.fda.gov`) as flat, ready-to-use rows: recall
enforcement reports for drugs, medical devices and food; structured product labels (SPL) for any brand or generic drug
name; medical device adverse event reports from MAUDE; and the export status of every openFDA dataset. Every row carries
the same handful of shared columns (`recordId`, `title`, `organization`, `category`, `date`, `url`), every date is UTC
ISO-8601, and every report links back to the exact openFDA record it came from. No API key, no proxy, no browser.

The data is US public-domain FDA data. It is not medical advice: a recall or an adverse event record is a *report*, not
proof that a product caused harm, and the datasets can be incomplete or several weeks behind.

### Use cases

- **Pharmacovigilance and pharmacy compliance**: a standing list of Class I drug recalls of the last 12 months, with the
  reason, the recalling firm and the distribution pattern, to check against your own stock lists.
- **Food safety and retail QA**: every food recall whose stated reason mentions an undeclared allergen or ingredient, so
  a grocery or private-label buyer can react the same week the recall is published.
- **Hospital biomedical engineering and device distributors**: the running list of device recall enforcement reports,
  filtered to a device family or a manufacturer, to match against installed equipment.
- **Clinical and pharmacy app developers**: the newest SPL label per generic name (set id, version, NDC codes, route,
  labeler, application number), which answers "which label do I show for this drug" without parsing SPL XML.
- **Device safety, quality and product-liability research**: MAUDE reports for one device type or product code, with
  device and patient problem codes and a detail link that actually opens the report on the FDA site.
- **Data engineering**: `mode: "datasets"` answers "how fresh is FDA data right now" — export date and record count for
  each of the 30 openFDA datasets — before a pipeline run trusts them.
- **Monitoring**: `sinceDays` plus `onlyNew` turns any of the above into a scheduled watchlist that emits only records
  it has not delivered before.

### Input

Nothing is required. The defaults run a drug-recall search; `query` is the only field with a prefilled example.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `mode` | string | `recalls` | `recalls`, `drugLabels`, `deviceEvents`, `datasets` — see [Modes](#modes) |
| `productArea` | string | `drug` | `drug`, `device`, `food`. Which enforcement dataset `recalls` reads; ignored by other modes |
| `query` | string | *(prefill `insulin`)* | Search words. Several words are searched as a phrase. Empty = everything matching the filters |
| `searchField` | string | `auto` | Which field `query` is matched in — see [Search fields](#search-fields) |
| `classifications` | string\[] | all | `Class I`, `Class II`, `Class III`. `recalls` only — see [Recall classes](#recall-classes) |
| `recallStatuses` | string\[] | all | `Ongoing`, `Completed`, `Terminated`, `Pending`. `recalls` only |
| `eventTypes` | string\[] | all | `Death`, `Injury`, `Malfunction`, `Other`, `No answer provided`. `deviceEvents` only |
| `productCode` | string | — | Three-character FDA device product code, e.g. `QFG`. `deviceEvents` only — see [Device product codes](#device-product-codes) |
| `state` | string | — | Two-letter US state of the recalling firm, e.g. `NJ`. `recalls` only |
| `country` | string | — | Country of the recalling firm as FDA spells it, e.g. `United States`. `recalls` only |
| `sinceDays` | integer | — | 1–3650. Keep only records whose main date falls in the last N days (UTC). Wins over `fromDate`/`toDate` |
| `fromDate` | string | — | Earliest date, `YYYY-MM-DD`, inclusive |
| `toDate` | string | — | Latest date, `YYYY-MM-DD`, inclusive |
| `onlyNew` | boolean | `false` | Emit only records this input has not delivered in an earlier run |
| `sortOrder` | string | `newest` | `newest` or `oldest`, by the mode's main date |
| `maxItems` | integer | `25` | 1–5000 rows |
| `includeText` | boolean | `false` | Add SPL section text (`drugLabels`) or the report narrative (`deviceEvents`) |
| `labelSections` | string\[] | purpose, indications and usage, warnings | Which SPL sections `includeText` adds — see [Label sections](#label-sections) |
| `fields` | string\[] | all | Keep only these output fields, in this order |
| `customSearch` | string | — | A raw openFDA expression ANDed to everything above — see [Raw search expressions](#raw-search-expressions) |

Choice fields accept only the listed values (Apify rejects anything else before the run starts). Free-text fields are
normalised — `query` is trimmed, `state` and `productCode` are upper-cased — and an impossible combination (e.g.
`productCode` with `mode: "recalls"`) fails the run with a clear message instead of quietly returning something wider.

### Reference

#### Modes

| `mode` | openFDA endpoint | What one row is | Filters that apply |
|---|---|---|---|
| `recalls` | `/{drug\|device\|food}/enforcement.json` | One recall enforcement report | `query`, `searchField`, `classifications`, `recallStatuses`, `state`, `country`, dates |
| `drugLabels` | `/drug/label.json` | One SPL label version | `query`, `searchField`, dates (`effective_time`), `includeText`, `labelSections` |
| `deviceEvents` | `/device/event.json` | One MAUDE adverse event report | `query`, `searchField`, `eventTypes`, `productCode`, dates, `includeText` |
| `datasets` | `/download.json` | One openFDA dataset (30 of them) | none — the date and search filters are ignored and reported as such |

The main date differs per mode: `report_date` for recalls, `effective_time` for labels, `date_received` for device
reports. `sinceDays`, `fromDate`, `toDate` and `sortOrder` all work on that field.

#### Recall classes

| Value | What FDA means by it |
|---|---|
| `Class I` | Reasonable probability that the product causes serious harm or death |
| `Class II` | May cause temporary or medically reversible harm; serious harm unlikely |
| `Class III` | Unlikely to cause harm, but the product violates FDA regulations |

Recall statuses are `Ongoing` (the firm is still recalling), `Completed`, `Terminated` (FDA closed the recall) and
`Pending` (not yet classified).

#### Search fields

`searchField` picks the field `query` is matched in. A field an endpoint does not have falls back to `auto`, with a
warning in the log — the search is never silently widened.

| `searchField` | `recalls` | `drugLabels` | `deviceEvents` |
|---|---|---|---|
| `auto` | every field of the record | every field | every field |
| `product` | `product_description` | package label text | `device.generic_name` |
| `reason` | `reason_for_recall` | → `auto` | → `auto` |
| `firm` | `recalling_firm` | → `auto` | `manufacturer_name` |
| `brandName` | `openfda.brand_name` | `openfda.brand_name` | `device.brand_name` |
| `genericName` | `openfda.generic_name` | `openfda.generic_name` | `device.generic_name` |
| `manufacturer` | `openfda.manufacturer_name` | `openfda.manufacturer_name` | `device.manufacturer_d_name` |
| `productCode` | not possible (see below) | → `auto` | `device.device_report_product_code` |
| `identifier` | `recall_number` | `set_id`, SPL id or NDC | MAUDE report number or report key |

`identifier` looks up one exact record. When the id does not exist, the run writes a single row with `found: false`
instead of returning nothing.

Device recall records carry **no** product code — measured on 2026-09-19, 0 of 39,949 device enforcement records have
one and there is no field to fall back to. `productCode` (or `searchField: "productCode"`) combined with
`mode: "recalls"` therefore fails with a message instead of returning an unfiltered list. Search device recalls by
product description or recalling firm instead.

#### Device product codes

A product code is FDA's three-letter key for a device type. Examples verified in the device classification data:

| Code | Device type | Class |
|---|---|---|
| `QFG` | Alternate controller enabled insulin infusion pump | 2 |
| `QJY` | Infusion pump, drug specific, pharmacy-filled | 2 |
| `DTE` | Pulse generator, pacemaker, external | 2 |
| `DXY` | Implantable pacemaker pulse generator | 3 |
| `PQF` | Sensor, glucose, invasive, non-adjunctive | 3 |
| `DQO` | Catheter, intravascular, diagnostic | 2 |
| `QOS` | Continuous ventilator | — |
| `JDG` | Prosthesis, hip, femoral component, cemented, metal | 2 |

To find the code for any other device, search FDA's classification list by name in a browser:
`https://api.fda.gov/device/classification.json?search=device_name:"insulin pump"&limit=10`. Each device event row also
carries the code that FDA filed it under, so one broad `genericName` run tells you which code to narrow to.

#### Label sections

`includeText` adds a `sections` object to drug label rows. `labelSections` picks which ones: `purpose`,
`indicationsAndUsage`, `dosageAndAdministration`, `warnings`, `adverseReactions`, `contraindications`,
`activeIngredient`, `inactiveIngredient`, `description`, `howSupplied`. Sections a particular label does not have are
left out. These fields can be tens of kilobytes each, which is why they are off by default.

#### Raw search expressions

`customSearch` is ANDed to everything the input already built, for people who know the openFDA field names. Useful
starting points:

- drug labels: `openfda.pharm_class_epc:"Nonsteroidal Anti-inflammatory Drug [EPC]"`, `openfda.route:"ORAL"`,
  `openfda.is_original_packager:true`
- enforcement: `voluntary_mandated:"Voluntary: Firm initiated"`, `distribution_pattern:"Nationwide"`
- device events: `patient.patient_problems:"Death"`, `device.device_class:3`, `source_type:"Consumer"`

Multi-word values must be quoted. An expression openFDA cannot parse fails the run with the API's own message, naming
`customSearch` as the culprit.

### Examples

**Class I drug recalls of the last 12 months** — pharmacovigilance and pharmacy compliance.

```json
{ "mode": "recalls", "productArea": "drug", "classifications": ["Class I"], "sinceDays": 365, "sortOrder": "newest", "maxItems": 20 }
```

**Food recalls for undeclared allergens** — food safety and retail QA.

```json
{ "mode": "recalls", "productArea": "food", "query": "undeclared", "searchField": "reason", "sinceDays": 180, "maxItems": 20 }
```

**Device recalls of the last 6 months from one firm** — hospital biomedical engineering.

```json
{ "mode": "recalls", "productArea": "device", "query": "Medtronic", "searchField": "firm", "sinceDays": 180, "maxItems": 25 }
```

**Newest drug labels for a generic name** — clinical and pharmacy apps.

```json
{ "mode": "drugLabels", "query": "ibuprofen", "searchField": "genericName", "sortOrder": "newest", "maxItems": 15 }
```

**Adverse event reports for one device family** — device safety and liability research.

```json
{ "mode": "deviceEvents", "query": "infusion pump", "searchField": "genericName", "sinceDays": 180, "maxItems": 20 }
```

**Device reports with a death outcome, as a daily watchlist** — safety monitoring.

```json
{ "mode": "deviceEvents", "eventTypes": ["Death"], "sinceDays": 180, "onlyNew": true, "maxItems": 15 }
```

**How fresh is each FDA dataset** — data engineering.

```json
{ "mode": "datasets", "maxItems": 40 }
```

### Output

One real row from a cloud run with the default input (`mode: "recalls"`, `productArea: "drug"`, `query: "insulin"`),
with the long `codeInfo` trimmed:

```json
{
  "mode": "recalls",
  "recordId": "D-0806-2026",
  "title": "MYXREDLIN, Insulin Human in 0.9% Sodium Chloride Injection, 100 units/100 mL (1 unit/mL), Rx only, Baxter Healthcare Corporation, Deerfield, IL 60015 USA, NDC 0338-0126-12.",
  "organization": "Baxter Healthcare Corporation",
  "category": "Class II",
  "date": "2026-09-09",
  "status": "Ongoing",
  "found": true,
  "recallNumber": "D-0806-2026",
  "eventId": "99500",
  "productArea": "drug",
  "classification": "Class II",
  "recallStatus": "Ongoing",
  "productType": "Drugs",
  "productDescription": "MYXREDLIN, Insulin Human in 0.9% Sodium Chloride Injection, 100 units/100 mL (1 unit/mL), Rx only, Baxter Healthcare Corporation, Deerfield, IL 60015 USA, NDC 0338-0126-12.",
  "reasonForRecall": "CGMP Deviations",
  "productQuantity": null,
  "codeInfo": "Lot # NC188630, NC188708, NC188791, NC188845, NC188876, NC188968, Exp Date: 12/31/2027; Lot # NC193719, NC193849, …",
  "moreCodeInfo": null,
  "distributionPattern": "US Nationwide; Puerto Rico; and Chile.",
  "recallingFirm": "Baxter Healthcare Corporation",
  "firmAddress": "1 Baxter Pkwy",
  "firmCity": "Deerfield",
  "firmState": "IL",
  "firmPostalCode": "60015-4625",
  "firmCountry": "United States",
  "voluntaryMandated": "Voluntary: Firm initiated",
  "initialFirmNotification": "Letter",
  "recallInitiationDate": "2026-08-06",
  "centerClassificationDate": "2026-08-28",
  "reportDate": "2026-09-09",
  "brandNames": [
    "MYXREDLIN"
  ],
  "genericNames": [
    "INSULIN HUMAN"
  ],
  "manufacturerNames": [
    "Baxter Healthcare Corporation"
  ],
  "productNdcs": [
    "0338-0126"
  ],
  "url": "https://api.fda.gov/drug/enforcement.json?search=recall_number%3A%22D-0806-2026%22&limit=1",
  "detailUrl": null,
  "fetchedAt": "2026-09-19T20:14:59.688Z"
}
```

Shared fields, present in every mode:

| Field | Type | Meaning |
|---|---|---|
| `mode` | string | Which job produced the row |
| `recordId` | string | Recall number, SPL set id, MAUDE report number or dataset key |
| `title` | string | Product description, brand (generic) name, device brand or dataset name |
| `organization` | string | Recalling firm, labeler or device manufacturer |
| `category` | string | Recall class, product type, event type or dataset category |
| `date` | string | The mode's main date, `YYYY-MM-DD` UTC |
| `status` | string | Recall status or MAUDE report type; empty for labels and datasets |
| `found` | boolean | `false` only for an `identifier` lookup that matched nothing |
| `url` | string | openFDA URL that returns exactly this record |
| `detailUrl` | string | FDA or label page for the record, where one exists |
| `fetchedAt` | string | Fetch time, ISO 8601 UTC |

`recalls` adds: `recallNumber`, `eventId`, `productArea`, `classification`, `recallStatus`, `productType`,
`productDescription`, `reasonForRecall`, `productQuantity`, `codeInfo`, `moreCodeInfo`, `distributionPattern`,
`recallingFirm`, `firmAddress`, `firmCity`, `firmState`, `firmPostalCode`, `firmCountry`, `voluntaryMandated`,
`initialFirmNotification`, `recallInitiationDate`, `centerClassificationDate`, `reportDate`, `brandNames[]`,
`genericNames[]`, `manufacturerNames[]`, `productNdcs[]`.

`drugLabels` adds: `setId`, `splId`, `version`, `effectiveDate`, `brandName`, `brandNames[]`, `genericName`,
`genericNames[]`, `manufacturerName`, `substanceNames[]`, `productNdcs[]`, `packageNdcs[]`, `routes[]`, `productType`,
`rxcuis[]`, `pharmClasses[]`, `applicationNumbers[]`, `isOriginalPackager`, `labelUrl`, and `sections{}` with
`includeText`. The scalar `brandName`/`genericName` are the first entry of the matching array, so filters and
spreadsheets work on a string.

`deviceEvents` adds: `reportNumber`, `mdrReportKey`, `eventType`, `dateReceived`, `dateOfEvent`, `dateReport`,
`sourceType`, `deviceBrandName`, `deviceGenericName`, `deviceManufacturer`, `productCode`, `modelNumber`,
`catalogNumber`, `lotNumber`, `udiDi`, `deviceName`, `deviceClass`, `medicalSpecialty`, `regulationNumber`,
`productProblems[]`, `patientProblems[]`, `deviceCount`, `patientCount`, `remedialAction`, `summaryReportFlag`, and
`narrative` with `includeText`.

`datasets` adds: `datasetKey`, `endpointCategory`, `endpointName`, `exportDate`, `totalRecords`, `partitionCount`,
`downloadSizeMb`, `downloadUrl`.

Link fields: `url` is always an `api.fda.gov` query that returns this single record. For device reports `detailUrl` is
the MAUDE detail page built from `mdr_report_key` plus the product code — building it from the report number instead is
the usual reason such links do not open. For drug labels `detailUrl` and `labelUrl` point at the DailyMed page of the
SPL set; for datasets `detailUrl` is the openFDA documentation page. Recall enforcement records have no per-record page
on the FDA site, so `detailUrl` is empty there.

Dataset views: **Overview** (works for every mode), **Recall enforcement reports**, **Drug labels (SPL)**,
**Device adverse events**.

A `SUMMARY` record in the run's key-value store holds the endpoint and the exact search expression that was sent, the
dataset's `last_updated` date, the total number of matches, rows written, API requests used, how many rows were dropped
by a filter or as already seen, every input warning, and the FDA disclaimer.

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~openfda-records/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"recalls","productArea":"drug","classifications":["Class I"],"sinceDays":365,"maxItems":20}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/openfda-records').call({
    mode: 'deviceEvents', query: 'infusion pump', searchField: 'genericName', sinceDays: 180, maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/openfda-records").call(run_input={
    "mode": "drugLabels", "query": "ibuprofen", "searchField": "genericName", "maxItems": 15,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

For LLM agents, `fields` keeps rows small enough to paste into a prompt:
`{"mode":"recalls","classifications":["Class I"],"sinceDays":90,"fields":["recallNumber","productDescription","reasonForRecall","recallingFirm","reportDate"]}`.

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/openfda-records` tool with the
same JSON input.

### Pricing

Pay per event: **$0.001 per run start + $0.002 per dataset row**. Nothing else is charged; there is no proxy and no
browser in the run.

| Run | Cost |
|---|---|
| The default 25-row recall search | $0.051 |
| 50 rows (a typical monitoring run, ~40 s) | $0.101 |
| 500 rows | $1.001 |

Lower tiers on Apify reduce the per-row price automatically (Bronze −10 %, Silver −20 %, Gold and above −30 %).

### Limits & FAQ

- **Rate limit.** The actor uses openFDA without an API key: 240 requests per minute and 1,000 per day per IP. A run
  needs one request per 1,000 recall rows (500 for labels and device reports) plus a retry budget, so a normal run
  costs 1–2 requests. 429 answers are retried with backoff.
- **Paging depth.** openFDA refuses to page past 25,000 records of one query. `maxItems` is capped at 5,000, which stays
  well inside that, but a query that would need to skip further stops with a message asking you to narrow the filters.
- **Freshness.** FDA publishes in batches, roughly weekly. On 2026-09-19 the enforcement datasets were last updated
  2026-09-09 and device events 2026-09-08, with the newest report received 2026-08-31. A `sinceDays` window shorter
  than about 30 days can legitimately return nothing — that is the source, not the actor.
- **Empty results are not errors.** openFDA answers "no matches" with HTTP 404; the actor reports zero rows with a
  message that says what to widen. Only an `identifier` lookup writes a row (`found: false`), so you can tell "id does
  not exist" from "run failed".
- **`openfda` is often empty.** Device and food recall records usually have no `openfda` block, so `brandNames`,
  `genericNames` and `productNdcs` are empty arrays on those rows. Drug recalls and labels do have it.
- **Recall numbers can be missing.** Food enforcement records are published before FDA assigns a recall number; those
  rows fall back to `event-<eventId>` as `recordId` and leave `recallNumber` empty.
- **No personal data.** MAUDE records contain patient age, sex, weight, race and ethnicity and a manufacturer contact
  person with phone and address. None of those are ever written to the dataset. Patient *problem* codes and the device
  and patient counts are kept, because that is what safety analysis needs. Company names and addresses in recall
  records stay — they are the subject of the record.
- **What is not here.** This actor covers four endpoints. openFDA has more (drug adverse events/FAERS, NDC directory,
  510(k), UDI, Drugs@FDA, Orange Book, drug shortages, food and cosmetic events, tobacco reports); `mode: "datasets"`
  lists them all with their freshness, but reading their records is not implemented. FDA guidance documents are not
  part of openFDA at all.
- **Is this medical advice?** No. openFDA data is provided as-is. Adverse event and recall records are reports and do
  not establish that a product caused a problem. Do not use this data to make decisions about medical care.
- **Licence.** FDA data is US public domain and may be used commercially; FDA asks for credit and does not endorse any
  product built on it. The actor calls only `api.fda.gov`.

***

Made by **Yadroo**. Sibling actors: [sec-edgar-filings](https://apify.com/yadroo/sec-edgar-filings),
[sanctions-screen](https://apify.com/yadroo/sanctions-screen),
[world-bank-indicators](https://apify.com/yadroo/world-bank-indicators),
[openalex-works](https://apify.com/yadroo/openalex-works),
[public-holidays](https://apify.com/yadroo/public-holidays).

# Actor input Schema

## `mode` (type: `string`):

Which openFDA endpoint to read. `recalls` = /{drug|device|food}/enforcement, `drugLabels` = /drug/label, `deviceEvents` = /device/event, `datasets` = the export status of every openFDA dataset (one row per dataset, ignores the filters below).

## `productArea` (type: `string`):

Which enforcement-report dataset to read in `recalls` mode. Ignored by the other modes.

## `query` (type: `string`):

Words to search for, e.g. a drug name, a device type, a firm or a recall reason. Several words are treated as a phrase; leave empty to list everything that matches the filters. Which field is searched is set by `searchField`.

## `searchField` (type: `string`):

Which field `query` is matched in. `identifier` looks up one exact record and returns a row with `found: false` when the id does not exist. Fields that an endpoint does not have fall back to `auto`.

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

Keep only recalls of these classes. Empty = all classes.

## `recallStatuses` (type: `array`):

Keep only recalls with these statuses. Empty = all.

## `eventTypes` (type: `array`):

`deviceEvents` only: keep only reports of these event types. Empty = all.

## `productCode` (type: `string`):

Three-letter FDA device product code (e.g. QFG for alternate-controller insulin pumps, DXT for infusion pumps). Applies to `deviceEvents` only (device reports). See README → Reference dictionaries.

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

Two-letter US state code of the recalling firm, e.g. NJ, CA, TX. `recalls` only.

## `country` (type: `string`):

Country of the recalling firm as openFDA spells it, e.g. "United States", "India", "Germany". `recalls` only.

## `sinceDays` (type: `integer`):

Keep only records whose main date (report date for recalls, date received for device reports, effective date for labels) falls in the last N days. Use it for monitoring runs; leave empty for the whole archive. FDA publishes in weekly batches, so allow at least 30 days.

## `fromDate` (type: `string`):

Earliest date, YYYY-MM-DD, inclusive. Ignored when `sinceDays` is set.

## `toDate` (type: `string`):

Latest date, YYYY-MM-DD, inclusive. Ignored when `sinceDays` is set.

## `onlyNew` (type: `boolean`):

Keep a list of record ids in this actor's key-value store and output only records that were not in it on the previous run. Makes a scheduled task emit just the new recalls or reports. The first run outputs everything it finds.

## `sortOrder` (type: `string`):

Order by the record's main date.

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

Stop after this many rows. openFDA allows paging through roughly 25,000 hits per query; narrow the filters for bigger jobs.

## `includeText` (type: `boolean`):

Add the label sections (`drugLabels`) or the narrative text of the report (`deviceEvents`) to every row. Off by default because these fields can be tens of kilobytes each.

## `labelSections` (type: `array`):

Which SPL sections land in `sections` when `includeText` is on. Empty = purpose, indications and usage, and warnings. Sections a label does not have are left out.

## `fields` (type: `array`):

Keep only these output fields, in this order, e.g. \["recallNumber", "classification", "productDescription", "url"]. Empty = all fields of the mode.

## `customSearch` (type: `string`):

Advanced: a raw openFDA query string that is ANDed to everything above, e.g. `openfda.pharm_class_epc:"Nonsteroidal+Anti-inflammatory+Drug"` or `patient.patient_problems:"Death"`. Use the field names of the endpoint you selected; an invalid expression fails the run with the API's own message.

## Actor input object example

```json
{
  "mode": "recalls",
  "productArea": "drug",
  "query": "insulin",
  "searchField": "auto",
  "onlyNew": false,
  "sortOrder": "newest",
  "maxItems": 25,
  "includeText": false
}
```

# Actor output Schema

## `results` (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 = {
    "query": "insulin"
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/openfda-records").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 = { "query": "insulin" }

# Run the Actor and wait for it to finish
run = client.actor("yadroo/openfda-records").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 '{
  "query": "insulin"
}' |
apify call yadroo/openfda-records --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/openfda-records"
        }
    }
}
```

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/wvEdyOdlvpQ1DefkO/builds/DIcXkdpQjgg7PfUVm/openapi.json
