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

TierPriceRequests / monthIdentifiers / monthBurst
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"
}
typeMeaning
/problems/unauthorizedunauthorized
/problems/forbiddenforbidden
/problems/quota-exceededquota exceeded
/problems/rate-limitedrate limited
/problems/not-foundnot found
/problems/invalid-parameterinvalid parameter
/problems/invalid-cursorinvalid cursor
/problems/internalinternal

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 key
GET /v1/recalls

Recalls newest first.

Parameters

NameTypeDescription
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 key
GET /v1/recalls/{id}

Returns a single recall including every extracted product identifier.

Parameters

NameTypeDescription
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 key
GET /v1/recalls/{id}/revisions

Every observed change to this record, oldest first, with the field-level delta and the date we observed it.

Parameters

NameTypeDescription
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 key
GET /v1/identifiers/{kind}/{value}

The catalogue-check endpoint.

Parameters

NameTypeDescription
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 key
POST /v1/checks

Submits 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 key
GET /v1/checks

Every check recorded against your API key, newest first.

Parameters

NameTypeDescription
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 key
GET /v1/checks/{id}

The full receipt including the matches frozen as they stood at check time.

Parameters

NameTypeDescription
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 required
GET /v1/sources

Every 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 required
GET /v1/health

Per-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.