VIN Fuel Type API

By Vehicle API
VIN Fuel Type API

You need a dependable way to tell if a VIN represents a gasoline, diesel, flex-fuel, or electrified vehicle, and you want consistent fields you can drop into eligibility checks, pricing models, emissions logic, or fueling workflows. By the end of this guide you will decode any 17-character VIN with Vehicle API and read the fuel_type and engine.fuel fields—plus handle nulls, caching, coverage limits, and errors—so you can ship a VIN Fuel Type feature with confidence.

What the VIN Fuel Type field returns

The VIN decode endpoint returns a fuel type in two places you will use together:

Illustration: VIN Fuel Type API
  • fuel_type (top-level string): the normalized fuel category for the decoded VIN (for example, “Gasoline”).
  • engine.fuel (nested string): the fuel attribute reported with the engine details, as published by NHTSA vPIC (for example, “Gasoline”).

If a value is not published by NHTSA for a given VIN, the field will be null. Electrification-specific fields (electrification_level, ev_drive_unit, battery_kwh, charger_level, charger_power_kw) will be present for the same endpoint and will be null for non-EVs. You should not assume EV data exists unless these are non-null.

Endpoint and authentication

VIN Fuel Type is available via the VIN decode endpoint:

  • Method and URL: POST https://vehicles-api.com/api/v1/vin/decode
  • Authentication: send your key in X-API-Key: YOUR_API_KEY. An Authorization: Bearer YOUR_API_KEY header is also accepted.
  • Body: JSON with vin (a 17-character string)

Decoding works for any 17-character VIN worldwide and is fullest for US-market vehicles. Nulls can occur when the source (NHTSA vPIC) does not publish a field for that VIN. The response is always wrapped in an envelope with status, source, and data. Errors use the same envelope with an error object.

You can explore the full reference in the Documentation and learn about machine-friendly access via the MCP server for AI agents.

cURL: decode a VIN and read fuel fields

Copy and run this to decode the control VIN. It is a gasoline car, so electrification fields are null.

curl -X POST "https://vehicles-api.com/api/v1/vin/decode" -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"vin":"1HGCM82633A004352"}'

Official response JSON

This is the official example response. Do not expect EV attributes for this VIN.

{
"status": "success",
"source": "nhtsa",
"data": {
"vin": "1HGCM82633A004352",
"valid": true,
"year": 2003,
"make": "HONDA",
"model": "Accord",
"trim": "EX-V6",
"body": "Coupe",
"doors": 2,
"vehicle_type": "PASSENGER CAR",
"engine": {
"cylinders": 6,
"displacement_l": 3,
"configuration": "V-Shaped",
"model": "J30A4",
"hp": 240,
"fuel": "Gasoline"
},
"fuel_type": "Gasoline",
"electrification_level": null,
"ev_drive_unit": null,
"battery_kwh": null,
"charger_level": null,
"charger_power_kw": null,
"drive": null,
"transmission": {
"style": "Automatic",
"speeds": 5
},
"plant": {
"country": "UNITED STATES (USA)",
"city": "MARYSVILLE",
"state": "OHIO"
},
"manufacturer": "AMERICAN HONDA MOTOR CO., INC."
}
}

Fields you will use

  • status: “success” or “error”. Check this before reading data.
  • source: “nhtsa” indicates the decode came from NHTSA vPIC.
  • data.vin: echo of the requested VIN (useful for caching keys).
  • data.valid: boolean indicating VIN structure validity.
  • data.fuel_type: normalized top-level fuel type string (Gasoline, Diesel, etc.).
  • data.engine.fuel: engine-level fuel descriptor from NHTSA (should generally align with fuel_type).
  • data.electrification_level and related EV fields: null for non-EVs; non-null for EVs/plug-in hybrids when available.

Python example: fetch and normalize fuel type

This sample posts a VIN, reads fuel_type and engine.fuel, and applies minimal normalization and null handling. It uses the same endpoint and VIN as the cURL example above and respects the response envelope.

import json
import os
import requests

API_URL = "https://vehicles-api.com/api/v1/vin/decode"
API_KEY = os.getenv("VEHICLES_API_KEY", "YOUR_API_KEY")

def decode_vin_fuel(vin: str) -> dict:
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
}
resp = requests.post(API_URL, headers=headers, json={"vin": vin}, timeout=10)
# Raise for transport errors; the API still includes a JSON envelope on 4xx/5xx with error.code/message
resp.raise_for_status()
payload = resp.json()

