Vehicle history

A paid vehicle history report for used car buyers in the US. Enter a VIN or a licence plate, see a free preview, subscribe, and get the full report: ownership, odometer, accidents, title, theft, recalls and auction history, with a PDF to keep. We built the product for a US consumer brand.

Industry
Automotive
Client
A US consumer brand, name under NDA
Our role
Built the product, backend and frontend
Built
About four months, April to August 2026

Every report depends on data that can fail.

Before buying a used car, a buyer wants to know whether it was stolen, crashed, flooded or had its odometer rolled back. The answer comes from a paid vehicle data service with quotas, and it can fail halfway through a report the customer has already paid for.

The client needed the whole product around that data: the lookup, a funnel that sells the report, checkout on their own payments platform, the report and its PDF, and an account where subscribers manage everything. In two languages, with prices in local currencies, and correct every time money or a vehicle's history is on the screen.

~92%

of the product's code written by us, across about 230 pull requests

~1,150

unit and integration tests, most of them ours

48

currencies priced and formatted correctly at checkout

What we built.

From a VIN to a report

A VIN or a plate, a free preview that shows the report is worth buying, a funnel that sells it, and a report of up to seventeen sections, with auction photos stored and served through our own proxy. Every report downloads as a PDF, and the whole product runs in English and Spanish across about 3,300 strings.

Checkout and subscriptions

Card and wallet checkout on the client's payments platform, with prices that can live in different payment accounts. Events from that platform send the welcome email and create the first report, and subscribers can cancel, reactivate, change card and download invoices from their account.

Reports that repair themselves

When the data service fails mid-report, the gaps are marked and a background job fetches them again later. Only one server runs it at a time, it backs off when the quota runs out, and a fresh empty answer can never overwrite data we already had.

Security and quality, audited

We ran security and quality audits and shipped the fixes: sign-in hardened against account takeover, rate limits on sign-in and report creation, logs redacted, error tracking on both apps.

What broke, and what we changed.

The wrong price in Icelandic krónur.

Some currencies have no cents. A price stored in the smallest unit has to be divided by a hundred in dollars and by one in krónur, and a locale library will not tell you which is which. One price in krónur came out wrong. We now format money from the payment provider's own list of zero-decimal currencies, and the wrong price was corrected.

PDFs under load.

Each PDF is a headless browser rendering the report. Two requests at once could launch two browsers, and a burst of downloads could pile up with no limit at all. There is now one shared browser, a queue with a hard limit that turns extra requests away quickly, and a check that refuses to return an error page dressed up as a PDF.

A report that said more than it knew.

We audited every field of the report against real data from the provider and made about fifteen fixes. No more “no accidents” when accidents were never checked, the right amount shown as the sale price, and catalogue photos no longer passed off as photos of the actual car.

What it runs on

NestJS and TypeScript with Postgres and Redis on the back, Next.js and React on the front. Events over NATS from the client's payments platform, Puppeteer for PDFs, and Sentry on both apps.

Four months. From a VIN to a PDF.