Identity & safety · Vehicle Specifications

Vehicle Specs API

Where VIN decode gives you identity, this gives you the manufacturer spec sheet: body class, doors, seats, drive type, cylinders, displacement, horsepower, engine configuration, transmission style and speeds, GVWR class, plant country, manufacturer and vehicle type. It is a live, uncached NHTSA vPIC read projected through a fixed 20-field allowlist, so what you get is the factory record for that VIN, in the factory's own vocabulary. Use it when your product needs to reason about what the vehicle physically is — payload class, seating, powertrain — rather than how to label it.

GET/v1/vehicles/specifications/{vin}15 s route budget

Get an API keyFull parameter reference

What comes back

The response carries source, the upper-cased vin, and a specifications object on snake_case keys: make, model, year, trim, series, body_class, doors, seats, drive_type, cylinders, displacement_l, engine_hp, fuel_primary, engine_config, transmission_style, transmission_speeds, gvwr, plant_country, manufacturer and vehicle_type. A real 2022 Highlander sheet reads body_class "Sport Utility Vehicle [SUV]/Multipurpose Vehicle [MPV]", seats "7", displacement_l "3.5", engine_hp "295", transmission_speeds "8", gvwr "Class 1D: 5,001 - 6,000 lb (2,268 - 2,722 kg)", plant_country "UNITED STATES (USA)". Two properties will shape your integration. Every value is a string, including year, doors, seats, cylinders, engine_hp, displacement_l and transmission_speeds — parse them client-side, do not assume numbers. And the vocabulary is unnormalized vPIC: make arrives as "TOYOTA", drive_type as "4WD/4-Wheel Drive/4x4". Blank fields are dropped from the object entirely.

Request
curl -sS https://api.vehicles.dev/v1/vehicles/specifications/5TDDZRBHXNS221317 \
  -H "Authorization: Bearer $VEHICLES_API_KEY" \
  -H "Accept: application/json"
200 · full vPIC spec sheet
{
  "source": "carscrape",
  "specifications": {
    "make": "TOYOTA",
    "model": "Highlander",
    "year": "2022",
    "trim": "Limited",
    "series": "75 Series",
    "body_class": "Sport Utility Vehicle [SUV]/Multipurpose Vehicle [MPV]",
    "doors": "5",
    "seats": "7",
    "drive_type": "4WD/4-Wheel Drive/4x4",
    "cylinders": "6",
    "displacement_l": "3.5",
    "engine_hp": "295",
    "fuel_primary": "Gasoline",
    "engine_config": "V-Shaped",
    "transmission_style": "Automatic",
    "transmission_speeds": "8",
    "gvwr": "Class 1D: 5,001 - 6,000 lb (2,268 - 2,722 kg)",
    "plant_country": "UNITED STATES (USA)",
    "manufacturer": "TOYOTA MOTOR MANUFACTURING, INDIANA, INC.",
    "vehicle_type": "MULTIPURPOSE PASSENGER VEHICLE (MPV)"
  },
  "vin": "5TDDZRBHXNS221317"
}

The complete parameter table, the response-field dictionary and the per-endpoint error codes live in the reference: full parameter reference for /v1/vehicles/specifications/{vin}.

What it is actually built on

Unlike VIN decode, this endpoint consults no store cache. Every request performs a live NHTSA vPIC DecodeVinValuesBatch call, and the raw vPIC row is then projected through a fixed 20-field allowlist with blank values dropped. That design is intentional and worth understanding before you buy: it means you always see the current vPIC record rather than a snapshot we captured at scrape time, and it means your latency tracks NHTSA's. The route enforces a 15-second budget, and if vPIC is unreachable or that budget elapses you get 503 specifications_upstream_unavailable; an unexpected upstream status maps to 503 specifications_upstream_error. Both are marked retryable. What we add over calling vPIC yourself is the allowlist projection into stable snake_case keys, blank-field removal, the shared authentication and billing surface, and a hard timeout so a slow upstream cannot hold your request open indefinitely. If you also need our normalized, controlled-vocabulary view of the same vehicle, that is VIN decode — the two endpoints are complementary on purpose, not redundant.

Data source
A live NHTSA vPIC DecodeVinValuesBatch call on every request — no store cache is consulted. The raw vPIC row is projected through a fixed 20-field allowlist and blank values are dropped.
Route budget
15 s
Billed per
successful lookup, successful responses only
MCP tool
get_specifications

