GET /vehicle/tax

Computes the French registration tax (carte grise) of a vehicle: the CO2 malus, the weight malus and the regional certificate tax, each priced against the schedule in force on the registration date you supply — not the one a model happens to remember. Every item shows its bracket, its threshold, the articles of the code des impositions sur les biens et services behind it and their LEGI identifiers, so the figure is auditable against the law rather than taken on trust.

The schedules are embedded locally: pure calculation at request time, no network call and no secret. The technical figures can be declared, or resolved from the EU CO2 dataset by passing a vehicle key — in which case each figure says whether it was declared or resolved. See the live /catalog for the authoritative endpoint listing and price.

Two properties carry the credibility of this endpoint. Coverage is France only: any other country is a 400, because approximating a neighbouring schedule would be worse than refusing. And the total disappears rather than being partial: if a required figure was neither declared nor resolved, that item is undetermined with a reason, the others stay computed, and total_eur is absent — a partial sum presented as a total is a wrong figure.

x402 golden rule: the agent pays for the answer to its question. A computable request is a billed 200, including one where an item is exempt (0 EUR, with the exempting article named), not_applicable (no schedule existed at that date) or undetermined (no amount, a reason instead). Only requests the service cannot answer — a country other than France, a date before the first published schedule, an unknown region, a missing fuel — leave the 200 range and are not billed.

Parameters

Query-string parameters. country=FR is always required. The technical figures (co2_wltp, weight_kg, fuel) are either declared or resolved from a vehicle key; the administrative figures (fiscal_power, region) are French records absent from the EU registry and are therefore always declarative.

ParameterTypeRequiredDescription
countrystringyesJurisdiction. FR is the only covered value; anything else is a 400 COUNTRY_NOT_COVERED
registration_datestringno (default today, UTC)YYYY-MM-DD — selects the schedule to the day (the CO2 schedule changed mid-year on 2025-03-01)
co2_wltpintdeclared or resolvedWLTP CO2 in g/km (0–1000) — base of the CO2 malus
weight_kgintdeclared or resolvedMass in running order, kg (100–20000) — base of the weight malus
fuelstringdeclared or resolvedelectric, hydrogen, gas (gpl/gnv), plug_in_hybrid, petrol, diesel, petrol_hybrid, diesel_hybrid — the vocabulary of /vehicle/critair, usual synonyms accepted
fiscal_powerintfor the regional taxFiscal power in CV (1–999) — base of the regional tax; always declarative
regionstringfor the regional taxFrench region by INSEE code (11) or exact name (case and accents folded); always declarative
type_approvalstringresolution keyResolves the technical figures from /vehicle/co2
make model yearresolution keyThe approximate key of /vehicle/co2, all three together
GET /vehicle/tax?country=FR&co2_wltp=150&weight_kg=1900&fuel=diesel&fiscal_power=7&region=11&registration_date=2026-05-01
GET /vehicle/tax?country=FR&make=Renault&model=Clio&year=2021&fiscal_power=5&region=52

A declared value always wins over a resolved one. A future registration_date is legitimate as long as an open schedule covers it; a date before the first published schedule is a 404 that names the bound (2020-01-01).

200 response — UnifiedResponse

{
  "data": {
    "country": "FR",
    "registration_date": "2026-05-01",
    "inputs_used": { "...": "..." },
    "co2_malus":    { "status": "due", "...": "..." },
    "weight_malus": { "status": "due", "...": "..." },
    "regional_tax": { "status": "due", "...": "..." },
    "total_eur": 10272.65,
    "schedule": { "...": "..." },
    "limits": ["..."]
  },
  "provenance": {
    "source": "fr-registration-tax",
    "fetched_at": "2026-07-30T18:29:54Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" }
  }
}

Fields of data

FieldTypeDescription
inputs_usedobjectEvery figure used, with its source (declared or resolved), so the result is reconstructable; a resolution entry appears when a vehicle key served, carrying the match_level of /vehicle/co2
co2_malusobjectCO2 malus, priced gram by gram against the dated schedule
weight_malusobjectWeight malus, at the marginal rate bracket by bracket on the mass after any allowance
regional_taxobjectFiscal power × the tariff voted by the region, plus the flat national fee
total_eurnumberSum of the three items — absent as soon as one is undetermined
scheduleobjectWhich schedule was applied: validity window per item, plus legal_basis[] (code, article, legi_id, in_force_since, subject)
limitsstring[]The six reading limits carried by every answer

status — read it before the amount

The three items share one closed enumeration:

ValueMeaning
dueComputed (including 0 EUR below the threshold — a real zero)
exemptAn automatic exemption applied, named by its article in exemption — never silent
not_applicableNo schedule existed at that date (the weight malus before 2022): an absence of tax, not a data gap
undeterminedA required figure was neither declared nor resolved: no amount, a reason instead — and total_eur disappears

