Skip to content

API docs

Every U.S. recall from CPSC, FDA, USDA FSIS and NHTSA, in one JSON format. Base URL: https://recallrelay.com

Quickstart

Create a free key on the home page, then:

curl "https://recallrelay.com/v1/recalls?q=crib&min_severity=high&limit=5" \
  -H "X-API-Key: $RECALLRELAY_KEY"

Lists come back as {"data": [...], "total": 128, "limit": 5, "offset": 0, "next": "…"}. Follow next to page.

Your API key

Send it in the X-API-Key header, or as Authorization: Bearer <key>. Keep it on your server; don't ship it in a browser or mobile app. /v1/stats works without a key.

Limits and errors

PlanRequestsAlertsItems per catalog check
Free 100 a day 125
Starter 10,000 a month 5500
Pro 100,000 a month 505,000
Business 1,000,000 a month 50050,000

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. A catalog check costs one request per 100 items.

Errors use HTTP status codes and one shape:

{"error": {"code": "limit_reached", "message": "Your Free plan limit is used up. It resets 2026-11-15."}}
400 invalid_requestA parameter is wrong; the message says which and how to fix it.
401 missing_keyNo key, or the key isn't active.
404 not_foundNo recall, alert or endpoint with that id.
429 limit_reachedPlan limit used up until the reset date.
502 upstream_unavailableNHTSA's live vehicle lookup didn't answer. Retry shortly.

The recall record

Every agency's recalls use these fields. Agency-only details (lot codes, injuries, do-not-drive flags) live in extra.

FieldWhat it holds
idStable id: `<source>-<agency recall number>`
source One of: cpsc, fda, fsis, nhtsa.
agency
agency_name
category One of: consumer_product, food, drug, device, meat_poultry_egg, vehicle, vehicle_equipment, tire, child_seat.
title
descriptionWhat was recalled.
hazardWhy it was recalled.
remedyWhat owners should do.
classificationAgency class (Class I, II, III) when the agency assigns one.
severity One of: low, medium, high.
severity_basis`estimated` means Recall Relay inferred severity from the hazard text. One of: agency_class, agency_advisory, estimated.
status One of: ongoing, completed, terminated.
recall_date
published_date
companies
products
upcsBarcodes named in the recall: labeled UPC, GTIN, EAN or (for medical devices) UDI-DI, check digit verified.
statesTwo-letter codes; `US` means nationwide.
distribution
units_affected
urlThe agency's own record.
images
extraAgency-specific fields (lot codes, injuries, do-not-drive flags...).
first_seenWhen Recall Relay first saw it.

Verifying alerts

Alert deliveries are POSTed as JSON with a RecallRelay-Signature header: t=<unix time>,v1=<hex>. The hex is an HMAC-SHA256 of "<t>.<raw body>" using the secret you got when you created the alert. Reply with any 2xx status; anything else is retried with backoff.

Python

import hmac, hashlib, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    mac = hmac.new(secret.encode(), f'{parts["t"]}.'.encode() + raw_body, hashlib.sha256)
    return hmac.compare_digest(mac.hexdigest(), parts["v1"])

Node.js

import crypto from "node:crypto";

export function verify(rawBody, header, secret) {
  const p = Object.fromEntries(header.split(",").map(s => s.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(p.t)) > 300) return false;
  const mac = crypto.createHmac("sha256", secret).update(`${p.t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(p.v1));
}
GET/v1/recalls

Search recalls

Full-text search across every agency with filters. Newest first, or `sort=relevance`.

ParameterDescription
q Words to search for. Every word must match; the last word matches as a prefix. Example: crib
source Comma-separated agencies. Example: cpsc,fda
category Comma-separated categories: consumer_product, food, drug, device, meat_poultry_egg, vehicle, vehicle_equipment, tire, child_seat. Example: food,drug
min_severity Only recalls at or above this severity. One of: low, medium, high.
since Recall date on or after (YYYY-MM-DD). Example: 2026-01-01
until Recall date on or before (YYYY-MM-DD).
state Two-letter state; nationwide recalls always match. Example: CA
company Company name contains this text. Example: medtronic
status ongoing, completed or terminated. One of: ongoing, completed, terminated.
sort recent (default) or relevance. One of: recent, relevance.
limit 1 to 100. Default 20.
offset For paging.
curl "https://recallrelay.com/v1/recalls?q=crib&source=cpsc,fda&category=food,drug" \
  -H "X-API-Key: $RECALLRELAY_KEY"
GET/v1/recalls/{id}

Get one recall

ParameterDescription
id required Recall id, for example `fda-D-0006-2027`.
curl "https://recallrelay.com/v1/recalls/fda-D-0006-2027" \
  -H "X-API-Key: $RECALLRELAY_KEY"
GET/v1/upc/{upc}

Look up a barcode

Recalls that name this UPC, EAN or GTIN. Leading zeros and spaces are ignored.

ParameterDescription
upc required The barcode digits. Example: 867166000004
curl "https://recallrelay.com/v1/upc/867166000004" \
  -H "X-API-Key: $RECALLRELAY_KEY"
POST/v1/check

Check a product list

Send your catalog; get back which items match a recall. Barcodes give exact matches; brand and name give possible matches to review. Costs 1 request per 100 items.

curl -X POST "https://recallrelay.com/v1/check" \
  -H "X-API-Key: $RECALLRELAY_KEY" -H "Content-Type: application/json" \
  -d '{"items": [{"id": "sku-1001", "upc": "8 67166 00000 4"}, {"brand": "Sharper Image", "id": "sku-1002", "name": "Tabletop Fire Pit, concrete"}]}'
GET/v1/vehicles

Recalls for a vehicle

Recalls for one make, model and model year, straight from NHTSA (cached 24 hours).

ParameterDescription
make required Vehicle make. Example: honda
model required Vehicle model. Example: pilot
year required Model year. Example: 2023
curl "https://recallrelay.com/v1/vehicles?make=honda&model=pilot&year=2023" \
  -H "X-API-Key: $RECALLRELAY_KEY"
GET/v1/watches

List alerts

curl "https://recallrelay.com/v1/watches" \
  -H "X-API-Key: $RECALLRELAY_KEY"
POST/v1/watches

Create an alert

Get a signed webhook the moment a new recall matches. Set any of `q`, `upcs`, `companies` (a recall matches if any of them match), and narrow with `categories`, `sources`, `min_severity` and `states`. Each list takes up to 200 values; create more alerts for longer lists. The webhook_url must be a public https address. The response includes the signing secret once.

curl -X POST "https://recallrelay.com/v1/watches" \
  -H "X-API-Key: $RECALLRELAY_KEY" -H "Content-Type: application/json" \
  -d '{"categories": ["consumer_product"], "min_severity": "medium", "name": "Baby gear we resell", "q": "crib", "webhook_url": "https://example.com/hooks/recalls"}'
DELETE/v1/watches/{id}

Delete an alert

ParameterDescription
id required Alert id.
POST/v1/watches/{id}/test

Send a test alert

ParameterDescription
id required Alert id.
GET/v1/statsNo key

Coverage and freshness

Record counts and the last successful update for each agency. No key needed.

curl "https://recallrelay.com/v1/stats" \
  -H "X-API-Key: $RECALLRELAY_KEY"
GET/v1/me

Your plan and usage

curl "https://recallrelay.com/v1/me" \
  -H "X-API-Key: $RECALLRELAY_KEY"