Limits: what this endpoint will not do

Coverage varies heavily by manufacturer and model year, and this is the endpoint where you will feel it. Older VINs and EVs commonly lack trim, seats and engine_hp; because blanks are omitted, a thin sheet returns a small object rather than a full one with nulls. Everything is a string, so any numeric comparison — horsepower bands, seat thresholds, GVWR parsing — is your code's job, and gvwr in particular is a prose class label, not a number. The vocabulary is raw vPIC, so do not join it directly against normalized data without mapping: "TOYOTA" will not equal "Toyota", and "4WD/4-Wheel Drive/4x4" will not equal "4WD". There is no options, equipment or packages list; the 20 allowlisted fields are the complete surface. Since nothing is cached, repeated lookups of the same VIN cost the same each time and take the same round trip. On input, the public route requires exactly 17 letters or digits and rejects I, O and Q. A VIN rejected by the backing validator or vPIC returns 400 invalid_vin, and a clean vPIC row with neither Make nor Model returns 404 specifications_not_found. Specifications shares the free Starter plan's 1,000 monthly calls with the other synchronous vehicle data APIs. After that shared allowance is used, successful lookups cost $0.0015 from the one-time $10 signup credit — enough for roughly 6,666 additional lookups — and calls return 402 insufficient_credits only when both are exhausted. The endpoint is available now and successful responses use the published catalog rate. Standard plans include no SLA.

What teams build with it

Fitment and parts catalog matching

Parts retailers, tire and accessory sellers, and aftermarket catalog vendors match SKUs on engine configuration, displacement, cylinder count, drive type and transmission — not on trim names. This endpoint gives all of those from a VIN in one call, in the same vocabulary most fitment tables were originally built against. Pair it with VIN decode when you also need clean display labels for the customer-facing part of the page, since specs deliberately keeps the raw source strings.

Commercial fleet and DOT class routing

Fleet management, telematics and compliance tools need to know whether a unit is Class 1 or Class 3 before applying inspection schedules, weight-based rules or insurance categories. gvwr returns NHTSA's full class string with both pound and kilogram ranges, and vehicle_type distinguishes an MPV from a passenger car or truck. That combination is hard to derive from marketing trim names and is exactly what this endpoint is for.

Vehicle detail pages and spec comparison tables

Marketplaces and dealer-site builders that render a specs table under each listing can populate it from one call per VIN, then keep the merchandising layer separate: identity and photos come from the VIN decode and photos endpoints, valuation from market value. Because coverage varies by manufacturer and year, render the table from whichever keys are actually present rather than from a fixed row list — omitted fields mean vPIC had nothing, not that the value is zero.

Underwriting and eligibility rules

Warranty administrators, service-contract sellers and specialty insurers often gate eligibility on horsepower bands, seat count or plant country. Reading those from the factory record rather than from a scraped listing description removes a class of dispute later. Note the tradeoff you are accepting: this is a live call per request, so build eligibility checks around a 15-second budget and cache results on your side if you re-check the same VIN often.

Integrating it properly

The reference ships the bare curl. This is the shape worth deploying: a typed client that branches on the RFC 9457 code slug rather than the human-readable title, and retries only the codes this endpoint marks retryable.

TypeScript
const API = "https://api.vehicles.dev";

// Only these codes are marked retryable for this endpoint. Everything else is terminal.
const RETRYABLE = new Set(["specifications_upstream_unavailable", "specifications_upstream_error"]);

export async function getSpecifications(vin: string, attempt = 0): Promise<GetSpecificationsResponse> {
  const response = await fetch(
    `${API}/v1/vehicles/specifications/${encodeURIComponent(vin)}`,
    {
      headers: {
        Accept: "application/json",
        Authorization: `Bearer ${process.env.VEHICLES_API_KEY ?? ""}`
      },
      // The route budget is 15 s; allow it plus headroom.
      signal: AbortSignal.timeout(20_000)
    }
  );

  if (response.ok) return (await response.json()) as GetSpecificationsResponse;

  // Failures are application/problem+json. Branch on `code`, never on the human-readable title.
  const problem = (await response.json()) as { code: string; detail?: string };
  if (RETRYABLE.has(problem.code) && attempt < 3) {
    await new Promise((resolve) => setTimeout(resolve, 250 * 2 ** attempt));
    return getSpecifications(vin, attempt + 1);
  }
  throw new Error(`${response.status} ${problem.code}: ${problem.detail ?? ""}`);
}

