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": "9aece4d6115ea7273c80a6027a5025c2",
"source": {
"id": "nhtsa",
"record_id": "26V329000",
"agency": "NHTSA",
"jurisdiction": "US"
},
"title": "CADILLAC ESCALADE ESV — AIR BAGS:FRONTAL:DRIVER SIDE:INFLATOR MODULE",
"summary": "General Motors, LLC (GM) is recalling certain 2015 Cadillac Escalade, Escalade ESV, XTS, 2015-2016 Cadillac ATS, CTS, and SRX vehicles. The front-driver air bag inflator may rupture during deployment.",
"hazard": {
"category": "other",
"text": "An inflator rupture may result in sharp metal fragments striking the driver or other occupants, resulting in serious injury or death."
},
"product": {
"category": "motor_vehicle",
"brands": [
"General Motors, LLC"
],
"models": [
"CADILLAC ESCALADE ESV 2015",
"CADILLAC SRX 2015",
"CADILLAC ATS 2016",
"CADILLAC CTS 2015",
"CADILLAC CTS 2016",
"CADILLAC SRX 2016",
"CADILLAC XTS 2015",
"CADILLAC ESCALADE 2015",
"CADILLAC ATS 2015"
]
},
"severity": "unknown",
"source_classification": "AIR BAGS:FRONTAL:DRIVER SIDE:INFLATOR MODULE",
"remedy": "replace",
"recall_date": "2027-08-16",
"published_date": "2026-05-21",
"countries": [
"United States"
],
"url": "https://www.nhtsa.gov/recalls?nhtsaId=26V329000",
"revision": 20,
"data_as_of": "2026-09-13",
"first_seen_at": "2026-08-16T09:30:47.092Z",
"last_seen_at": "2026-09-13T09:31:08.446Z"
}
],
"meta": {
"count": 1,
"limit": 1,
"next_cursor": "eyJkIjoiMjAyNi0wNy0yNCIsImkiOiJhYmMifQ",
"data_as_of": "2026-09-13",
"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-09-13T11:23:47.403Z",
"submitted_count": 2,
"submitted_digest": "644639bfbbd085d8484122214dfc92e16f0c6d6cceabefbd362c27f22c427f0b",
"rejected_count": 0,
"rejected": [],
"match_count": 1,
"result_digest": "fd4a973133a9bd937127cad0cdd2e6d63cca678060f917a22c2a461f654b1d6e",
"corpus_as_of": "2026-09-13",
"corpus_size": 176037,
"matches": [
{
"recall_id": "9aece4d6115ea7273c80a6027a5025c2",
"matched_on": {
"kind": "gtin",
"normalized": "00012345678905"
},
"revision": 20,
"title": "CADILLAC ESCALADE ESV — AIR BAGS:FRONTAL:DRIVER SIDE:INFLATOR MODULE",
"jurisdiction": "US",
"recall_date": "2027-08-16",
"severity": "unknown",
"url": "https://www.nhtsa.gov/recalls?nhtsaId=26V329000"
}
]
},
"meta": {
"count": 1,
"data_as_of": "2026-09-13"
}
}
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-09-13T09:40:58.246Z",
"data_as_of": "2026-09-10",
"consecutive_failures": 0
},
{
"id": "eu-safety-gate",
"cadence": "weekly (published every Friday)",
"last_success_at": "2026-09-13T10:01:02.471Z",
"data_as_of": "2026-09-13",
"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.