If you build anything that touches vehicle data, sooner or later you need to answer a simple-sounding question: "Which World Manufacturer Identifiers (WMIs) belong to this manufacturer?" Maybe you want to pre-validate VINs on a marketplace form, group inventory by maker, or flag a VIN whose first three characters do not match the brand a seller typed in.
The tempting shortcut is to scrape a WMI table off some website. Don't. Those tables go stale, are often incomplete, and scraping them is fragile. The U.S. National Highway Traffic Safety Administration (NHTSA) already publishes this data through its free vPIC API, including an endpoint built for exactly this job: GetWMIsForManufacturer.
What a WMI actually is
A modern 17-character VIN (ISO 3779) is split into three sections:
- Positions 1-3: WMI (World Manufacturer Identifier). Identifies the manufacturer and, through the first character, the region/country.
- Positions 4-9: VDS (Vehicle Descriptor Section). Model, body, engine, etc., plus the check digit in position 9.
- Positions 10-17: VIS (Vehicle Identifier Section). Model year, plant code, and serial number.
The first character roughly indicates the region (for example 1, 4, 5 for the United States, J for Japan, W for Germany). The three characters together are assigned to a specific manufacturer. One wrinkle: small-volume manufacturers (fewer than 1,000 vehicles per year) use a 9 in position 3, and their identity continues in positions 12-14. Keep that in mind when you match on WMI alone.
The NHTSA endpoints you need
All of these live under https://vpic.nhtsa.dot.gov/api/vehicles/ and accept ?format=json. No API key required.
-
GetWMIsForManufacturer/{manufacturer}returns every WMI registered to a manufacturer. You can pass a name fragment (e.g.honda) or a manufacturer ID. An optionalvehicleTypeparameter narrows results. -
DecodeWMI/{wmi}goes the other way: given a 3-character WMI (or 6 characters for small manufacturers), it returns the manufacturer name, vehicle type, and more. -
GetAllManufacturersis a paginated list of manufacturers with their IDs, handy for building a picker. -
GetManufacturerDetails/{name}returns addresses, country, and vehicle types for a manufacturer.
Together, they let you build a manufacturer-to-WMI map from an authoritative source instead of a scraped HTML table.
Sample TypeScript: manufacturer to WMIs
type WmiRow = {
WMI: string;
Name: string;
Country: string | null;
VehicleType: string | null;
CreatedOn: string | null;
UpdatedOn: string | null;
};
type VpicResponse<T> = {
Count: number;
Message: string;
Results: T[];
};
const BASE = "https://vpic.nhtsa.dot.gov/api/vehicles";
export async function getWmisForManufacturer(
manufacturer: string,
vehicleType?: string
): Promise<WmiRow[]> {
const url = new URL(
`${BASE}/GetWMIsForManufacturer/${encodeURIComponent(manufacturer)}`
);
url.searchParams.set("format", "json");
if (vehicleType) url.searchParams.set("vehicleType", vehicleType);
const res = await fetch(url);
if (!res.ok) throw new Error(`vPIC error ${res.status}`);
const data = (await res.json()) as VpicResponse<WmiRow>;
return data.Results;
}
export async function buildWmiIndex(makers: string[]) {
const index = new Map<string, Set<string>>(); // WMI -> manufacturer names
for (const maker of makers) {
const rows = await getWmisForManufacturer(maker);
for (const row of rows) {
const set = index.get(row.WMI) ?? new Set<string>();
set.add(row.Name);
index.set(row.WMI, set);
}
}
return index;
}
// Usage
const index = await buildWmiIndex(["honda", "toyota"]);
console.log(index.get("1HG")); // e.g. Set { "HONDA OF AMERICA MFG., INC." }
And the reverse lookup for a single VIN:
export async function decodeWmi(vin: string) {
const v = vin.trim().toUpperCase();
// Small-volume makers: position 3 is '9', identity continues at 12-14
const wmi = v[2] === "9" ? v.slice(0, 3) + v.slice(11, 14) : v.slice(0, 3);
const res = await fetch(`${BASE}/DecodeWMI/${wmi}?format=json`);
const data = await res.json();
return data.Results?.[0] ?? null;
}
Mapping manufacturer to WMI without scraping
A practical pattern:
-
Seed a list of manufacturers you care about (from
GetAllManufacturersor your own catalog). -
Fetch WMIs for each with
GetWMIsForManufacturer, throttled politely (a few requests per second is plenty). -
Store the result in your own table:
wmi,manufacturer_name,country,vehicle_type,updated_on. -
Refresh on a schedule (weekly or monthly). WMIs do not change often, and the
UpdatedOnfield tells you what moved. -
Fall back to
DecodeWMIat request time for any WMI not in your cache, then add it.
This gives you fast local lookups, an authoritative source, and no brittle HTML parsing.
Caveats that will bite you
Multiple plants, multiple WMIs. A single brand can have many WMIs because each manufacturing entity and region gets its own. Honda cars built in the U.S., Canada, and Japan carry different WMIs. Never assume one brand equals one WMI.
Brand vs manufacturer. vPIC is keyed on the legal manufacturer, not the marketing brand. Searching "Chevrolet" may give you less than searching "General Motors". Some brands are built by another company entirely (badge engineering, joint ventures, contract assembly). If your UI talks in brands, keep a brand-to-manufacturer mapping layer between users and the API.
Name matching is fuzzy. GetWMIsForManufacturer/ford matches anything containing "ford", which can include unrelated companies. Filter results, or resolve to a manufacturer ID first and query by ID.
Vehicle type matters. The same manufacturer may have separate WMIs for passenger cars, trucks, motorcycles, and trailers. Use the VehicleType field rather than discarding it.
U.S.-centric coverage. vPIC is strongest for vehicles sold in the U.S. market. For other regions, treat results as useful but not exhaustive.
A WMI is not validation. A matching WMI does not prove a VIN is genuine. Combine it with check-digit validation, a model-year sanity check, and a full decode.
Wrapping up
WMI lookups are one of those things that feel like they need a scraped spreadsheet but really need a small cache in front of an official API. GetWMIsForManufacturer plus DecodeWMI cover both directions, and a scheduled refresh keeps you current without hammering anyone's servers.
Disclosure: I maintain VIN Lookup, a free VIN decoder that builds on public data like NHTSA vPIC. If you just want to see what a WMI and the rest of a VIN decode to without writing code, it's there to try.
Top comments (0)