Product Recall & Safety API
The Product Recall API returns FDA product-safety recalls as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary search endpoint returns normalized enforcement records with a severity score, and you can pull a recall_detail, recalls by company, the latest recalls, stats and categories, and batch. It is built for compliance, marketplace safety and consumer apps that need recall data without parsing raw FDA feeds. One ReefAPI key, one shared credit pool, the standard envelope.
Recall number prefixes, hazard classes and the severity score
The recall_number prefix, not a category field, is what tells you which FDA registry a row came from, and recall_detail auto-detects the category from it. The hazard class and the derived severity_score are two different things, and the score is ours rather than the FDA's. Everything below was read off live responses in August 2026.
| Value | What it means | Measured |
|---|---|---|
| H-… | Food and cosmetics recall. This is the prefix most current food recalls actually carry, not F | H-1034-2026, Albertsons peanut butter bar, Class II; 15 of 50 rows in a 30-day latest sweep |
| F-… | Also food, from the older enforcement numbering. recall_detail still resolves it to category food | F-1397-2012 returned meta.category food without passing category |
| D-… | Human and animal drug recall | D-0590-2025, PFIZER INC, Class II, Ongoing |
| Z-… | Medical device recall | 17 of 50 rows in the same 30-day latest sweep |
| Class I / II / III | FDA hazard tier, I being the most serious | food stats: 12,867 Class I, 14,704 Class II, 1,745 Class III |
| Not Yet Classified | A fourth classification value the parameter enum does not list, used while the FDA has not tiered the recall yet | 2 of 50 rows in the 30-day sweep; 1 row in the all-time food classification stats |
| severity_score | A derived 0-100 number built from hazard class plus lifecycle status. It is not an FDA field | Class I ongoing 80-100, Class I terminated 70, Class II 55-75, Class III 45, Not Yet Classified 50-60 |
| Date fields | Plain YYYYMMDD strings with no separators, and null when the event has not happened | report_date 20260610, termination_date 20260702 on a terminated recall and null on an ongoing one |
status accepts Ongoing, Completed, Terminated and Pending and is declared on_invalid=ignore, so a typo silently returns unfiltered results instead of an error. classification and category are on_invalid=reject and fail loudly instead.
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/recall/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "listeria",
"category": "food",
"limit": 3
}
}{
"ok": true,
"meta": {
"api": "recall",
"endpoint": "search",
"mode": "live",
"latency_ms": 1143.9,
"record_count": 3,
"bytes": 4182,
"cache_hit": false,
"sources": "openFDA-RES + EU-Safety-Gate",
"categories_searched": [
"food"
],
"total": 7469,
"skip": 0,
"limit": 3,
"has_more": true,
"next_skip": 3
},
"data": {
"recalls": [
{
"source": "openFDA",
"category": "food",
"recall_number": "H-[redacted-phone]",
"event_id": "98993",
"status": "Ongoing",
"classification": "Class I",
"severity_score": 80,
"recalling_firm": "HH FRESH TRADING CORP",
"product_description": "HH Fresh Trading Corp. (branded) ENOKI MUSHROOM; Premium Quality; Net WT/ Poids Net 150g(5.29oz) Distributed by HH Fresh Trading Exported by JIA YANG INTERNATIONAL ENTERPRISES CO., LTD. Produced by Green Farm (Taiwan) UPC: [redacted-phone]",
"product_quantity": "120 cases",
"reason_for_recall": "Imported Enoki Mushrooms tested positive for Listeria Monocytogenes.",
"code_info": "No lot codes",
"product_type": "Food",
"voluntary_mandated": "Voluntary: Firm initiated",
"initial_firm_notification": "Telephone",
"distribution_pattern": "Product was distributed to a single customer located in Texas. Product was further distributed as samples were collected in Florida.",
"city": "Los Angeles",
"state": "CA",
"country": "United States",
"recall_initiation_date": "20260511",
"center_classification_date": "20260610",
"report_date": "20260617",
"termination_date": null,
"more_code_info": null,
"brand_name": null,
"generic_name": null,
"manufacturer_name": null,
"product_ndc": null,
"substance_name": null,
"device_name": null,
"medical_specialty_description": null,
"openfda": null
},
{
"source": "openFDA",
"category": "food",
"recall_number": "H-[redacted-phone]",
"event_id": "99001",
"status": "Ongoing",
"classification": "Class I",
"severity_score": 80,
"recalling_firm": "IQ PRODUCE, LLC",
"product_description": "Enoki Mushroom, Net Weight 150g; Product of Korea; Distributed by IQ Produce UPC: [redacted-phone]",
"product_quantity": "319 units",
"reason_for_recall": "Imported Enoki Mushrooms samples collected by Florida Department of Health tested positive for Listeria Monocytogenes.",
"code_info": "Lot UI775",
"product_type": "Food",
"voluntary_mandated": "Voluntary: Firm initiated",
"initial_firm_notification": "Two or more of the following: Email, Fax, Letter, Press Release, Telephone, Visit",
"distribution_pattern": "Product was distributed to 3 California customers.",
"city": "Vernon",
"state": "CA",
"country": "United States",
"recall_initiation_date": "20260514",
"center_classification_date": "20260602",
"report_date": "20260610",
"termination_date": null,
"more_code_info": "",
"brand_name": null,
"generic_name": null,
"manufacturer_name": null,
"product_ndc": null,
"substance_name": null,
"device_name": null,
"medical_specialty_description": null,
"openfda": null
},
{
"source": "openFDA",
"category": "food",
"recall_number": "H-[redacted-phone]",
"event_id": "98725",
"status": "Ongoing",
"classification": "Class I",
"severity_score": 90,
"recalling_firm": "HEMU TRADING INC",
"product_description": "Black label with blue lettering. FOOD Korean Food, ENOKI MUSHROOM, 150g clear plastic package; Product of Korea, Keep Refrigerated. Distributed by Hemu Trading Inc. UPC: [redacted-phone]",
"product_quantity": "1056 cases (34 packs/case)",
"reason_for_recall": "product tested positive for Listeria Monocytogenes.",
"code_info": "Lot code:215",
"product_type": "Food",
"voluntary_mandated": "Voluntary: Firm initiated",
"initial_firm_notification": "Two or more of the following: Email, Fax, Letter, Press Release, Telephone, Visit",
"distribution_pattern": "5 direct account consignees located in CA, FL and MD.",
"city": "Los Angeles",
"state": "CA",
"country": "United States",
"recall_initiation_date": "20260402",
"center_classification_date": "20260430",
"report_date": "20260506",
"termination_date": null,
"more_code_info": "",
"brand_name": null,
"generic_name": null,
"manufacturer_name": null,
"product_ndc": null,
"substance_name": null,
"device_name": null,
"medical_specialty_description": null,
"openfda": null
}
],
"categories_searched": [
"food"
],
"total": 7469,
"skip": 0,
"limit": 3,
"has_more": true,
"next_skip": 3
}
}What the Product Recall & Safety API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | Search FDA recalls by keyword, category, classification, status, company, and date range with skip/limit pagination. Pass category=all (default) to span food+drug+device. | Ops teams call search to search FDA recalls by keyword, category, classification, status, company, and date range with…. | query, category, classification, status, company, ... |
| recall_detail | Full detail for one recall by its FDA recall_number (category auto-detected from prefix). | Developer tools call recall_detail to get full detail for one recall by its FDA recall_number (category auto-detected from prefix).. | recall_number, category |
| by_company | All recalls for a recalling firm / manufacturer, newest first, paginated. | Validation workflows call by_company to get all recalls for a recalling firm / manufacturer, newest first, paginated.. | company, category, classification, status, date_from, ... |
| latest | Most recent recalls across all categories (or one), within the last N days. | Data-quality teams call latest to get most recent recalls across all categories (or one), within the last N days.. | category, classification, days, limit, skip, ... |
| batch | Run multiple keyword searches in one call (compliance-watch over a product list). | Ops teams call batch to get run multiple keyword searches in one call (compliance-watch over a product list).. | queries, category, classification, limit |
| stats | Aggregate recall counts grouped by a field (classification/status/firm/state/type). | Developer tools call stats to get aggregate recall counts grouped by a field (classification/status/firm/state/type).. | category, field, query, date_from, date_to |
| categories | The recall taxonomy: FDA categories + EU Safety Gate product-category & risk-type enums + EU country list (reference data for filters). | Validation workflows call categories to get the recall taxonomy. | none |
| eu_recall | One EU Safety Gate (RAPEX) recall/alert by notification id — product, risk, measure, traceability, reacting countries. | Data-quality teams call eu_recall to get one EU Safety Gate (RAPEX) recall/alert by notification id. | id, language |
| eu_recalls | Search/list EU Safety Gate alerts (the EU analogue of `search`): pages over recent weekly reports (open-data XML) and filters by query, product category, country and risk type, with skip/limit pagination. Each alert carries product, barcode, brand, risk, measures, notifying country and country of origin. | Ops teams call eu_recalls to get search/list EU Safety Gate alerts (the EU analogue of `search`). | query, category, country, risk_type, weeks, ... |
| eu_latest | The newest EU Safety Gate weekly report fully expanded into its ~80-100 product alerts (newest-published recalls across the EU/EEA). | Developer tools call eu_latest to get the newest EU Safety Gate weekly report fully expanded into its ~80-100 product alerts (newes…. | limit |
Call search from your stack
curl -X POST https://api.reefapi.com/recall/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"listeria","category":"food","limit":3}'import requests
r = requests.post(
"https://api.reefapi.com/recall/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "listeria",
"category": "food",
"limit": 3
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/recall/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "listeria",
"category": "food",
"limit": 3
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.recall.search with {"query":"listeria","category":"food","limit":3}.Who uses this API and why
- Marketplaces call by_company to flag products from a brand with active recalls.
- Compliance teams monitor latest recalls for their categories.
- Consumer apps use search and recall_detail to warn users.
Questions developers ask before integrating
Why does my food recall number start with H when the docs say F means food?
Both prefixes are food. F belongs to the older enforcement numbering and H is what current food recalls carry: in a 30-day latest sweep all 15 food rows were H-something, for example H-1034-2026 from Albertsons. You do not have to work it out yourself. recall_detail auto-detects the category from the prefix, and passing only recall_number H-1034-2026 came back with meta.category food.
Does this cover vehicle, CPSC or EU recalls?
Not in the search results. Every row measured across search, latest and by_company carried source openFDA, covering the FDA food, drug and device registries only. The categories action does return EU Safety Gate reference vocabulary, 34 product-category keys, 22 risk types and a 251-entry country list, but no EU rows came back from the data actions. NHTSA vehicle recalls are a separate engine.
Is severity_score an FDA number?
No. The FDA publishes a hazard class, not a score. severity_score is derived from that class plus the recall's lifecycle status, which is why one class spans a range: ongoing Class I recalls measured 80, 90 and 100 while a terminated Class I, F-1397-2012, scored 70. Class II ran 55 to 75 and Class III 45. Set include_severity to false if you want the record without it.
Why did stats ignore my category=all?
stats aggregates one registry at a time. A call with field classification and category all came back with meta.category food and food-only buckets. To get cross-category totals, run stats once per category and add them up. The same call with category drug returned its own buckets: 14,801 Terminated, 2,662 Ongoing and 436 Completed.
Which fields come back null on a normal record?
The drug and device specific fields are null on food rows and the other way round. On measured food records brand_name, generic_name, manufacturer_name, product_ndc, substance_name, device_name and openfda were all null, while product_description, reason_for_recall, recalling_firm, city, state and the dates were populated. termination_date is null for anything still Ongoing. Check the field you need, not whether a record came back.
How do I page past the first 20 results?
Every list response carries total, has_more and next_skip, and you feed next_skip back in as skip. limit tops out at 100 per page and the underlying ceiling is skip plus limit at most 25,000, so roughly 25,000 records per filter combination. A search for peanut butter in food reported total 680 with limit 3 and next_skip 3.
What does latest with category=all actually return?
It fans out across all three registries and merges them, so a limit of 50 is not 50 rows from one place. A measured 30-day window returned 16 food, 17 drug and 17 device rows, with meta.categories_searched listing all three and total 328. Ordering is newest report_date first, and the window is set by days, which defaults to 90 and caps at 3,650.
Can I watch a list of products in one request?
Yes. batch takes up to 20 keyword queries and returns a separate {query, count, recalls[]} block for each, which is the compliance-watch shape. If you already know the firm, by_company is more precise: it matches the FDA recalling_firm field case-insensitively on partial words, which is why a Pfizer query returned rows filed under both PFIZER INC and Pfizer, 155 in total in the drug registry.
What is the Product Recall & Safety API?
Product Recall & Safety API is a ReefAPI endpoint group for product recall & safety It returns live JSON through POST requests under /recall/v1.
Is the Product Recall & Safety API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Product Recall & Safety calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Product Recall & Safety login or account?
No login to Product Recall & Safety is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Product Recall & Safety data?
The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Product Recall & Safety API use?
Product Recall & Safety actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Product Recall & Safety from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call recall actions with the same key, credit pool and JSON envelope used by normal REST requests.