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:

BlockContractWhat it means
vin_decodeAnchorAlways present; if the VIN cannot decode, there is no report at all
recallsBest-effortSearched by the decoded make and model year; degrades to a coverage.missing entry, never an error
critairConditionalPresent 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 missing array 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:

  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 — the decoded identity, the recall candidates, the Crit’Air verdict, and coverage for what is missing and why.
  4. Branch — clear the vehicle, flag campaigns to confirm with the manufacturer, or re-call with declared characteristics to fill the critair block.

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:

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.