The regional tax deserves a note of its own: its flat national fee stays due even when the region exempts the vehicle, so an exempt electric car still shows status: "exempt" with a non-zero amount_eur. That is the law, not a rounding artefact.

Example — a diesel registered in Île-de-France

GET /vehicle/tax?country=FR&co2_wltp=150&weight_kg=1900&fuel=diesel&fiscal_power=7&region=11&registration_date=2026-05-01

{
  "data": {
    "country": "FR",
    "registration_date": "2026-05-01",
    "inputs_used": {
      "co2_wltp_g_km": { "value": 150, "source": "declared" },
      "weight_kg": { "value": 1900, "source": "declared" },
      "fiscal_power_cv": { "value": 7, "source": "declared" },
      "fuel": { "value": "diesel", "source": "declared" },
      "region": {
        "value": { "insee_code": "11", "name": "Île-de-France", "eur_per_fiscal_hp": 68.95 },
        "source": "declared"
      }
    },
    "co2_malus": {
      "status": "due",
      "amount_eur": 4279,
      "co2_g_km": 150,
      "threshold_g": 108,
      "capped": false
    },
    "weight_malus": {
      "status": "due",
      "amount_eur": 5500,
      "mass_kg": 1900,
      "taxable_mass_kg": 1900,
      "threshold_kg": 1500,
      "brackets": [
        { "from_kg": 1500, "to_kg": 1699, "taxable_kg": 200, "eur_per_kg": 10, "amount_eur": 2000 },
        { "from_kg": 1700, "to_kg": 1799, "taxable_kg": 100, "eur_per_kg": 15, "amount_eur": 1500 },
        { "from_kg": 1800, "to_kg": 1899, "taxable_kg": 100, "eur_per_kg": 20, "amount_eur": 2000 }
      ]
    },
    "regional_tax": {
      "status": "due",
      "amount_eur": 493.65,
      "region": { "insee_code": "11", "name": "Île-de-France", "eur_per_fiscal_hp": 68.95 },
      "fiscal_power_cv": 7,
      "proportional_eur": 482.65,
      "fixed_fee_eur": 11
    },
    "total_eur": 10272.65,
    "schedule": {
      "as_of": "2026-07-28",
      "co2_malus": { "valid_from": "2026-01-01", "valid_to": "2026-12-31" },
      "weight_malus": { "valid_from": "2026-01-01", "valid_to": null },
      "regional_tax_as_of": "2026-07-28",
      "legal_basis": [
        {
          "code": "code des impositions sur les biens et services",
          "article": "L. 421-62",
          "legi_id": "LEGIARTI000051214838",
          "in_force_since": "2025-03-01",
          "subject": "barèmes CO2 WLTP"
        }
      ]
    }
  },
  "provenance": {
    "source": "fr-registration-tax",
    "fetched_at": "2026-07-30T18:29:54Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" }
  }
}

Every bracket of the weight malus is shown with its rate and its taxable kilograms: the 5 500 EUR is not asserted, it is derived in the open. legal_basis is elided here to one entry — the real answer carries the ten articles behind the three items, each with its LEGI identifier.

Example — exemptions are named, and the flat fee survives them

Same vehicle as an electric one (fuel=electric&co2_wltp=0): all three items are exempt, each citing its article — and the regional tax still bills the flat national fee.

{
  "co2_malus": {
    "status": "exempt",
    "amount_eur": 0,
    "co2_g_km": 0,
    "threshold_g": 108,
    "exemption": {
      "id": "electric_or_hydrogen",
      "article": "L. 421-67",
      "label": "vehicle powered exclusively by electricity, hydrogen or both"
    }
  },
  "weight_malus": {
    "status": "exempt",
    "amount_eur": 0,
    "mass_kg": 1900,
    "threshold_kg": 1500,
    "exemption": {
      "id": "low_carbon_footprint_electric_or_hydrogen",
      "article": "L. 421-79",
      "label": "low-carbon-footprint vehicle, and hydrogen or electric vehicle"
    }
  },
  "regional_tax": {
    "status": "exempt",
    "amount_eur": 11.0,
    "proportional_eur": 0.0,
    "fixed_fee_eur": 11,
    "exemption": {
      "id": "regional_clean_vehicle_exemption",
      "article": "L. 421-49",
      "label": "region has voted the exemption of electric and hydrogen vehicles"
    }
  },
  "total_eur": 11.0
}

A plug-in hybrid instead shows an allowance rather than an exemption — the mass deduction of article L. 421-79-1, with the kilograms it removed and the fact that it does not exempt:

"weight_malus": {
  "status": "due",
  "amount_eur": 5500,
  "mass_kg": 2100,
  "taxable_mass_kg": 1900,
  "threshold_kg": 1500,
  "allowance": {
    "id": "hybrid",
    "article": "L. 421-79-1",
    "label": "hybrid vehicles, by first registration date and drivetrain",
    "allowance_kg": 200,
    "exempts": false
  }
}

Example — an undetermined item removes the total

