API documentation
A read-mostly REST API over normalised
government recall data. Every response carries data_as_of, and every list is
cursor-paginated. Examples below are rendered from the live corpus.
Authentication
Send your key as a bearer token. X-API-Key is accepted as an
alternative for clients that cannot set Authorization.
curl https://api.recallproven.com/v1/recalls?limit=1 \ -H "Authorization: Bearer rk_xxxxxxxxxxxxxxxx_..."
Keys are issued on request and are shown once — we store only a hash and
cannot recover a lost key. /v1/health and this specification need no key at
all.
Rate limits and quotas
| Tier | Price | Requests / month | Identifiers / month | Burst |
|---|---|---|---|---|
free |
Free | 500 | 5,000 | 10/min |
starter |
$29/mo | 10,000 | 100,000 | 60/min |
growth |
$99/mo | 100,000 | 1,000,000 | 300/min |
scale |
$299/mo | 1,000,000 | 10,000,000 | 1000/min |
The monthly quota is the limit that governs. Burst limits are enforced per
Cloudflare location and are intentionally permissive, so treat them as a courtesy rather
than a contract. Exceeding the monthly quota returns 402; exceeding a burst
limit returns 429 with Retry-After.
Errors
Errors are RFC 9457 problem documents served as
application/problem+json. Branch on type, which is stable;
title may be reworded.
{
"type": "/problems/invalid-parameter",
"title": "Invalid query parameter",
"status": 400,
"detail": "Unknown query parameter. Supported filters: jurisdiction, source, ...",
"instance": "/v1/recalls",
"parameter": "jurisdication"
}
| type | Meaning |
|---|---|
/problems/unauthorized | unauthorized |
/problems/forbidden | forbidden |
/problems/quota-exceeded | quota exceeded |
/problems/rate-limited | rate limited |
/problems/not-found | not found |
/problems/invalid-parameter | invalid parameter |
/problems/invalid-cursor | invalid cursor |
/problems/internal | internal |
Unknown query parameters are rejected rather than ignored. A typo in a filter would otherwise return the entire corpus and look like a working query.
Caching
Every response carries a weak ETag. Send it back as
If-None-Match and an unchanged corpus returns 304 with no body.
The data is rebuilt at most once a day, so this is the difference between a cheap
integration and an expensive one.
curl -H "Authorization: Bearer $KEY" \
-H 'If-None-Match: W/"1d22962d4764190921860e3c8553e2d1"' \
https://api.recallproven.com/v1/recalls?limit=50
# HTTP/1.1 304 Not Modified
Recalls
List recalls
Requires an API keyRecalls newest first.
Parameters
| Name | Type | Description |
|---|---|---|
jurisdiction |
string | ISO-ish jurisdiction code as published, e.g. `EU`, `FR`, `US`. |
source |
string | Restrict to one source feed. See `/v1/sources`. |
hazard_category |
string | Canonical hazard taxonomy value. |
severity |
string | Normalized severity. One of: serious, high, medium, low, unknown |
remedy |
string | Normalized remedy offered to consumers. One of: repair, replace, refund, dispose, stop_use, other, unknown |
from |
string | Earliest `recall_date`, inclusive (YYYY-MM-DD). |
to |
string | Latest `recall_date`, inclusive (YYYY-MM-DD). |
limit |
integer | Rows per page. Default 50, maximum 200. |
cursor |
string | Opaque cursor from `meta.next_cursor` of the previous page. Do not construct by hand; its encoding is not part of the contract. |
include_total |
boolean | Include `meta.total`. Off by default because an exact count scans every matching row, which costs materially more than the page itself. |
Request
curl https://api.recallproven.com/v1/recalls \ -H "Authorization: Bearer $KEY"
Response — real output from the live corpus
{
"data": [
{
"id": "5cc93eac2f5fc616d74be5f97963fff5",
"source": {
"id": "nhtsa",
"record_id": "24V901000",
"agency": "NHTSA",
"jurisdiction": "US"
},
"title": "MCLAREN 765LT — STRUCTURE:BODY",
"summary": "McLaren Automotive Incorporated (McClaren) is recalling certain 2021 765LT Coupe vehicles. The rear cabin window may have insufficient adhesive bonding, which can allow the window to detach from the support frame.",
"hazard": {
"category": "injury",
"text": "A rear window that detaches from the vehicle can create a road hazard for other drivers, increasing the risk of a crash."
},
"product": {
"category": "motor_vehicle",
"brands": [
"McLaren Automotive Incorporated"
],
"models": [
"MCLAREN 765LT 2021"
]
},
"severity": "unknown",
"source_classification": "STRUCTURE:BODY",
"remedy": "unknown",
"recall_date": "2026-09-25",
"published_date": "2024-11-28",
"countries": [
"United States"
],
"url": "https://www.nhtsa.gov/recalls?nhtsaId=24V901000",
"revision": 2,
"data_as_of": "2026-07-29",
"first_seen_at": "2026-07-26T22:56:34.404Z",
"last_seen_at": "2026-07-29T18:22:00.811Z"
}
],
"meta": {
"count": 1,
"limit": 1,
"next_cursor": "eyJkIjoiMjAyNi0wNy0yNCIsImkiOiJhYmMifQ",
"data_as_of": "2026-07-29",
"attribution": [
"Source: …"
]
}
}
Fetch one recall
Requires an API keyReturns a single recall including every extracted product identifier.
Parameters
| Name | Type | Description |
|---|---|---|
idrequired |
string | Stable recall id, as returned in `data[].id`. |
Request
curl https://api.recallproven.com/v1/recalls/RECALL_ID \ -H "Authorization: Bearer $KEY"
Amendment history for a recall
Requires an API keyEvery observed change to this record, oldest first, with the field-level delta and the date we observed it.
Parameters
| Name | Type | Description |
|---|---|---|
idrequired |
string | Stable recall id. |
limit |
integer | Rows per page. Default 50, maximum 200. |
Request
curl https://api.recallproven.com/v1/recalls/RECALL_ID/revisions \ -H "Authorization: Bearer $KEY"
Lookup
Find recalls by product identifier
Requires an API keyThe catalogue-check endpoint.
Parameters
| Name | Type | Description |
|---|---|---|
kindrequired |
string | Identifier type. One of: gtin, upc, ean, vin, ndc, udi, model, lot, batch |
valuerequired |
string | The identifier as printed on the product or in your catalogue. |
limit |
integer | Rows per page. Default 50, maximum 200. |
Request
curl https://api.recallproven.com/v1/identifiers/gtin/00012345678905 \ -H "Authorization: Bearer $KEY"
Compliance checks
Check a catalogue and record the evidence
Requires an API keySubmits product identifiers, matches them against the corpus, and records an immutable receipt that the check happened.
Request
curl -X POST https://api.recallproven.com/v1/checks \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"label":"Q3 audit","identifiers":[{"kind":"gtin","value":"00012345678905"}]}'
Response — real output from the live corpus
{
"data": {
"check_id": "186948a03f7c4eec76feb148a715b387",
"label": "Q3 audit",
"performed_at": "2026-07-30T05:45:14.420Z",
"submitted_count": 2,
"submitted_digest": "644639bfbbd085d8484122214dfc92e16f0c6d6cceabefbd362c27f22c427f0b",
"rejected_count": 0,
"rejected": [],
"match_count": 1,
"result_digest": "fd4a973133a9bd937127cad0cdd2e6d63cca678060f917a22c2a461f654b1d6e",
"corpus_as_of": "2026-07-29",
"corpus_size": 176037,
"matches": [
{
"recall_id": "5cc93eac2f5fc616d74be5f97963fff5",
"matched_on": {
"kind": "gtin",
"normalized": "00012345678905"
},
"revision": 2,
"title": "MCLAREN 765LT — STRUCTURE:BODY",
"jurisdiction": "US",
"recall_date": "2026-09-25",
"severity": "unknown",
"url": "https://www.nhtsa.gov/recalls?nhtsaId=24V901000"
}
]
},
"meta": {
"count": 1,
"data_as_of": "2026-07-29"
}
}
Your check history
Requires an API keyEvery check recorded against your API key, newest first.
Parameters
| Name | Type | Description |
|---|---|---|
limit |
integer | Rows per page. Default 50, maximum 200. |
Request
curl https://api.recallproven.com/v1/checks \ -H "Authorization: Bearer $KEY"
Retrieve one check receipt
Requires an API keyThe full receipt including the matches frozen as they stood at check time.
Parameters
| Name | Type | Description |
|---|---|---|
idrequired |
string | Check id from `POST /v1/checks`. |
Request
curl https://api.recallproven.com/v1/checks/RECALL_ID \ -H "Authorization: Bearer $KEY"
Metadata
Data sources, licences and attribution
No key requiredEvery upstream feed with its licence, the attribution string its licence requires, and its observed update cadence.
Request
curl https://api.recallproven.com/v1/sources \ -H "Authorization: Bearer $KEY"
Ingestion freshness
No key requiredPer-source last successful ingestion and upstream freshness stamp.
Request
curl https://api.recallproven.com/v1/health \ -H "Authorization: Bearer $KEY"
Response — real output from the live corpus
{
"status": "ok",
"sources": [
{
"id": "cpsc",
"cadence": "continuous",
"last_success_at": "2026-07-29T09:40:21.555Z",
"data_as_of": "2026-07-23",
"consecutive_failures": 0
},
{
"id": "eu-safety-gate",
"cadence": "weekly (published every Friday)",
"last_success_at": "2026-07-29T10:01:13.016Z",
"data_as_of": "2026-07-29",
"consecutive_failures": 0
}
],
"degraded": []
}
Need the archive instead?
The complete corpus is available as a one-time licensed export — a dated, checksummed set of JSON Lines files with every identifier, the full amendment history and all attribution obligations documented. Enquire.