ProductGuru · Recalls · Data · Developers
A free, open, read-only API over consumer-product recall notices compiled from 31 public regulatory authorities worldwide. No key. No account. No write endpoints. Every record names the authority that issued it and links to that authority’s own notice.
curl -s "https://myproduct.guru/api/v1/recalls/3109850018511"Is this barcode recalled anywhere in the world?| Base URL | https://myproduct.guru/api/v1 |
|---|---|
| Auth | None. No key, no registration, no tiers. |
| Methods | GET and HEAD only. There are no write endpoints. |
| Format | JSON (UTF-8). CORS Access-Control-Allow-Origin: * — call it straight from the browser. |
| Rate limit | 60 requests/minute per IP, burst 20. Over the limit you get 429 with Retry-After. |
| Caching | Every response carries ETag and Last-Modified. Send If-None-Match, get 304. |
| Licence | CC-BY-4.0 — header X-Data-License: CC-BY-4.0 |
| Cite as | ProductGuru consumer recall dataset (https://myproduct.guru), CC BY 4.0, DOI 10.5281/zenodo.22685727 — 10.5281/zenodo.22685727 |
| OpenAPI | /api/v1/openapi.json |
authority vs issuing_body. authority is the register a notice was compiled from; issuing_body is the government body that actually issued it. For most registers these are the same. They differ for shared portals — canada-recall-portal carries Transport Canada, the Canadian Food Inspection Agency and several Health Canada branches side by side, so we resolve the issuer per notice rather than crediting one regulator for all of them. Where the portal does not say, issuing_body names the portal itself; we never guess a regulator.The core call. Pass an EAN/GTIN of 8–14 digits. Returns every notice on file for that barcode, newest first.
curl -s "https://myproduct.guru/api/v1/recalls/3109850018511"{
"meta": { "license": "CC-BY-4.0", "doi": "10.5281/zenodo.22685727", ... },
"ean": "3109850018511",
"recalled": true,
"count": 1,
"recalls": [
{
"authority": "rappelconso-france",
"authority_name": "RappelConso — Government of France",
"authority_url": "https://rappel.conso.gouv.fr/",
"notice_id": "2024-05-0123",
"notice_url": "https://rappel.conso.gouv.fr/fiche-rappel/.../interne",
"published_date": "2024-05-14",
"first_indexed_at": "2024-05-15T03:12:44Z",
"country": "FR",
"country_name": "France",
"risk_level": null,
"authority_classification": "volontaire (sans arrêté préfectoral)",
"hazard": "… the authority's own hazard wording …",
"product_name": "antesite reglisse anis",
"product_category": "Food",
"ean": "3109850018511",
"productguru_url": "https://myproduct.guru/wiki/recall/…"
}
]
}"recalled": false with "count": 0 is a normal 200 — a barcode with no notice on file is an answer, not an error. A string that is not 8–14 digits is a 400.
Filter by date, country, authority, category or brand. Newest first.
curl -s "https://myproduct.guru/api/v1/recalls?since=2026-08-01&country=FR&limit=5"Everything the EU Safety Gate recalled in the Toys category.
curl -s "https://myproduct.guru/api/v1/recalls?authority=eu-safety-gate&category=Toys&limit=50"Polling for new data? Sort by indexed and filter on updated_since — that is when we first saw the notice, so nothing slips past you when an authority backdates one.
curl -s "https://myproduct.guru/api/v1/recalls?updated_since=2026-09-01&sort=indexed&limit=100"| Parameter | Meaning |
|---|---|
since, until | YYYY-MM-DD. Filters the authority’s publication date. |
updated_since | YYYY-MM-DD. Filters when ProductGuru first indexed the notice. |
country | ISO 3166-1 alpha-2, e.g. FR. See /countries. |
authority | Slug from /authorities, e.g. us-cpsc. |
category, brand | Exact match, case-insensitive. |
sort | published (default) or indexed. |
limit | 1–100, default 20. |
offset | 0–10,000. Past that, narrow the window with since/until — deep offsets are slow for everyone. |
The response’s meta.next is the ready-made URL for the following page, or null at the end.
Totals by authority, by year and by country, plus when the dataset was last added to. Cached for an hour.
curl -s "https://myproduct.guru/api/v1/recalls/stats"Slug, official name, homepage and current notice count for every register.
curl -s "https://myproduct.guru/api/v1/authorities"Every ISO 3166-1 alpha-2 code present in the data, with counts.
curl -s "https://myproduct.guru/api/v1/countries"Newly indexed notices, as they land. Both feeds accept the same ?authority=, ?country= and ?limit= filters as the listing endpoint.
Subscribe in any reader, or wire it into Slack, Zapier or an alerting job.
curl -s "https://myproduct.guru/recalls.xml" # RSS 2.0
curl -s "https://myproduct.guru/recalls.atom" # Atom 1.0
curl -s "https://myproduct.guru/recalls.xml?country=DE&limit=25" # filteredPython, standard library only — no SDK, no key.
import urllib.request, json
url = "https://myproduct.guru/api/v1/recalls/3109850018511"
with urllib.request.urlopen(url) as r:
data = json.load(r)
print(data["recalled"], data["count"])
for rec in data["recalls"]:
print(rec["authority_name"], "-", rec["hazard"][:80])
print(" official notice:", rec["notice_url"])Send back the ETag you were given and unchanged pages cost you nothing.
ETAG=$(curl -sI "https://myproduct.guru/api/v1/recalls?limit=5" \
| awk -F": " 'tolower($1)=="etag"{print $2}' | tr -d "\r")
curl -s -o /dev/null -w '%{http_code}\n' \
-H "If-None-Match: $ETAG" "https://myproduct.guru/api/v1/recalls?limit=5"
# 304updated_since once a day rather than crawling every page.public-cacheable. Please honour max-age.The data is licensed CC-BY-4.0. Use it commercially, remix it, ship it in an app — just say where it came from:
ProductGuru consumer recall dataset (https://myproduct.guru), CC BY 4.0, DOI 10.5281/zenodo.22685727authority_name and notice_url pointing at the register that actually issued it. When something matters, verify it there. This API is informational only and is not legal, medical or safety advice.| Slug | Authority | Jurisdiction |
|---|---|---|
accc-australia | Australian Competition and Consumer Commission | AU |
bvl-germany | Bundesamt für Verbraucherschutz und Lebensmittelsicherheit (Germany) | DE |
eu-safety-gate | European Commission — Safety Gate (RAPEX) | EU |
fsai-ireland | Food Safety Authority of Ireland | IE |
fsanz-australia-nz | Food Standards Australia New Zealand | AU |
canada-recall-portal | Government of Canada — recall portal (recalls-rappels.canada.ca) | CA |
gis-poland | Główny Inspektorat Sanitarny (Poland) | PL |
oecd-globalrecalls-bn | OECD GlobalRecalls — Brunei Darussalam | BN |
oecd-globalrecalls-tw | OECD GlobalRecalls — Chinese Taipei | TW |
oecd-globalrecalls-co | OECD GlobalRecalls — Colombia | CO |
oecd-globalrecalls-cr | OECD GlobalRecalls — Costa Rica | CR |
oecd-globalrecalls-id | OECD GlobalRecalls — Indonesia | ID |
oecd-globalrecalls-il | OECD GlobalRecalls — Israel | IL |
oecd-globalrecalls-jp | OECD GlobalRecalls — Japan | JP |
oecd-globalrecalls-kr | OECD GlobalRecalls — Korea | KR |
oecd-globalrecalls-my | OECD GlobalRecalls — Malaysia | MY |
oecd-globalrecalls-ph | OECD GlobalRecalls — Philippines | PH |
oecd-globalrecalls-sg | OECD GlobalRecalls — Singapore | SG |
oecd-globalrecalls-th | OECD GlobalRecalls — Thailand | TH |
oecd-globalrecalls-ae | OECD GlobalRecalls — United Arab Emirates | AE |
oecd-globalrecalls-vn | OECD GlobalRecalls — Viet Nam | VN |
rappelconso-france | RappelConso — Government of France | FR |
senacon-brazil | Senacon — Secretaria Nacional do Consumidor (Brazil) | BR |
transport-canada | Transport Canada — Vehicle Recalls Database | CA |
us-cpsc | U.S. Consumer Product Safety Commission | US |
us-fda-food | U.S. Food and Drug Administration — Food Enforcement | US |
us-fda-devices | U.S. Food and Drug Administration — Medical Devices | US |
us-nhtsa | U.S. National Highway Traffic Safety Administration | US |
uk-dvsa | UK Driver and Vehicle Standards Agency | GB |
uk-fsa | UK Food Standards Agency | GB |
uk-opss | UK Office for Product Safety and Standards | GB |