Same request without co2_wltp and without a resolution key. The CO2 malus cannot be computed, so it carries a reason instead of an amount; the other two items stay computed; and total_eur is absent from the JSON — a billed 200 that refuses to publish a wrong number:

{
  "data": {
    "country": "FR",
    "registration_date": "2026-05-01",
    "co2_malus": {
      "status": "undetermined",
      "threshold_g": 108,
      "reason": "'co2_wltp' is neither declared nor resolved: the CO2 malus cannot be computed"
    },
    "weight_malus": { "status": "due", "amount_eur": 5500, "...": "..." },
    "regional_tax": { "status": "due", "amount_eur": 493.65, "...": "..." }
  }
}

The same happens the other way round when weight_kg is missing ("'weight_kg' (mass in running order) is neither declared nor resolved: the mass tax cannot be computed"). And a vehicle registered before 2022 shows the weight malus as not_applicable — an absence of tax, dated and reasoned ("the mass tax applies to vehicles first registered from 2022 onwards"), with total_eur still served because nothing is unknown.

Example — figures resolved from the vehicle instead of declared

GET /vehicle/tax?country=FR&make=Renault&model=Clio&year=2021&fiscal_power=5&region=52 resolves CO2, mass and fuel from the EU dataset and says so, item by item:

"inputs_used": {
  "co2_wltp_g_km": { "value": 118, "source": "resolved" },
  "weight_kg": { "value": 1171, "source": "resolved" },
  "fuel": { "value": "petrol", "source": "resolved" },
  "fiscal_power_cv": { "value": 5, "source": "declared" },
  "resolution": {
    "match_level": "model_year",
    "source": "eea-co2-monitoring",
    "make": "RENAULT",
    "commercial_name": "CLIO",
    "year": 2021
  }
}

provenance.source then becomes fr-registration-tax+eea-co2-monitoring, and limits gains a line stating that the CO2 came from a model-year aggregate spanning N versions, so the malus of one specific version may differ. The precision limit of /vehicle/co2 is propagated, never hidden behind a clean-looking euro amount.

What this endpoint refuses to do

The six limits come back with every answer:

  • new vehicles registered in France: the reduction coefficient for vehicles already registered abroad (imported used cars) is not modelled;
  • WLTP schedules only: the NEDC and administrative-power schedules for vehicles outside WLTP are not modelled;
  • exemptions and allowances that depend on the taxpayer’s situation (disability card, dependent children, legal person operating a vehicle with at least eight seats) are published in the schedules but never applied automatically;
  • the superethanol E85 allowance (L. 421-68) is not applied: the fuel vocabulary shared with /vehicle/critair does not express it;
  • the regional tariff is voted yearly and applies at the date the certificate is issued, not at first registration — only current tariffs are published, so no history is embedded;
  • out of scope: annual taxes on business use of vehicles, transport-vehicle taxes, purchase incentives (bonus) and the non-tax delivery fee.

This is a costing of the published schedules, not tax advice and not a quote from the administration.

Freshness

The schedules and regional tariffs are served from a local snapshot, dated by freshness.as_of and by schedule.as_of / schedule.regional_tax_as_of. A missed refresh keeps serving the last good snapshot, honestly dated, and never becomes a 5xx.

Errors

Only requests the service cannot answer leave the 200 range — none of them are billed.

StatuscodeCase
400COUNTRY_NOT_COVEREDcountry is not FR — a neighbouring schedule is never approximated
400INVALID_INPUTMissing fuel without a resolution key; unknown region; a figure outside its bounds
404DATE_OUT_OF_RANGEregistration_date predates the first published schedule (the message names it)
404NOT_FOUNDA resolution key that the EU CO2 dataset does not match; unknown route
500INTERNALInternal error (detail logged, not exposed)
{ "error": "country 'DE' is not covered; only France (country=FR) has an embedded registration tax schedule", "code": "COUNTRY_NOT_COVERED" }
{ "error": "no published registration tax schedule for '2019-01-01'; France is covered from 2020-01-01 onwards", "code": "DATE_OUT_OF_RANGE" }
{ "error": "unknown region 'Atlantide'; supply an INSEE region code (for instance '11' for Île-de-France) or the exact region name", "code": "INVALID_INPUT" }

Attribution

The schedules are those of the code des impositions sur les biens et services, published by Légifrance (DILA) under the Licence Ouverte / Etalab — each applied article is returned with its LEGI identifier. Regional tariffs are the ones voted by the regional councils. Technical figures resolved from a vehicle key come from the EU CO2 monitoring dataset (Regulation (EU) 2019/631).

See also

  • GET /vehicle/co2 — the type-approval CO2 and mass this costing is priced on.
  • GET /vehicle/report — one VIN, one settlement: decode, recalls, CO2, registration tax and Crit’Air.
  • GET /vehicle/critair — the Crit’Air class, which shares this endpoint’s fuel vocabulary.
  • For agents — discovery surfaces, the live /catalog and how settlement works.