How to Link Auto Parts SKUs to Vehicles with Vehicle IDs
A plate lookup tells you what the customer drives. To turn that into "here are the parts that fit", every product in your catalogue needs to know which vehicles it fits. Most stores keep that as text -- "Toyota Hilux 2015-2020 2.8L diesel" -- and match it with string comparisons. That works until it does not. This guide shows the sturdier way: link each SKU to PlateAPI vehicle IDs once, then answer every lookup with a single query.
Why text matching breaks
Vehicle names are not consistent enough to match on:
- Trims are often separate models. In the vehicle database,
HILUX,HILUX SRandHILUX SR5 EXTRA CABare three model names. A fitment line that says "Hilux" has to cover all of them. - Identical text can be different vehicles. The 2018 Mazda CX-5 has two 2.5L petrol AWD automatics with the same series (
KF -KF4WL) and the same variant text. One is the 140kW engine, the other the 170kW turbo. A part that fits one may not fit the other. - Plate lookups and vehicle records can word things differently. The sandbox plate
TEST123returns modelHILUX; the record for the same vehicle has modelHILUX SR.
A vehicle_id removes the guesswork. It identifies one exact variant, it is the same whether it comes from a plate lookup or the vehicle database, and it does not change. One ID covers every model year of that variant, so a part that fits a 2015-2020 Hilux SR needs one row, not six.
Step 1: a fitment table
Many-to-many between your products and vehicle IDs:
CREATE TABLE fitments (
sku text NOT NULL,
vehicle_id integer NOT NULL, -- PlateAPI vehicle_id
PRIMARY KEY (sku, vehicle_id)
);
CREATE INDEX fitments_vehicle ON fitments (vehicle_id);If your store platform has no database you control, the same data fits in a product custom field (a comma-separated list of IDs). The WooCommerce guide does it that way.
Step 2: map your catalogue once
For each fitment line, walk the vehicle database: every model name that starts with the base model, each year in the range, every series, the engines that match, and the vehicles under them. The Python SDK does the walk for you with walk_vehicles():
import csv, os
from plateapi import PlateAPI # pip install plateapi
client = PlateAPI(os.environ["PLATEAPI_KEY"])
# Your fitment lines: SKU, make, base model, years, engine text
FITMENT = [
("OIL-FLT-123", "TOYOTA", "HILUX", 2015, 2020, "2.8L"),
("AIR-FLT-456", "MAZDA", "CX-5", 2018, 2018, "2.5L"),
]
with open("fitments.csv", "w", newline="") as f:
out = csv.writer(f)
out.writerow(["sku", "vehicle_id"])
for sku, make, model, year_from, year_to, engine in FITMENT:
for v in client.walk_vehicles(make, model, year_from=year_from,
year_to=year_to, engine_contains=engine):
out.writerow([sku, v.vehicle_id])
print(sku, v.vehicle_id, v.model, v.engine)The CX-5 line returns both 2.5L engines, each with its own ID (run on 4 October 2026, 1.9 seconds):
AIR-FLT-456 4453973 CX-5 2.5L, PET PY I4 16v DOHC VVT Direct Inj {140kW}
AIR-FLT-456 6095835 CX-5 2.5L, PET PY I4 16v DOHC VVT I/C Turbo Direct Inj {170kW}If the filter fits only the non-turbo engine, narrow the text (engine_contains="VVT Direct Inj {140kW}") or delete the row you do not want. A wide walk, such as every Hilux trim from 2015 to 2020, is a few hundred requests and takes a minute or two at the SDK's default pace.
- Store the IDs, not the text. IDs are stable; names and series strings can change.
- Map every ID the walk returns unless you know a variant does not fit. Two records can share all their text and still be different vehicles.
- Narrow by what makes the part specific: the engine string carries displacement, engine code and power; the variant text carries doors, body, drive and gearbox ("4D Ute", "4WD", "AT/MT").
- The walk does not use lookup quota. The vehicle database is on Starter plans and above, with its own limit of 500 requests a minute.
Loading the result is one command, for example \copy fitments FROM 'fitments.csv' CSV HEADER in PostgreSQL.
Step 3: one query per lookup
A lookup returns a vehicle_id on the vehicle and on each alternative, plus a match field that tells you how sure the answer is:
"exact": one variant. Query its ID."multiple": several trims of one make and model, all on sale at the same time. Either show parts that fit any of them, or ask the customer to pick their trim and query that one ID."ambiguous": different models or generations. The vehicle has no ID (it would be a guess) andalternativeslists every candidate with its ID. Ask the customer to pick.
-- match = "exact" SELECT sku FROM fitments WHERE vehicle_id = 1380801; -- match = "multiple": everything that fits any candidate SELECT DISTINCT sku FROM fitments WHERE vehicle_id IN (1380801, 1346446, 1330126);
In Python, result.candidate_ids gives you every non-null ID in order, ready for the IN list:
result = client.lookup(plate, state)
if not result.success:
show_not_found()
elif result.match == "exact":
show_parts(result.candidate_ids) # one ID; empty if the variant is not certain
elif result.match == "multiple":
show_parts(result.candidate_ids) # or let the customer pick their trim
else: # "ambiguous": different models or generations
show_picker(result.alternatives) # each alternative has its own vehicle_idKeeping it current
- New vehicles get new IDs. Re-run the mapping for products whose fitment has not been resolved yet; monthly is plenty. Never re-map rows you already have.
- A lookup ID with no fitment rows is a mapping gap, not an unknown vehicle. Fetch the record with
GET /api/v1/vehicles/{vehicle_id}, see what it is, and map the SKUs that fit. - Merged IDs still resolve. If the database once held one vehicle under two IDs, fetching the old ID returns the current record. Compare the
vehicle_idyou get back with the one you stored and update your row. - Basic records keep their ID. A vehicle first seen on a plate can start as a basic record (make, model, years and engine size) and keeps the same ID when its full record arrives.
What you need
Plate lookups work on every plan, including the free tier. The vehicle database, used for the one-off mapping and for make/model/year dropdowns, is on Starter ($79/month) and above, and its requests do not count toward your lookup quota. The vehicle database reference has the full SKU-linking section, and the lookup reference documents vehicle_id and match field by field.
PlateAPI turns Australian number plates into structured vehicle data -- one REST endpoint, all eight states, free tier included.