Can this car enter a French ZFE? Its Crit'Air class, computed offline

Crit'Air class and in-force ZFE restrictions, computed offline from declared fuel plus Euro norm or first-registration date. No account, pay per call.

By Matthias Begot · · Updated

Whether a car may enter a French low-emission zone (ZFE) comes down to its Crit’Air class — a deterministic function of vehicle category, fuel and Euro emission standard, fixed by French regulation. That means an agent does not need a registry lookup to answer it: one offline call, GET /vehicle/critair, computes the class from declared characteristics and returns the ZFE restrictions currently in force for that class. Pure calculation, no store, no network, no account — one x402 settlement per answer.

The problem: access rules an agent cannot guess

A purchase-assistant agent comparing used cars, a trip planner routing through Lyon, a fleet-compliance agent auditing vans: all of them hit the same question — is this vehicle allowed where it needs to go? The answer is regulatory, not observational. France classifies vehicles into Crit’Air classes under the Arrêté du 21 juin 2016 (art. R. 318-2 of the code de la route), and each ZFE restricts entry by class.

The rules are also moving. The 2025 simplification law voted to abolish the ZFE mandate; in May 2026 the Conseil constitutionnel struck that repeal down on procedural grounds, leaving the zones in force. An agent that hardcodes last year’s understanding of ZFE schedules gets this wrong; an endpoint that models only restrictions actually in force, from a dated snapshot, does not.

A calculation, not a lookup

GET /vehicle/critair takes declared inputs — values the agent typically already holds from a registration document, a listing, or a VIN decode:

  • fuel — always required (electric, hydrogen, petrol, diesel, petrol_hybrid, diesel_hybrid; a hybrid is classified by its combustion engine).
  • At least one of euro_norm (pre_euro, euro2..euro6) or first_registration (YYYY-MM-DD, used to derive the norm). When both are given, the explicit euro_norm wins.
GET /vehicle/critair?fuel=diesel&first_registration=2009-05-01

The response gives the computed critair_class ("0", "1".."5" or "non_classe"), the list of modelled zones that restrict that class — each with a stable zone_id, its perimeter description and the date the restriction took effect — and a derivation block reporting which input path produced the effective Euro norm. The calculation is auditable: the agent can always see whether the class came from the declared norm or was derived from the registration date, and regulation.reference names the grid it was computed against.

Because the core is a pure function over embedded reference tables, there is no store to miss and no staleness error to hit: the answer always computes, in milliseconds.

Reading the result honestly

The endpoint sells a regulatory verdict, and it is precise about what that verdict covers:

  • non_classe is a successful answer. A vehicle too old to qualify for any sticker is exactly the fact a purchase or compliance agent is paying to learn — a 200, billed, per the x402 golden rule.
  • An empty zfe_restrictions list is a successful answer too. A clean sticker that no modelled zone restricts is the verdict, not a miss.
  • Input is declared, not verified. The class is exact for the characteristics given; the service does not check that the vehicle really has them. Garbage in, wrong class out — which is why feeding it from a VIN decode or a registration document beats trusting a listing’s prose.
  • Only permanent, in-force restrictions are modelled. Local, time-based and sector exemptions (protected axes, low-mileage permits, day passes) are explicitly out of scope, and the response says so in notes. Tightening schedules revised by the 2025 law are only included once actually in force.
  • Scope is M1/N1 only (passenger cars and light vans) in v1, and there is no lookup by licence plate. The ZFE perimeters come from a dated snapshot; provenance.freshness.as_of carries the oldest of the two embedded references, never a fresher-looking date.

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. Readcritair_class, the derivation audit trail, and the zones restricting that class.
  4. Branch — clear the vehicle for its route, flag it in a purchase comparison, or mark the fleet unit for replacement.

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.

Chain it: decode, then classify

The Crit’Air call slots naturally after a VIN decode: model year from GET /vehicle/vin/decode helps pin the first-registration era, and the decoded facts keep the declared inputs honest. For recall exposure on the same vehicle, add GET /vehicle/recalls; for all three answers in a single settlement, use the composite GET /vehicle/report.

Used for what it is — an offline, auditable regulatory calculation with an honestly-bounded ZFE model — /vehicle/critair lets an agent answer “can this car go there?” before anyone buys, routes or dispatches it. For the full field reference and error codes, see the GET /vehicle/critair documentation; for how agents discover and call Invoket endpoints, see For agents.