A full vehicle report for one VIN: decode, recalls, Crit'Air
One paid call returns the VIN decode, the candidate recall campaigns and a Crit'Air class — each block with its own provenance, and an explicit coverage map.
By Matthias Begot · · Updated
An agent vetting a vehicle end-to-end asks three questions: what is this VIN,
really? — which recall campaigns may concern it? — where is it allowed to
drive? Each has its own Invoket endpoint. When the agent wants all three for
the same vehicle, GET /vehicle/report composes
them into one response for one x402 settlement: the VIN decode as the
anchor, candidate recalls and a Crit’Air class as secondary blocks, each
carrying its own provenance, plus an explicit coverage map of anything
that could not be produced. Three answers, one payment loop.
Why a composite endpoint exists
For a machine buyer, every paid call is a full loop — receive the 402
challenge, sign, replay, verify. That per-call overhead is fine when the agent
has one question; it is pure friction when the questions always travel
together, as they do when vetting a single used-car listing or auditing one
fleet unit.
The report removes that friction without inventing anything new. It is not a new dataset: internally it orchestrates the same three cores documented on their own pages — VIN decode, recalls and Crit’Air — over local stores and pure calculation, with no network call and no secret at runtime. What the single settlement buys is the composition: one grounded answer per VIN, with a per-block provenance and a coverage map instead of three separate envelopes.
The call: a VIN anchor, optional declared characteristics
The vin is required — it is the anchor of the report, and there is no
lookup by licence plate. The Crit’Air characteristics are optional and
follow the same declarative contract as the standalone endpoint: supply at
least fuel (plus euro_norm or first_registration) to obtain the
critair block.
GET /vehicle/report?vin=1HGCM82633A004352&fuel=petrol&euro_norm=euro6
The three blocks have three different contracts:
| Block | Contract | What it means |
|---|---|---|
vin_decode | Anchor | Always present; if the VIN cannot decode, there is no report at all |
recalls | Best-effort | Searched by the decoded make and model year; degrades to a coverage.missing entry, never an error |
critair | Conditional | Present only when usable characteristics were declared |
Each block has exactly the shape of its standalone endpoint, provenance
included — nhtsa-vpic for the decode, the recall sources for recalls, the
regulatory grid and ZFE reference for critair. The root provenance mirrors
the anchor; the per-block provenances are what stand for each block. An agent
that already parses the standalone responses parses the report for free.
A partial report is a successful, billed answer
The report’s honesty lives in coverage. As soon as the anchor decodes, the
call is a 200 and is billed — even when a secondary block is absent.
Every absent block is listed in coverage.missing as { block, reason }:
"declared characteristics not provided" for a skipped Crit’Air, a make
absent from every recall source, a store that was unavailable. The map is
never a silent error, and a block is never invented to look complete.
Three consequences worth designing around:
- Only the anchor can fail the call. A missing or malformed VIN, or a well-formed VIN whose manufacturer is absent from the vPIC tables, leaves the 200 range and is not billed — without a decode there is no report.
- Secondary blocks never produce a 5xx. Store trouble degrades the block
into
coverage.missing; the report still ships with what it has. - An empty recall list is a present block. “No known recall in the covered
sources” is data, not a miss — the
missingarray is reserved for blocks that could not be produced at all.
Every scope limit of the underlying cores still holds: recalls are candidate campaigns matched on make and year, never a per-VIN verdict; the Crit’Air class is computed from declared, not verified characteristics; sources and freshness are dated per block.
Where it sits in the x402 loop
One report is one standard loop — 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 — the decoded identity, the recall candidates, the Crit’Air
verdict, and
coveragefor what is missing and why. - Branch — clear the vehicle, flag campaigns to confirm with the
manufacturer, or re-call with declared characteristics to fill the
critairblock.
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.
Report or standalone calls?
The rule of thumb is the number of questions:
- One question, one core. Just grounding a listing’s claims? Call
/vehicle/vin/decode. Only recall exposure?/vehicle/recalls. Only zone access, with characteristics in hand?/vehicle/critair. - The whole picture for one vehicle — a purchase decision, a fleet
intake — call
/vehicle/reportonce and read the coverage map.
Used for what it is — a composition of three honestly-scoped cores under a
single settlement — /vehicle/report turns vetting a vehicle from three
payment loops into one. For the full block shapes, coverage semantics and
error codes, see the
GET /vehicle/report documentation; for how
agents discover and call Invoket endpoints, see
For agents.