
Every figure on every page. As JSON.
The whole dataset, machine-readable
One REST API and static JSON twins for every page. Sign in for a free key; upgrade when a product ships.
Every figure on every page is present in the served HTML and in that page's JSON twin under /data/; nothing is rendered client-side after load, so a crawler or assistant that runs no JavaScript reads the whole record.
Authentication
Base URL https://api.whichtrim.com/v1. Send your key in the x-api-key header. Keys are created in the dashboard; each has its own client ID for per-app attribution. Over-quota requests return 429 with Retry-After; a missing or revoked key returns 403.
curl "https://api.whichtrim.com/v1/vehicles?make=toyota&year=2026" -H "x-api-key: YOUR_KEY"
Endpoints
GET /v1/vehicles
List model-years. Filters: make, model, year, grade, min_score, advisory=true, limit (≤500), offset.
{"count": 12, "vehicles": [{"id": "2026_kia_sportage", "make": "Kia", "model": "Sportage", "year": 2026, "segment": "Compact SUV", "powertrains": ["Plug-in hybrid","Hybrid","Gas"], "grade": "A", "score": 92, "recall_count": 1, "critical_count": 0, "active_advisory": false, "complaints": 32, "ncap_overall": 5, "best_mpg": 42, "best_range_mi": null, "msrp_from": 28790, "page": "https://whichtrim.com/kia/sportage/2026/"}]}GET /v1/vehicles/{id}
Full record: EPA configurations, every recall with severity and park-outside flags, complaint aggregates and excerpts, NCAP ratings, investigations, driver-assist crash reports filed under NHTSA’s Standing General Order, manufacturer service bulletins and campaigns, the diagnostic trouble codes that model year's own record names, and — where published — trims, specs and features from the manufacturer press kit.
{"id": "2026_kia_sportage", "configs": [{"model": "Sportage Hybrid FWD", "pt": "hev", "comb": 42, ...}], "recalls": [{"campaign": "26V046000", "severity": "high", "park_outside": false, ...}], "complaints": {"count": 32, "crash": 4, "fire": 0, "comps": [["Electrical System", 8], ...]}, "ncap": [{"desc": "SUV AWD", "overall": 5, ...}], "trims": [{"trim_id": "2026_kia_sportage_lx_fwd", "trim_name": "LX", "msrp_base": 28790, ...}], "specs": [...], "features": [...]}GET /v1/vehicles/{make}/{model}/{year}
Same record by names: /v1/vehicles/toyota/rav4/2026 (spaces or hyphens both work).
GET /v1/vin/{vin}
Decode a 17-character VIN (NHTSA vPIC) and get it back joined to this dataset: the model-year record, grade, every recall campaign, complaints and published trims. decode.equipment normalises the driver-assist equipment the manufacturer filed for that configuration to standard / optional.
{"decode": {"vin": "5XYP3DHC8NG123456", "model_year": 2022, "make": "KIA", "model": "Telluride", "trim": "EX", "body_class": "Sport Utility Vehicle (SUV)/Multipurpose Vehicle (MPV)", "drive_type": "4WD/4-Wheel Drive/4x4", "engine": {"displacement_l": 3.8, "cylinders": 6, "hp": 291}, "equipment": {"automatic_emergency_braking": "standard", "blind_spot_monitoring": "standard", "adaptive_cruise_control": "optional"}, "plant": {"city": "WEST POINT", "country": "UNITED STATES (USA)"}, "source": "NHTSA vPIC"}, "matched": {"exact_year": true, "id": "2022_kia_telluride"}, "vehicle": {"id": "2022_kia_telluride", "grade": "B", "recall_count": 3, "recalls": []}}GET /v1/recalls
Every campaign across the catalog, newest first, with the vehicle ids it covers. Filter: since=YYYY-MM, limit, offset.
{"count": 11342, "recalls": [{"campaign": "26V431000", "component": "ELECTRICAL SYSTEM:PROPULSION SYSTEM:TRACTION BATTERY", "park_outside": true, "vehicles": ["2024_kia_ev6"], ...}]}GET /v1/recalls/{campaign}
One campaign by NHTSA number, e.g. 26V431000.
GET /v1/bulletins
Manufacturer communications filed with NHTSA that have a page on the site — service campaigns, warranty extensions, over-the-air and emissions notices, and the service bulletins the model-year pages list — newest first, with every document number filed under each as an alias. Filters: make, kind (service campaign, warranty extension, over the air, emissions, service bulletin), letter=true (the kinds an owner is written to about), since=YYYY-MM, number (a number or document number, matched as the search box matches it), limit, offset. These are not safety recalls.
{"count": 6971, "bulletins": [{"make": "Hyundai", "make_slug": "hyundai", "number": "9D6", "slug": "9d6", "aliases": ["26-01-068h", "26-01-068h-dn", "26-01-068h-tsb"], "campaign_id": "9D6", "kind": "Service campaign", "letter_in_hand": true, "date": "2026-03-12", "received": "2026-03-18", "components": ["Electrical System"], "model_years": 1, "documents": 2, "page": "https://whichtrim.com/bulletins/hyundai/9d6/", "api": "https://whichtrim.com/v1/bulletins/hyundai/9d6"}]}GET /v1/bulletins/{make}/{number}
One communication by the number on the letter (the manufacturer’s campaign id) or by any document number filed under it: /v1/bulletins/hyundai/9d6 and /v1/bulletins/hyundai/26-01-068H return the same record. NHTSA’s summary, the model years it names (with vehicle ids where the site has the page), every document with its NHTSA id and a PDF link only where NHTSA’s server has been seen to serve it.
{"bulletin": {"make": "Hyundai", "number": "9D6", "campaign_id": "9D6", "kind": "Service campaign", "date": "2026-03-12", "received": "2026-03-18", "components": ["Electrical System"], "summary": "Some vehicles may exhibit ...", "documents": [{"number": "26-01-068H TSB", "nhtsa_id": "11036201", "kind": "Service campaign", "date": "2026-03-12", "pdf": "https://static.nhtsa.gov/odi/tsbs/2026/MC-11036201-0001.pdf", "pdf_bytes": 142480}, ...], "model_years": [{"id": "2026_hyundai_palisade", "year": 2026, "make": "Hyundai", "model": "Palisade", "page": "https://whichtrim.com/hyundai/palisade/2026/"}], "page": "https://whichtrim.com/bulletins/hyundai/9d6/", "not_a_recall": "..."}}GET /v1/advisories
Every model-year with an active park-outside or do-not-drive advisory, with the advisory recalls attached.
GET /v1/dtc
Diagnostic trouble codes joined to the vehicles whose federal record documents them — a WhichTrim dataset with no public equivalent. defined_by says whether the meaning comes from the OBD-II standard or from the automaker, because for a manufacturer-specific code nobody can define it honestly.
{"count": 1840, "codes": [{"code": "P0420", "meaning": "The catalytic converter on bank 1 is not cleaning up the exhaust as well as it should.", "defined_by": "standard", "system": "Powertrain — engine, transmission and emissions.", "bulletins": 214, "owner_reports": 1163, "components": ["Exhaust System", "Engine"], "vehicles": ["2015_honda_accord", ...], "page": "https://whichtrim.com/dtc/p0420/"}]}GET /v1/compare
Which is better: two or three vehicles scored on price, fuel, safety, space, performance, tech and warranty with your weights — the engine behind whichtrim.com/compare. ?a=2026_kia_sportage:lx_fwd&b=2024_mazda_cx_90:3_3_turbo_select_awd&weights=4-3-4-2-2-3-2. Returns the verdict plus every value and score it rests on.
{"overall": [92.0, 89.3], "verdict": {"winner": 0, "runner_up": 1, "margin": 2.7, "strength": "edge"}, "summary": "The Kia Sportage SX Prestige edges it, 92 to 89.3, on tech & comfort. ...", "categories": [{"id": "budget", "weight": 4, "scores": [75.2, 100], "metrics": [{"id": "msrp", "values": [37990, 28565], "scores": [75.2, 100]}]}], "reasons": [...], "flips": [...]}GET /v1/grades
Safety Signal grade + score for every model-year (lightweight, good for caching).
GET /v1/meta · GET /v1/health
Dataset metadata (counts, generation time, method) and liveness.
Compare endpoint & scoring method
GET https://api.whichtrim.com/v1/compare?a=<id>[:<trim>]&b=<id>[:<trim>][&c=…][&weights=4-3-4-2-2-3-2] returns the same verdict the site shows, with the arithmetic.
Categories (weights 0–5, order for the weights parameter): price · fuel & range · safety · space & cargo · performance · tech & comfort · warranty. Or name them: weights=budget:5,safety:4.
Scoring. Relative metrics (MSRP, EPA fuel cost, mpg/MPGe, cargo, horsepower, warranty terms…) give 100 to the best contender and a proportional share to the rest (best/value for lower-is-better, value/best for higher-is-better). Absolute metrics keep their own scale: NHTSA overall stars ×20, Safety Signal as-is. A metric missing for any contender is dropped for all of them. Category score = weighted mean of its metrics; overall = weighted mean of the categories using your weights; categories with no usable metric are excluded and the weights renormalised. An open park-outside or do-not-drive advisory costs 25 safety points. Verdict strength: margin ≥ 6 = clear, ≥ 2 = edge, otherwise toss-up.
Response. overall[], verdict{winner, runner_up, margin, strength}, categories[] (each with available, weight, scores[], metrics[]{label, unit, dir, values[], scores[]}), reasons[] (category contributions to the lead), flips[] (the weight change that would reverse the verdict) and a plain-English summary. A contender given without a trim uses its base trim (lowest MSRP) wherever a press kit is on file — base compares with base — and its most efficient EPA configuration; a trim-level contender uses that trim's own MSRP, specs and equipment; a vehicle without a press kit is compared on EPA and NHTSA data only. The response says which (contenders[].trim_auto, trim_label). Add detail=1 for the side-by-side sections the site shows: detail.specs (by family, with best/worst flags where the direction is unambiguous), detail.equipment (feature matrix by system, differences flagged), detail.safety (NCAP, Safety Signal, recalls with remedy status, complaints), detail.ownership (price range, fuel cost, warranty). Add narrative=1 for the plain-English take WhichTrim publishes on that pair (narrative.summary, pick_a_if, pick_b_if, basis) — written from the default-weight verdict on the base trims and cached at build time, so it exists for the pre-computed head-to-heads and is null for other pairs. Where no manufacturer press kit exists, seating and horsepower fall back to what the manufacturer filed with NHTSA (vPIC), decoded from the VIN pattern; a press-kit value is never overridden. Engine version is returned as version (c3); the method above is versioned with it.
Identifiers
Vehicle ids are <year>_<make>_<model> in lowercase with spaces as underscores — 2026_ford_f_150. A "vehicle" is one nameplate in one model year as defined by the EPA base model, so gas, hybrid and plug-in versions share a record and are distinguished inside configs and, for recalls, by the variants field. Trim ids are prefixed with the vehicle id (2026_kia_sportage_sx_prestige_awd). Recall campaigns use NHTSA numbers. Dates are ISO YYYY-MM-DD.
Data, coverage & refresh
Model level (every vehicle): EPA fueleconomy.gov configurations (mpg, MPGe, range, fuel cost), NHTSA recalls with severity and park-outside / do-not-drive flags, owner-complaint aggregates and excerpts, defect investigations, NCAP crash ratings, crash reports filed under NHTSA’s Standing General Order (Level 2 driver-assist and automated-driving systems, as filed), the WhichTrim Safety Signal grade.
Trim level (where a manufacturer press kit is on file): MSRP, ~55 specifications on one schema (engine, dimensions, cargo, weights, warranty…), ~260 canonical features with standard / optional availability per trim. Records list trims, specs, features; an empty trims array means model-level only.
Refresh. The dataset is rebuilt daily (NHTSA and EPA files re-read every build). Manufacturer newsrooms are crawled weekly for new spec sheets and pricing; a new kit is extracted, checked and published on the next build. Every response carries x-data-generated-at.
Provenance. Press-kit values are transcribed from the manufacturer's official documents and carry source_url, source_type and a confidence; nothing is hand-edited.
Static JSON (no key)
Per-vehicle JSON
Every page has a twin at /data/v/<id>.json, CORS-open and edge-cached. Attribution required; no bulk redistribution.
What is in the data
Every field, the authority behind it, how often it refreshes, where the coverage stops, and what you may do with it.
Coverage & sourcesSafety Signal badge
for dealer and fleet websitesPut a vehicle's safety record on the page that sells it: the WhichTrim grade, the recall count, any open park-outside or do-not-drive advisory, and the date it was last checked against NHTSA. Free. The link to the model-year page is the price — keep it and the badge is yours to use on any page that lists that vehicle.
The snippet is a plain link first and a badge second. Without the script (or before it loads) your page carries an ordinary link to the vehicle's record; with it, the link is redrawn as the badge from the vehicle's public JSON twin — one request, no key, credentials: omit. It sets no cookie, reads no storage, loads nothing else and sends nothing about your visitor or your page; the only thing that reaches us is that JSON request. The data behind it is rebuilt nightly.
Name the vehicle by id (data-vehicle="2026_ford_f_150") or by name (data-year="2026" data-make="Ford" data-model="F-150"); add data-theme="dark" for a dark card. Several badges on one page share one script tag.
A recall covers a build range, not a model year: the badge states what is filed against the model year, and the two VIN lookups on the linked page settle a specific vehicle. Please do not present it as a clearance for one car.
Make your snippet
<a class="whichtrim-badge" href="https://whichtrim.com/ford/f-150/2026/" data-vehicle="2026_ford_f_150">2026 Ford F-150 safety record — WhichTrim</a> <script async src="https://whichtrim.com/embed.js"></script>
Preview
If the name does not match a vehicle we hold, the link still works and the badge stays a link. Check the id against the index.
MCP server
Source: Model Context ProtocolWhichTrim is also an MCP server, so an assistant can look a vehicle up directly instead of guessing. No key and no account — everything it returns is already on a public page, and we would rather be the thing that gets cited.
https://whichtrim.com/portal/mcp
Streamable HTTP, stateless: one JSON-RPC POST, one JSON reply. Nine tools — search_vehicles, get_vehicle, get_trims (every trim of a model year from the manufacturer's press kit: MSRP, specs and which equipment is standard where, or one trim's full spec sheet), check_recalls, decode_vin, lookup_trouble_code, lookup_bulletin (the number on a service-campaign letter or a dealer bulletin), compare_vehicles and federal_cases (the federal dockets in the RECAP index that name the manufacturer and mention a model and system, cached nightly). GET the same URL for a plain description of the server and its tools.
// Claude Desktop / any MCP client that speaks HTTP
{
"mcpServers": {
"whichtrim": { "url": "https://whichtrim.com/portal/mcp" }
}
}Every tool response carries the page URL it came from and the source line, because an answer a reader cannot trace is not worth giving. One rule is built into every recall answer and into the server's own instructions: a recall covers a build range, not a model year, so nothing here can tell somebody their particular car is clear — only NHTSA's VIN lookup settles that.
Webhooks
Source: Recall Watch, every planRecall Watch posts the same nightly digest to your endpoint as JSON, so a new campaign lands in the system that schedules the work instead of in somebody's inbox. The email still goes out: a silently-failing endpoint must not be the reason nobody hears about a do-not-drive recall.
Set the URL in your dashboard. It must be https and resolve to a public address — we refuse private and link-local hosts, and we never follow redirects. The signing secret is shown once, when you save it.
Verify every delivery. We send WhichTrim-Signature: t=<unix>,v1=<hex>, where the hex is HMAC-SHA256 of <t>.<raw body> using your secret. The timestamp is inside the signed material, so check it is within five minutes and a captured request cannot be replayed at you later. Compare in constant time.
// Node — the whole check
import { createHmac, timingSafeEqual } from "node:crypto";
function valid(raw, header, secret) {
const t = /(?:^|,)t=(\d+)/.exec(header)?.[1];
const v1 = /(?:^|,)v1=([0-9a-f]+)/.exec(header)?.[1];
if (!t || !v1) return false;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay window
const want = createHmac("sha256", secret).update(`${t}.${raw}`).digest("hex");
const a = Buffer.from(want, "hex"), b = Buffer.from(v1, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}Use the raw body, before any JSON parsing — re-serialising changes the bytes and the signature will not match.
Reply 2xx and we are done. A 5xx or a timeout is retried twice with backoff; a 4xx is not retried, because that is a configuration problem at your end and hammering it helps nobody. The dashboard shows the last delivery result, so a broken endpoint is something you see rather than something you discover in an audit.
The payload
{
"type": "recall.opened",
"at": "2026-09-14T09:00:11Z",
"watched": 412,
"vehicles": [{
"vin": "1FTFW1ET9DFC10312",
"label": "A4471",
"year": 2023, "make": "Ford",
"model": "F-150",
"opened": [{
"campaign": "24V123000",
"component": "FUEL SYSTEM",
"severity": "critical",
"park_outside": false,
"do_not_drive": false,
"summary": "…",
"nhtsa_url": "…"
}],
"verify": {
"nhtsa": "…",
"manufacturer": "…"
}
}]
}A test delivery has "type":"test" and an empty vehicles array, so you can finish the integration without waiting for a recall to land.
verify carries both doors that settle one VIN: NHTSA's checker and that make's own lookup, which 49 CFR 573.15 obliges the manufacturer to run and refresh weekly. A campaign covers a build range, so neither this payload nor anything else we publish can tell you a specific vehicle is affected.
Plans & limits
| Free | Developer | Pro | Business | |
|---|---|---|---|---|
| Requests | 100 requests / day | 25,000 requests / month | 250,000 requests / month | 2,000,000 requests / month |
| Rate limit | 2 req/s | 5 req/s | 20 req/s | 50 req/s |
| API keys / client IDs | 1 | 3 | 10 | 10 |
| Commercial use | — | ✓ | ✓ | ✓ |
| Uptime SLA | — | — | — | 99.9% |
| Support | Community | Priority email | Named contact | |
| Every endpoint & field | ✓ | ✓ | ✓ | ✓ |
| Bulk JSON downloads | — | — | ✓ | ✓ |
| Internal redistribution | — | — | — | ✓ |
Full details and FAQ on the API pricing page. The same API is also listed on RapidAPI.
Changelog
2026-10-11 (recall fix sheets) — additive. Every recall record (in recalls.json, advisories.json and each vehicle record) gains fix: null, or what the manufacturer’s dealer documents filed with NHTSA say — stop_sale, remedy_available (true, false, or null when the notice does not say), remedy_availability_quote, remedy, labor (operation code and hours from the warranty table), parts, tools, owner_instructions, sources (the two PDFs) and line, the one-line summary. Read nightly; a campaign whose documents are not yet read carries null.
2026-10-06 (bulletin depth, warranty terms) — all additive. A bulletin record gains applies_to (the build windows, engine and transmission NHTSA’s summary states, each with its own words), supersedes and superseded_by ([{number, page}]; page is null when the other filing has no page here). Each row of a vehicle record’s complaints.excerpts gains a fifth element, the NHTSA ODI number. A vehicle record whose press kit states no warranty gains warranty_fallback: the make’s consensus terms, with how many of its kits state them and agree, the model years they span and the source, labelled as the make’s terms rather than this model year’s.
2026-10-02 (what else a bulletin names) — each row of a vehicle record’s bulletins.items may carry for: the model years the filing names, one entry per model (“2016 Patriot”, “2016 Compass”, “2016 Dodge Journey”), the record’s own model first. Absent when the filing names only that model year.
2026-09-28 (one bulletin page per filing) — a number the manufacturer filed under several of its brands (GM’s Chevrolet, GMC, Buick and Cadillac; Ford and Lincoln; Stellantis; Jaguar Land Rover) is now one page listing every brand’s vehicles. /v1/bulletins/{make}/{slug} still answers for every brand, and each record gains makes (every brand it lists) and maker; page is the one page, which may sit under another brand’s address. Rows of GET /v1/bulletins stay one per brand, with that brand’s own nameplates.
2026-09-14 (usage) — GET /portal/usage gains route_errors (failed responses per endpoint), by_key_route (calls and failures per key per endpoint) and key_names. Your dashboard now shows which endpoint is failing rather than a single error total. Counting starts with this release: requests answered before it have a total but no per-endpoint breakdown, and the page says so rather than reporting zero.
2026-09-14 (trouble codes) — new endpoint /v1/dtc, and /v1/vehicles/{id} gains trouble_codes: [{code, bulletins, owner_reports, components, page}]. A WhichTrim dataset derived from the federal record, filtered so that a part number which happens to look like a code is not counted as one. defined_by is standard, manufacturer or undefined; a meaning is only ever returned for the first. Counts are mentions in the federal files, not failure rates.
2026-09-29 (complaints by system) — a vehicle record’s complaints gains by_comp: for up to eight of NHTSA’s component groups on the model year, the complaint count, how many report a crash, a fire or an injury, the count by year filed, and up to five owner accounts about that system (scrubbed as everywhere else). It is what the new problems pages (/<make>/<model>/<year>/problems/<system>/) are built from. Additive.
2026-09-29 (the build window the document states) — document_body gains build_windows: the production-date windows the manufacturer’s own PDF sets (“built on or before 04-Dec-2023”, “produced from 8/24/2022 – 12/06/2022”), each as from / to ISO dates (YYYY-MM when the document gives only a month; an open end is null), bound (before, on or before, after, on or after, between), for (the model the sentence names, or null) and quote (the document’s own words). An empty list when the document states none; a VIN-only cut-off is not a window. Documents read before today are read again over the coming nights. Additive.
2026-09-29 (the codes the document names) — document_body gains trouble_codes: the diagnostic trouble codes the manufacturer’s own PDF names, read with the same test as the summary’s codes (a code only where the text is discussing diagnostics), up to 40, in code order. An empty list when the document names none. Additive.
2026-09-29 (what the document itself lists) — a bulletin record (/v1/bulletins/{make}/{number}, /data/b/<make>/<number>.json) gains document_body once the PDF NHTSA serves for it has been read (about 2,000 documents a night): parts (number, description, qty — a number only in the manufacturer’s own catalogue shape), labor (operation, description, time, unit), supersedes, title, pdf, pages, read_at. A description the reader could not settle is null, never a guess. Absent until the document has been read. Additive.
2026-09-26 (bulletin nameplates) — every row of GET /v1/bulletins gains nameplates: the make/model slugs ("alfa-romeo/giulia") of the model-year pages the communication names. Additive.
2026-09-20 (bulletins for machines) — GET /v1/bulletins and GET /v1/bulletins/{make}/{number} (above); the MCP server gains lookup_bulletin; every bulletin page has a JSON twin at /data/b/<make>/<number>.json. Additive.
2026-09-20 (bulletin pages) — every entry in bulletins.items (the vehicle record) and every bulletin listed under a trouble code now carries url: the bulletin number’s own page, /bulletins/<make>/<number>/, when this build wrote one. Every bulletin with a usable number that a vehicle record lists has one; a communication filed with no usable number (blank, “N/A”) carries no url. Additive; nothing else changes.
2026-09-13 (owner narratives) — complaints.excerpts changes shape and content. Each entry was [date, component, text] and is now [date, component, text, miles], where miles is the odometer reading from the same filing or null. Up to six are returned instead of three, chosen one per component in order of how often that component is cited rather than by date. The text itself is now scrubbed before it is stored: whole sentences containing a VIN, phone number, email address or URL are removed, NHTSA's clerical marks are stripped, and filings written in upper case are sentence-cased. Nothing is paraphrased — the owner's words are unchanged.
2026-09-12 (emissions) — every EPA configuration in configs gains emissions: smog rating 1–10, the certified emission standard, SmartWay status, engine family id, and the EPA sales areas that say whether the configuration is a 50-state car or a California/CARB one (fifty_state, carb_only). A configuration holding both a federal and a California certificate reports a score range.
2026-09-12 (bulletins) — /v1/vehicles/{id} gains bulletins: the manufacturer communications filed with NHTSA for that model year — service bulletins, service campaigns, warranty extensions and over-the-air updates — with counts by kind and component, the most recent few document numbers, dates and summaries. The layer that describes what actually goes wrong with a car short of a recall, and one no vehicle-history report carries.
2026-09-12 (c4) — /v1/vin/{vin} returns decode.equipment: the driver-assist equipment the manufacturer filed for that configuration, normalised to standard / optional. /v1/compare scores it as its own safety metric for vehicles with no press kit — never against a press-kit feature count, since the two are itemised differently.
2026-09-12 (c3) — vehicles with no press kit now carry vinspec: engine, transmission, seating, body class and driver-assist equipment as filed with NHTSA and decoded from the VIN pattern. /v1/compare uses seating and horsepower from it when the press kit has none, so space and performance stop scoring as "no data".
2026-09-12 — /v1/vin/{vin}: decode a 17-character VIN against NHTSA vPIC and get it back joined to this dataset — the model-year record, its grade, every recall campaign, complaint aggregates and published trims. The same decoder powers the free tool at /vin/.
2026-09-13 — /v1/compare?narrative=1 returns the "our take" text shown on the site's head-to-head pages (summary, pick_a_if, pick_b_if, basis) for pre-computed pairs.
2026-09-12 (c2) — /v1/compare: a vehicle given without a trim now scores its base trim when a press kit is on file (was model-level only); detail=1 returns specs by family, the equipment matrix, safety record and ownership. Contenders carry trim_auto / trim_label.
2026-09-12 — Feature rows carry name (the manufacturer's own wording) and oem_label; press-kit equipment that matches nothing in the shared catalog is now published under its own label (feature_id prefixed x_). Free-text specs are verbatim from the press kit.
2026-09-11 — /v1/compare added (engine c1). Vehicle records gained warranty, park_outside, do_not_drive, url. API moved to api.whichtrim.com. Portal: dashboard usage counts are live per key.
2026-09-10 — Trim-level press-kit layer (trims / specs / features) on vehicle records; carry-over model years; HD nameplates.
Terms in one paragraph
You may use responses in your own products and cache them for up to 7 days. Attribution ("Data: WhichTrim, from EPA and NHTSA public records") is required on the Free plan and appreciated on all plans. You may not resell the raw dataset or use it to build a competing data feed without a license. Federal data are public domain; our joins, grades, transcriptions and identifiers are ours. See the terms of use.