if payload.get("status") != "success":
err = payload.get("error", {})
raise RuntimeError(f"VIN decode failed: {err.get('code')} {err.get('message')}")

data = payload.get("data", {}) or {}
# Primary fields for fuel logic
top_level_fuel = data.get("fuel_type")
engine = data.get("engine") or {}
engine_fuel = engine.get("fuel")

# Prefer top-level fuel_type; fall back to engine.fuel if needed
fuel = top_level_fuel or engine_fuel

# Basic normalization example (do not over-normalize; preserve source when unsure)
norm = (fuel or "").strip().lower()
if norm in {"gasoline", "gas", "petrol"}:
fuel_normalized = "Gasoline"
elif norm in {"diesel"}:
fuel_normalized = "Diesel"
elif norm in {"flex-fuel", "e85"}:
fuel_normalized = "Flex-Fuel"
elif norm in {"cng"}:
fuel_normalized = "CNG"
elif norm in {"lpg"}:
fuel_normalized = "LPG"
elif norm in {"electric"}:
fuel_normalized = "Electric"
else:
fuel_normalized = fuel or None # keep original or None

return {
"vin": data.get("vin"),
"valid": data.get("valid"),
"fuel_type": top_level_fuel,
"engine_fuel": engine_fuel,
"fuel_normalized": fuel_normalized,
"electrification_level": data.get("electrification_level"),
"battery_kwh": data.get("battery_kwh"),
"charger_level": data.get("charger_level"),
"charger_power_kw": data.get("charger_power_kw"),
"source": payload.get("source"),
}

if __name__ == "__main__":
result = decode_vin_fuel("1HGCM82633A004352")
print(json.dumps(result, indent=2))

Choosing between fuel_type and engine.fuel

Both fields may be present and typically align. Use the top-level fuel_type as your primary decision field and keep engine.fuel for auditing, display, or fallback. For example, if you run a policy engine that must decide “Gasoline vs. Diesel vs. Electric,” use fuel_type. If you build an inspector-facing UI, show both so users can see the source-level detail.

Field Location Purpose Null behavior
fuel_type data.fuel_type Primary normalized fuel category used for rules and gating. May be null if not published. Fallback to engine.fuel.
engine.fuel data.engine.fuel Engine-level fuel from NHTSA vPIC; display, auditing, fallback. May be null if not published.
electrification_level data.electrification_level Identifies EV/PHEV/HEV when available. Null for non-EVs and when data is not published.
battery_kwh, charger_level, charger_power_kw data.* EV charging attributes when available. Null unless the VIN is an EV/PHEV and values are published.

Response envelope, errors, and nulls

Every response is an envelope:

  • On success: status = “success”, source identifies the data origin (here: “nhtsa”), and data contains the decoded fields.
  • On error: status = “error”, an error object is returned with error.code and error.message. Handle both transport errors (non-2xx HTTP) and logical errors (status=error).

Nulls are expected when the source does not publish a field for a given VIN. Do not coerce nulls into default values that would mislead business logic; prefer explicit checks, and use fallbacks only when they don’t risk false positives (e.g., prefer fuel_type, then fallback to engine.fuel).

Recommended error handling flow:

  • Check HTTP status. If non-2xx, read the JSON body for error.code and error.message.
  • If 2xx, parse JSON and check status. If status=error, log error.code/message for triage.
  • If status=success with data.valid=false, treat as an invalid VIN input and prompt the user to correct it.

Caching decoded VINs

VINs are immutable identifiers. Cache decoded results by data.vin to cut latency and reduce billable calls. A typical approach is to cache the entire envelope for 30–90 days and refresh opportunistically. If your logic cares only about a subset (fuel_type and engine.fuel), you can store a compact record keyed by VIN with a last_checked_at timestamp to monitor refresh cadence.

Because the underlying source can be updated by publishers, you should design for cache invalidation by age or explicit re-checks. For fuel fields, changes are rare for already manufactured vehicles, but design your cache strategy so you can force-refresh when you detect discrepancies.

Using fuel type in your product

Here are common patterns that directly use fuel_type and engine.fuel:

  • Eligibility checks: disallow Diesel for emissions-restricted zones; allow Electric-only discounts; require Flex-Fuel detection before E85 pricing.
  • Fuel routing: show gasoline stations for Gasoline vehicles; show charging locations only when electrification_level is non-null and battery_kwh is available.
  • Insurance rating: apply surcharges or discounts based on Diesel vs. Gasoline; handle EV-specific coverages when EV fields exist.
  • Marketplace UX: badge search results with a concise fuel tag from fuel_type; reveal engine.fuel in details for transparency.

