VIN Decoder
Mahad Farooq
A VIN is the 17-character ID stamped on every vehicle. Hidden inside it is the make, model, year, weight class, fuel type, and more, but only if you can decode it. The plain version of this project: you type in a VIN, and you get back clean, reliable details about the car.
The interesting part is not the decoding. The government already gives you that for free. The interesting part is making the result trustworthy.
The real problem: the source data is a mess
The app calls the free NHTSA vPIC API. That API works, but it hands you back around 150 fields that are noisy and completely untyped. Empty strings, the literal text "Not Applicable," stray whitespace, numbers stored as strings, weird range descriptions jammed into one field. If you build directly on that, every screen downstream has to re-handle the same garbage.
So I built a normalization layer that turns all of that into one consistent, strongly-typedVehicle contract. Decode a VIN once, and everything after it can trust the shape of the data.

What the normalization actually does
- Empty values, "Not Applicable," and whitespace all collapse to a clean
nullinstead of five different versions of nothing. - Numeric fields like model year, door count, and engine cylinders get coerced to real numbers, not strings.
- The GVWR weight class gets parsed out of the long range description into its own field.
- Error codes and messages from the API are kept, so you can tell how trustworthy a given decode is instead of silently showing bad data.
The output is one Vehicle model: VIN, make, model, year, vehicle type, body class, weight class, fuel types, drive type, engine specs, manufacturer, plant country, door count, and the data-quality signals.

How it is built
It is a Next.js app with the App Router, written in strict TypeScript with no any. Tailwind for styling. The tests run on Node's built-in test runner with experimental TypeScript type-stripping, which means zero test-framework dependencies, nothing extra to install.
There are two endpoints. GET /api/decode?vin=... decodes a single VIN, and POST /api/decode/batch takes a list of VINs at once. The whole thing deploys to Vercel with zero config and no API keys, because the vPIC API is free and needs no registration.
Why I built it
It is a small project, but it is the kind I like: take a messy real-world data source and wrap it in something clean and reliable that other code can actually depend on. The value was never the API call. It was the contract on top of it.