How to check it is behaving

The route enforces a 15-second upstream budget, so a slow dependency returns a problem document instead of holding your request open. Exactly 2 codes are marked retryable here — specifications_upstream_unavailable and specifications_upstream_error — and everything else documented for this endpoint is terminal, so backoff on anything else just burns your rate limit. Billing is success-only: failed calls release their reservation, so you can measure error rates and hold-out accuracy against your own data without paying for the failures. Usage is visible per endpoint in the dashboard.

What this one endpoint costs

Priced per successful lookup. The platform fee buys throughput and endpoint access; the unit price covers the data work. Worked at 50,000 successful calls a month so you can see where the plans cross over — the full price matrix is in the reference.

Vehicle Specs API pricing by plan
PlanPlatform feeRate limitPer successful lookup50,000 / month
Starter$0 / mo5 rps$0.0015$75$75 usage + platform fee
Pro$299 / mo10 rps$0.0015$374$75 usage + platform fee
Scale$599 / mo50 rps$0.001$649$50 usage + platform fee

Eligible for the Starter plan's included monthly calls; past those it draws on your credit balance. Data fees are prepaid from credits on every plan: when included calls and credits cannot cover a call you get 402 insufficient_credits rather than an overage bill. Published rates are active and apply only to successful responses. Standard plans include no SLA.

Questions engineers actually ask

Why are numbers returned as strings?

Because the values are passed through from NHTSA vPIC as-is, and vPIC returns strings. We deliberately do not coerce them, since coercion would have to invent a rule for values like "5,001 - 6,000 lb" or for blanks. Parse year, doors, seats, cylinders, engine_hp, displacement_l and transmission_speeds client-side, and guard for the key being absent entirely.

Should I call this or VIN decode?

Call VIN decode when you need clean, groupable identity — normalized make, model, trim, body style and a drivetrain constrained to AWD, FWD, RWD, 2WD or 4WD — and it is the cheaper call. Call Specifications when you need factory detail that decode does not carry: seats, horsepower, displacement, transmission speeds, GVWR class, plant country, manufacturer legal entity. Many integrations use both: decode for display and grouping, specs for rules and fitment.

Is the response cached, and how fast is it?

It is not cached at all. Every request is a live vPIC round trip, so latency tracks NHTSA against a 15-second route budget. If you look up the same VINs repeatedly — for example re-rendering a detail page — cache on your side; it will cut both your latency and your bill, since every successful lookup is billable.

Can I call this on the free Starter plan?

Yes. Specifications shares Starter's 1,000 included monthly calls with the other seven synchronous vehicle data APIs. After that shared allowance, each successful lookup costs $0.0015 from your one-time $10 signup credit (about 6,666 additional lookups). When both are exhausted the next call returns 402 insufficient_credits, not an invoice. On Pro it is $0.0015 per successful lookup ($1.50 per 1,000) and on Scale $0.001 ($1.00 per 1,000).

What does high-volume usage cost?

On Pro, 50,000 spec lookups is $75 in metered usage plus the $299 platform fee. On Scale the same volume is $50 plus the $599 fee. At spec volumes alone Pro is cheaper until roughly 600,000 lookups a month; choose Scale for its 50 rps ceiling rather than for this unit price at lower volume.

Do I pay when vPIC is down or the VIN has no sheet?

No. Billing is success-only: 400 invalid_vin, 404 specifications_not_found, and both retryable 503 codes release the reservation instead of settling it. That does mean a vPIC outage shows up as failed requests rather than stale cached data — a tradeoff of the always-live design.

Where to go next

Most integrations chain two or three of these. The ones that pair with vehicle specs api most often:

The reference entry for this endpoint — Vehicle Specifications in the API documentation — carries the parameter constraints, defaults, response fields and the full error table with retryable flags. Agents can reach the same endpoint as the get_specifications tool on the vehicles-dev-mcp MCP server, and the machine-readable contract is published at https://api.vehicles.dev/openapi.json.

Browse the rest of the catalog on the Vehicle data APIs hub.