# Which recalls may apply to this vehicle? NHTSA and RappelConso > Open recall data keys on make, model and year — never on one VIN. One offline call returns candidate campaigns from NHTSA and RappelConso, pay per call. Published 2026-07-11 · Updated 2026-08-16 · HTML version: https://invoket.com/blog/which-recall-campaigns-may-apply-to-this-vehicle --- An agent doing due diligence on a vehicle — vetting a used-car listing, auditing a fleet — needs to know which **recall campaigns could concern it**. That data is public, but it is scattered across national registers with different keys and formats. One offline call, [`GET /vehicle/recalls`](/docs/api/vehicle-recalls), consolidates the US **NHTSA** recall dataset and France's **RappelConso**, looked up by make/model/year or directly by VIN, and returns *candidate* campaigns — each with a `match` block stating why it was retained. No account, no API key, one x402 settlement per answer. ## The problem: public data, fragmented surfaces Vehicle recalls are open data by design — regulators want them found. NHTSA publishes its defect and recall records as [public-domain datasets](https://www.nhtsa.gov/nhtsa-datasets-and-apis); France's DGCCRF publishes [RappelConso on data.gouv.fr](https://www.data.gouv.fr/datasets/rappelconso-v2-rappels-de-produits) under the Licence Ouverte. But for an agent, "open" is not the same as "callable": each register has its own schema, its own keys, its own refresh cadence, and none of them will onboard an autonomous agent onto a B2B account. There is also a subtlety that trips up naive integrations: **open recall data is keyed on make, model and year range — not on the individual VIN**. A campaign says "Accords built 2001–2007", not "this chassis is affected". Any service that returns a per-VIN recall *verdict* from these sources is overselling them. The honest shape of the answer is a list of candidates. ## The call: one question, two forms [`GET /vehicle/recalls`](/docs/api/vehicle-recalls) accepts **one** of two mutually exclusive forms: - **By make** — `make`, optionally narrowed by `model` and `year`: ```http GET /vehicle/recalls?make=Honda&model=Accord&year=2003 ``` - **By VIN** — the VIN is decoded to a make and model year (the same decode as [`/vehicle/vin/decode`](/docs/api/vehicle-vin-decode)), the search runs on that resolution, and the resolution is echoed back in `data.vin` so the agent sees exactly what was searched: ```http GET /vehicle/recalls?vin=1HGCM82633A004352 ``` The response lists campaigns sorted by publication date, each carrying its originating `source` (`NHTSA`, `RappelConso`), the campaign identifier, the defect `summary`, the `remedy` when the source states one, a link back to the source record — and a `match` block (`make`, optional `model`, optional year range) that states **why the campaign was retained**. The agent never has to guess how a result relates to its query. The lookup is served from a local store built from these open datasets; the runtime makes **no network call and holds no secret**, which is why it answers in milliseconds and is cheap enough to run per listing or per fleet unit. ## Candidates, not a verdict The scope is stated in the response itself, and it is worth internalizing: - **Every result is a candidate to confirm with the manufacturer.** Matching is by make/model/year range because that is how the public sources are keyed. The endpoint answers "which campaigns *may apply*?" — never "this specific VIN is recalled". - **An empty list is a successful answer.** "No known recall for this vehicle in the covered sources" is exactly the data being sold — a **200**, billed, per the x402 golden rule. The 4xx range is reserved for requests the service cannot run at all: no search key, both forms at once, a malformed VIN or year, an unknown VIN manufacturer, or a make absent from every covered source — none of which are billed. - **Coverage is announced, never implied.** `coverage.sources` lists each expected source with its dated snapshot. The EU **Safety Gate** is on the roadmap but **not yet ingested**: it appears as `missing: true` with a reason, which alone forces `coverage.complete: false`. The response never pretends to a coverage it does not have. - **Freshness is the oldest source served.** `provenance.freshness.as_of` deliberately carries the stalest snapshot date among the served sources — the service never presents itself as fresher than its weakest input. ## Where it sits in the x402 loop The call follows the same loop as every Invoket endpoint — no signup precedes it: 1. **Discover** the endpoint via the live catalog and call it; receive the `402` challenge. 2. **Pay** — sign the chosen rail and replay the request. 3. **Read** — iterate `recalls[]`, keeping the `match` block and `source` next to each campaign. 4. **Branch** — an empty list clears the vehicle in the covered sources; a non-empty list becomes a checklist of campaigns to confirm with the manufacturer before purchase or dispatch. The [Quickstart](/docs/quickstart) walks the full discover → `402` → pay → replay cycle with runnable snippets. Price and accepted rails are not pinned here — they are served live by the [catalog](https://api.invoket.com/catalog); see the [endpoint reference](/docs/api/vehicle-recalls) for the current figure. ## Decode, then recalls, then the full report For a single listing, the natural sequence starts with [`GET /vehicle/vin/decode`](/docs/api/vehicle-vin-decode) — grounding the make and model year in the VIN itself — and follows with the recall lookup on that resolution. When the agent wants the whole picture in one settlement, [`GET /vehicle/report`](/docs/api/vehicle-report) bundles the decode, the candidate recalls and the Crit'Air classification into a single composite response. Used for what it is — a consolidated, honestly-scoped view of open recall data — `/vehicle/recalls` turns a scattered set of national registers into one question an agent can pay to ask. For the full field reference, `coverage` semantics and error codes, see the [`GET /vehicle/recalls` documentation](/docs/api/vehicle-recalls); for how agents discover and call Invoket endpoints, see [For agents](/docs/for-agents).