GET /vehicle/co2
Resolves a European vehicle into its type-approval CO2 emissions and the technical characteristics published alongside them: WLTP grams per kilometre, fuel, engine capacity, power and mass in running order. The answer is served from a local store built from the official EU CO2 monitoring dataset (Regulation (EU) 2019/631, new registrations reported by member states), so a lookup resolves in milliseconds with no network call and no secret at request time.
Use it when an agent needs a grounded figure before pricing, importing or
comparing a vehicle — “what CO2 was this car type-approved at?”, “what does it
weigh?” — typically as the technical base of a
French registration tax costing, which is priced on
exactly these two figures. See the live /catalog for the
authoritative endpoint listing and price.
The differentiator is not the number, it is the precision the number was
matched at. Every response opens with a match_level that says whether the
figure belongs to one type-approval or to a whole model-year population — and at
model-year level it carries a p10/p50/p90 dispersion instead of pretending a
single figure fits every powertrain sold under that name. A European VIN does
not carry the type-approval variant, so a VIN can never buy the precise form:
that limit is stated, never worked around.
x402 golden rule: the agent pays for the answer to its question. A key the
dataset matches is a billed 200 — including a genuine 0 g/km for a battery
electric vehicle. Only requests the service cannot answer — no key, both key
forms at once, an incomplete approximate key, a year outside the ingested window,
a vehicle absent from the dataset — leave the 200 range and are not billed.
Parameters
Two mutually exclusive key forms, as query parameters. Mixing them is a
400, and the approximate form needs all three of its parts.
| Parameter | Type | Required | Description |
|---|---|---|---|
type_approval | string | precise form | EU type-approval number as published (e.g. e2*2007/46*0624*10) — the precise key |
variant | string | no (precise form) | Narrows the type-approval to one variant |
version | string | no (precise form) | Narrows the type-approval to one version |
make | string | approximate form | Make; short forms and member-state spellings are folded (VW reaches VOLKSWAGEN VW) |
model | string | approximate form | Commercial name as reported to the EU registry (Clio); case and accents folded |
year | int | approximate form | Registration year (YYYY) within the ingested window; outside it is a 404 naming the years served |
GET /vehicle/co2?make=Renault&model=Clio&year=2021
GET /vehicle/co2?type_approval=e2*2007/46*0624*10
make, model and year go together: two of the three is a 400 naming the
one that is missing. A year outside the window is a 404 that names the years
actually served rather than returning a silent miss.
200 response — UnifiedResponse
{
"data": {
"match_level": "model_year",
"vehicle": { "...": "..." },
"co2": { "...": "..." },
"coverage": { "...": "..." },
"limits": ["..."]
},
"provenance": {
"source": "eea-co2-monitoring",
"fetched_at": "2026-07-30T18:29:19Z",
"freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" }
}
}
Fields of data
| Field | Type | Description |
|---|---|---|
match_level | string | Read this first: the precision the figures were matched at (see below) |
vehicle | object | The matched vehicle: make, commercial_name, year, fuel, engine_capacity_cm3, engine_power_kw, mass_kg, plus manufacturer / type_approval / wheelbase_mm on the precise form |
co2 | object | The emission figures (see below) |
coverage | object | years_covered (the ingested window), years_observed for the matched key, versions_aggregated, min_sample |
limits | string[] | The four fixed reading limits carried by every answer |
A field the source does not carry is omitted, never served null — a Tesla
has no engine_capacity_cm3, and that absence is the fact.
match_level — the precision you bought
| Value | Meaning |
|---|---|
type_approval_exact | One type-approval, narrowed by variant/version — unique published values |
type_approval_partial | Versions of one type-approval, aggregated by registration-weighted median; variant and version are then omitted on purpose |
model_year | Several powertrains sold under one make/model/year — the only level that carries p10/p90 |
co2
| Field | Type | Description |
|---|---|---|
wltp | object | p50 always; p10 and p90 at model_year, where a single figure would be wrong at both ends |
nedc | int | Correlated NEDC value, only where the source publishes it (registrations before the WLTP switchover) — absent is not zero |
unit | string | g/km |
sample_size | int | Number of registrations behind the aggregate |
low_sample | bool | true when the aggregate sits below coverage.min_sample — kept but stated, never presented as a measurement |
0 is a real value, an absent block is not. A battery electric vehicle is
type-approved at 0 g/km and the response says so; a vehicle with no WLTP
measurement omits the wltp block entirely. Never read one as the other.
Example — an approximate key, aggregated over a model year
GET /vehicle/co2?make=Renault&model=Clio&year=2021 — one commercial name
covering many powertrains, so the answer is a model_year aggregate with its
dispersion:
{
"data": {
"match_level": "model_year",
"vehicle": {
"make": "RENAULT",
"commercial_name": "CLIO",
"year": 2021,
"fuel": "PETROL",
"engine_capacity_cm3": 999,
"engine_power_kw": 67,
"mass_kg": 1171
},
"co2": {
"wltp": { "p50": 118, "p10": 99, "p90": 120 },
"unit": "g/km",
"sample_size": 200122,
"low_sample": false
},
"coverage": {
"years_covered": [2018, 2019, 2020, 2021, 2022],
"versions_aggregated": 427,
"min_sample": 5
},
"limits": [
"type-approval values under the WLTP procedure, not real-world fuel consumption (OBFCM data is out of scope)",
"statistical aggregate of new registrations reported by member states, not a manufacturer datasheet",
"no VIN to variant/version link: a European VIN does not carry the variant outside manufacturer databases",
"regulated pollutants (NOx, particulates) are not covered"
]
},
"provenance": {
"source": "eea-co2-monitoring",
"fetched_at": "2026-07-30T18:29:19Z",
"freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" }
}
}
427 versions sit behind that median, and p10: 99 / p90: 120 say how far apart
they are. An agent that needs one exact figure must buy the precise form — not
round the median.
Example — the precise key
GET /vehicle/co2?type_approval=e2*2007/46*0624*10 matches one type-approval
whose versions are aggregated, so variant and version are omitted on
purpose and no dispersion is served:
{
"data": {
"match_level": "type_approval_partial",
"vehicle": {
"type_approval": { "number": "e2*2007/46*0624*10" },
"manufacturer": "PSA AUTOMOBILES SA",
"manufacturer_eu": "PSA",
"make": "CITROEN",
"commercial_name": "BERLINGO",
"fuel": "DIESEL",
"fuel_mode": "M",
"engine_capacity_cm3": 1499,
"engine_power_kw": 75,
"mass_kg": 1505,
"wheelbase_mm": 2785
},
"co2": {
"wltp": { "p50": 140 },
"unit": "g/km",
"sample_size": 23118,
"low_sample": false
},
"coverage": {
"years_covered": [2018, 2019, 2020, 2021, 2022],
"years_observed": { "from": 2021, "to": 2022 },
"versions_aggregated": 61,
"min_sample": 5
}
},
"provenance": {
"source": "eea-co2-monitoring",
"fetched_at": "2026-07-30T18:29:19Z",
"freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" }
}
}
years_observed reports the registration years actually seen for that key —
narrower than years_covered, and never confused with it.
Example — a battery electric, and a correlated NEDC value
GET /vehicle/co2?make=Tesla&model=Model 3&year=2021 returns a genuine zero,
served as a figure like any other:
"co2": {
"wltp": { "p50": 0, "p10": 0, "p90": 0 },
"nedc": 0,
"unit": "g/km",
"sample_size": 99158,
"low_sample": false
}
GET /vehicle/co2?make=VW&model=Golf&year=2019 shows the same block on a
pre-switchover year, where the source publishes both procedures — and the short
make folded to the registry spelling ("make": "VOLKSWAGEN VW"):
"co2": {
"wltp": { "p50": 138, "p10": 128, "p90": 169 },
"nedc": 113,
"unit": "g/km",
"sample_size": 535576,
"low_sample": false
}
The 41-gram gap between nedc and wltp is exactly why a model that quotes “the
CO2 of a 2019 Golf” from memory is unusable for a tax computation: the two
procedures do not answer the same question, and only the WLTP figure feeds the
French registration tax.
What this endpoint refuses to do
The four limits are returned with every answer, because they are the
reading instructions, not a disclaimer:
- type-approval values under the WLTP procedure, not real-world fuel consumption (OBFCM data is out of scope);
- a statistical aggregate of new registrations reported by member states, not a manufacturer datasheet;
- no VIN → variant/version link: a European VIN does not carry the variant
outside manufacturer databases, so a VIN-keyed answer is always
model_year; - no regulated pollutants (NOx, particulates).
Nor is this a market valuation, a price quote or a purchase recommendation.
Freshness
Answers are served from a snapshot of the EU monitoring dataset, dated by
freshness.as_of. The ingested window (coverage.years_covered) is the machine
truth of which registration years are served — a request outside it is a 404
that names them, never a silent miss and never a 5xx.
Errors
Only requests the service cannot answer leave the 200 range — none of them are billed.
| Status | code | Case |
|---|---|---|
| 400 | INVALID_INPUT | No key; type_approval combined with make/model/year; an incomplete approximate key |
| 404 | YEAR_OUT_OF_WINDOW | The requested year is outside the ingested window (the message names the window) |
| 404 | NOT_FOUND | No aggregate for that make/model/year, or no record for that type-approval |
| 500 | INTERNAL | Internal error (detail logged, not exposed) |
{ "error": "the approximate key needs all of 'make', 'model' and 'year' (missing: year)", "code": "INVALID_INPUT" }
{ "error": "year 2030 is outside the ingested window (covered years: 2018-2022)", "code": "YEAR_OUT_OF_WINDOW" }
{ "error": "no type-approval record for 'e2*2007/46*0624*10' (variant 'ZZZZ') in the ingested window", "code": "NOT_FOUND" }
Attribution
Emission and characteristic data are derived from the EU CO2 monitoring dataset published under Regulation (EU) 2019/631 (European Environment Agency / European Commission), reused under its open licence.
See also
GET /vehicle/tax— what registering that vehicle costs in France, priced on exactly these figures.GET /vehicle/report— one VIN, one settlement: decode, recalls, CO2, registration tax and Crit’Air in a single report.GET /vehicle/critair— Crit’Air class and low-emission-zone restrictions from declared characteristics.- For agents — discovery surfaces, the live
/catalogand how settlement works.