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.
By Matthias Begot · · Updated
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, 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; France’s DGCCRF publishes RappelConso on data.gouv.fr 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 accepts one of two
mutually exclusive forms:
-
By make —
make, optionally narrowed bymodelandyear: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), the search runs on that resolution, and the resolution is echoed back indata.vinso the agent sees exactly what was searched: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.sourceslists each expected source with its dated snapshot. The EU Safety Gate is on the roadmap but not yet ingested: it appears asmissing: truewith a reason, which alone forcescoverage.complete: false. The response never pretends to a coverage it does not have. - Freshness is the oldest source served.
provenance.freshness.as_ofdeliberately 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:
- Discover the endpoint via the live catalog and call it; receive the
402challenge. - Pay — sign the chosen rail and replay the request.
- Read — iterate
recalls[], keeping thematchblock andsourcenext to each campaign. - 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 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; see the
endpoint reference for the current figure.
Decode, then recalls, then the full report
For a single listing, the natural sequence starts with
GET /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 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; for how
agents discover and call Invoket endpoints, see
For agents.