Normalization strategy tips:

  • Prefer the exact strings returned unless your product demands coalescing (e.g., “Gasoline” vs. “Petrol”).
  • Keep both the canonical fuel_type and raw engine.fuel for auditing and support.
  • Never infer EV battery or charging values; use the provided EV fields when non-null.

Coverage and data sources

VIN decoding is global and works for any 17-character VIN. Coverage depth is fullest for US-market vehicles. Fuel fields depend on what NHTSA vPIC publishes; when a field isn’t available, expect null.

Safety datasets (recall campaigns, owner complaints, NCAP crash ratings) are US-market only and matched by make + model + year. They are available via other endpoints and are not part of VIN Fuel Type. Use them to enrich vehicle context, not to determine fuel categorization.

Dutch plate lookups come from RDW open data and never include a VIN. VIN Fuel Type is derived from VIN decoding only and is not determined from plates. This service is not a vehicle history report; it does not include title, accident, or ownership history.

For architecture and schema specifics, see the Documentation.

Performance, rate limits, and monthly quota

Vehicle API enforces rate limits and a monthly quota per plan. Exact numbers depend on your subscription level and are shown in your dashboard and the docs. Avoid hard-coding assumptions—read limit headers if present and design exponential backoff on 429 responses.

Implementation practices that help:

  • Cache VIN decodes to reduce duplicate requests and avoid rate spikes.
  • Burst-control: queue VIN decodes in batches with client-side throttling.
  • Retry policy: only retry idempotent VIN decodes; back off on 429 or 5xx and stop on 4xx validation errors.
  • Observability: log status, source, and error.code/message for support and triage.

All plans include a 7-day free trial and the Starter plan begins at $19/mo. You can start building now and scale your usage when ready.

MCP server for AI agents

If you are building an AI agent or tool that needs to fetch fuel type on the fly, you can connect via the Model Context Protocol server at MCP. The underlying data is the same; the MCP integration layer helps tools request VIN decodes and retrieve fuel fields alongside other attributes such as year, make, model, and powertrain details.

Practical field behaviors and guardrails

  • VIN validation: data.valid tells you if the VIN structure passes checks. If false, prompt for correction before proceeding.
  • EV detection: rely on both fuel_type and electrification_level. Some hybrids may present nuanced values; do not assume EV unless EV fields are non-null.
  • Units: engine.displacement_l is in liters, engine.hp is horsepower, charger_power_kw (when present) is kilowatts.
  • Localization: strings such as “Gasoline” are in English. If you need locale-specific labels, map them in your client.

API request checklist

  • Use POST https://vehicles-api.com/api/v1/vin/decode with JSON body: { "vin": "…" }.
  • Send X-API-Key: YOUR_API_KEY. Authorization: Bearer YOUR_API_KEY also works.
  • Check status before reading data and handle error.code and error.message on failures.
  • Read fuel_type first, then engine.fuel as fallback; treat nulls explicitly.
  • Cache by VIN to avoid redundant calls and spikes.

FAQ

Does VIN Fuel Type work outside the US?
Yes. VIN decoding works worldwide for any 17-character VIN. Coverage depth is fullest for US-market vehicles. When the source does not publish a field, you will receive nulls.

What should I do if fuel_type is null?
Fallback to engine.fuel. If both are null, do not guess—surface an “Unknown fuel” state or ask the user to confirm. Cache the null result and consider periodic refreshes to catch source updates.

How are EVs represented?
If the VIN decodes to an electrified vehicle and the source publishes data, you may see non-null electrification_level, ev_drive_unit, battery_kwh, charger_level, and charger_power_kw. For non-EVs, these fields are null. Never infer EV specs if fields are null.

Can I use this for safety data like recalls?
Fuel Type is part of VIN decoding. Safety datasets (recalls, complaints, NCAP ratings) are US-market only and matched by make + model + year; they are separate from the fuel fields. Use them to enrich context, not to determine fuel.

What are the rate limits and monthly quota?
They depend on your plan and are visible in your dashboard and the docs. Implement caching and backoff on 429 responses to stay within limits.

Start building with the 7-day free trial: Register. Explore schemas and examples in the Documentation, and wire it into your AI tools via MCP.

Keep reading