# License plate API for format validation

> A license plate format API: POST a registration and a country or state code, get back valid or not, the matching series, the as-issued spelling and why it fails. Free key.

Page: https://vehiclesdb.com/license-plates/api · Markdown version of the HTML page, which is canonical. Site map: https://vehiclesdb.com/llms.txt · Terms of use: https://vehiclesdb.com/legal/terms

**The VehiclesDB plates API checks a license plate number against the formats the issuing authority actually uses.** You send a registration and a country or state code; it answers whether the plate is valid there, which registration series it belongs to (standard, motorcycle, diplomatic, dealer…), how the authority writes it, and, when it fails, why. It's for the form, the parking app, the fleet import or the ALPR pipeline that needs to know "is this a plate that can exist?" before trusting it.

## What it covers

The plates API covers **127 jurisdictions and 1,409 registration series**: 50 countries, plus the 56 US states and territories, 13 Canadian provinces and territories, and 8 Australian states and territories that issue their own plates. Every series carries its format, the years it was issued, the vehicles it's issued to and the colours its source states. You can browse all of them for free on the [license plates pages](https://vehiclesdb.com/license-plates).

Each format is recorded with its source (a regulation, the authority's own documents or, where those are silent, a flagged secondary source), and the sources are listed on that jurisdiction's page. Where a country has changed systems over the years, the old series are there too, with their dates, so an older car's plate still validates.

## Check one plate

`POST /api/v1/plates/{code}/match` takes the registration in a JSON body. `{code}` is a country (`es`, `de`, `nl`) or a state or province (`us-ca`, `ca-on`, `au-nsw`), and it isn't case sensitive.

```bash
curl -X POST "https://vehiclesdb.com/api/v1/plates/es/match" \
  -H "Authorization: Bearer vdb_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"plate": "1234 BCD"}'
```

A Spanish plate typed exactly as it's issued comes back like this:

`{ "plate": "1234 BCD", "jurisdiction": { "code": "es", "name": "Spain", "country": "Spain", "authority": "Dirección General de Tráfico (DGT) — Reglamento General de Vehículos, RD 2822/1998, Anexo XVIII", "series_count": 19 }, "valid": true, "exact": true, "as_issued": null, "strict": true, "reason": "ok", "excluded_letters": [], "passenger": true, "matches": [ { "id": "es-national-2000", "class": "standard", "pattern": "9999 LLL", "period": { "start": 2000 }, "categories": [ "car", "van", "truck", "bus", "motorcycle" ], "passenger": true, "background": "#FFFFFF", "foreground": "#000000", "render_url": "https://vehiclesdb.com/plates/es/es-national-2000.svg", "template_url": "https://vehiclesdb.com/plates/es/es-national-2000/template.svg" } ], "near_misses": [], "attribution": { "source": "VehiclesDB", "url": "https://vehiclesdb.com", "license": "Identity layer: CC-BY-4.0; enrichment/resolution: proprietary. Display requires visible credit — see https://vehiclesdb.com/legal/attribution", "dataset_version": "2026.11.9" } }`

The fields that matter most:

- **`valid`**: the plate fits at least one format this place issues.
- **`exact`**: it was typed exactly as issued, separators included. When it wasn't, **`as_issued`** gives you the authority's own spelling to store or show.
- **`matches`**: every series whose format accepts it. There's often more than one, because standard, export and historic series can share a pattern; each comes with its class, years, vehicle categories and colours.
- **`reason`**: one code that says why, when the answer is no: `bad_shape` (no series has that shape), `excluded_letters` (the shape exists but the authority never issues those letters, and `excluded_letters` lists them) or `unverifiable` (only a catch-all series has the shape).
- **`passenger`**: a strict match is issued to a vehicle that carries people, not only to trailers or machinery. Handy for ride-sharing and rental forms.

## Typed without the dashes

People type plates however they like. The matcher has two tiers: **exact**, the plate as the authority prints it, and **lenient**, where separators are forgiven but the letters and digits never are. Here's a Dutch plate typed as `12GBBD`:

`{ "plate": "12GBBD", "jurisdiction": { "code": "nl", "name": "Netherlands", "country": "Netherlands", "authority": "RDW (Dienst Wegverkeer)", "series_count": 33 }, "valid": true, "exact": false, "as_issued": "12-GB-BD", "strict": true, "reason": "ok", "excluded_letters": [], "passenger": true, "matches": [ { "id": "nl-sidecode6-car", "class": "standard", "pattern": "99-LL-LL", "period": { "start": 2000 }, "categories": [ "car" ], "passenger": true, "background": "#F9B700", "foreground": "#000000", "render_url": "https://vehiclesdb.com/plates/nl/nl-sidecode6-car.svg", "template_url": "https://vehiclesdb.com/plates/nl/nl-sidecode6-car/template.svg" }, { "id": "nl-export", "class": "export", "pattern": "LLL-99-L", "period": { "start": 1951 }, "categories": [ "car", "van", "truck", "bus", "motorcycle", "moped", "trailer", "semitrailer", "tractor", "machine" ], "passenger": true, "background": "#FFFFFF", "foreground": "#000000", "render_url": "https://vehiclesdb.com/plates/nl/nl-export.svg", "template_url": "https://vehiclesdb.com/plates/nl/nl-export/template.svg" }, { "id": "nl-historic-darkblue-agricultural", "class": "historic", "pattern": "LLL-99-L", "period": { "start": 1978 }, "categories": [ "tractor", "machine", "trailer" ], "passenger": false, "background": "#1D2E5B", "foreground": "#FFFFFF", "render_url": "https://vehiclesdb.com/plates/nl/nl-historic-darkblue-agricultural.svg", "template_url": "https://vehiclesdb.com/plates/nl/nl-historic-darkblue-agricultural/template.svg" } ], "near_misses": [], "attribution": { "source": "VehiclesDB", "url": "https://vehiclesdb.com", "license": "Identity layer: CC-BY-4.0; enrichment/resolution: proprietary. Display requires visible credit — see https://vehiclesdb.com/legal/attribution", "dataset_version": "2026.11.9" } }`

`exact` is false and `as_issued` is `12-GB-BD`, the way the RDW writes it. Notice the three matches too: the same shape is a standard car plate, an export plate and a historic agricultural plate in the Netherlands, and the API tells you all three rather than guessing.

## Get every format for a country or state

`GET /api/v1/plates/{code}` returns a jurisdiction's whole series list in one call: each series' pattern (`L` a letter, `9` a digit), the years it ran, its vehicle categories and its colours where the source states them (`null` where it doesn't; the dataset doesn't guess). Use it to build your own input masks, hints or offline checks. A shortened example for Germany:

`{ "jurisdiction": { "code": "de", "name": "Germany", "country": "Germany", "authority": "Fahrzeug-Zulassungsverordnung (FZV) — Bundesministerium für Digitales und Verkehr", "series_count": 13 }, "series": [ { "id": "de-standard", "class": "standard", "pattern": "LL-LL 9999", "period": { "start": 1995 }, "categories": [ "car", "van", "truck", "bus", "motorcycle", "trailer" ], "passenger": true, "background": "#FFFFFF", "foreground": "#000000", "render_url": "https://vehiclesdb.com/plates/de/de-standard.svg", "template_url": "https://vehiclesdb.com/plates/de/de-standard/template.svg" }, { "id": "de-seasonal", "class": "seasonal", "pattern": "LL-LL 999", "period": { "start": 1997 }, "categories": [ "car", "van", "truck", "bus", "motorcycle", "trailer" ], "passenger": true, "background": "#FFFFFF", "foreground": "#000000", "render_url": "https://vehiclesdb.com/plates/de/de-seasonal.svg", "template_url": "https://vehiclesdb.com/plates/de/de-seasonal/template.svg" } ], "attribution": { "source": "VehiclesDB", "url": "https://vehiclesdb.com", "license": "Identity layer: CC-BY-4.0; enrichment/resolution: proprietary. Display requires visible credit — see https://vehiclesdb.com/legal/attribution", "dataset_version": "2026.11.9" } }`

## Plate images for your interface

Every series in a response carries a `render_url`, the plate's design as an SVG, and a `template_url`: the same design with an empty, fully described text area and no registration in it. The template is the privacy-safe one: you fill in your user's plate in your own page, so the registration never leaves your side. Plate images are priced per image; [create an account](https://vehiclesdb.com/get/plate_images?return_to=/license-plates/api) to see the prices.

## Start

1. [Create a free account](https://vehiclesdb.com/get/plate_validate?return_to=/license-plates/api) and mint a private key (`vdb_sk_…`) under Settings → API keys. Keep it on your server.
2. Send your first `POST /api/v1/plates/{code}/match` with one of the examples above.
3. The full contract, every parameter and error code, is in the [API reference](https://vehiclesdb.com/api), generated from the code that serves the requests.

Every account starts with 100 free credits and no card. A match costs 1 credit, a whole jurisdiction's format list 5 credits, and mistakes like an unknown country code are free. If you need more, the [pricing page](https://vehiclesdb.com/pricing) has the plans.

If you'd rather not call an API at all, the plate formats are in the [open dataset on GitHub](https://github.com/vehiclesdb/vehiclesdb) under CC BY 4.0, and the Ruby gem (`gem "vehicles"`) runs the same matcher offline. For physical plate sizes there's a separate guide to [license plate dimensions](https://vehiclesdb.com/license-plates/dimensions).

---

Open data, CC BY 4.0: reuse it with a visible credit to VehiclesDB and a link (https://vehiclesdb.com/legal/attribution). Plate images show sample serials and are not open data (https://vehiclesdb.com/legal/image-license). Dataset commit db0ec0a: https://github.com/vehiclesdb/vehiclesdb
