Key
Every call needs your key in the Authorization header as a Bearer token. The key is secret: use it from your own server, never in code that runs in the browser.
Authorization: Bearer YOUR_KEY Endpoints
GET /v1/plates/{country}/{plate}
Looks up a number plate. country is DK or NL. Upper or lower case, spaces and dashes in the plate do not matter.
GET /v1/catalog/{country}/makes
Every make in a country with its number of vehicles, most first. country is dk, nl, fi or all (the sum of the countries). Finland is in the catalogue only, not in lookups. Slugs are the same in every country.
GET /v1/catalog/{country}/makes/{make_slug}/models
Every model of a make, gathered across the registers, so ID.3 and ID.3 Pro 150 kW are one model. make_slug is the slug from the list of makes. A country only shows models with vehicles in that country.
Without ?type= the catalogue shows cars and vans (car,van). You can give one or more vehicle types separated by commas, e.g. ?type=motorcycle. The catalogue only has car, van and motorcycle, and a model needs at least 100 vehicles in total. The response may be cached for a day.
Catalogue response
[
{ "name": "Volkswagen", "slug": "volkswagen", "count": 312456 },
{ "name": "Toyota", "slug": "toyota", "count": 254321 },
…
] Fields
The response always has every field. A field with no value is null. Text fields are in the language of the source (Danish from the Danish Motor Register, Dutch from RDW), while the _code fields are the same for both countries. Dates are YYYY-MM-DD. We never provide information about the owner.
| Field | Type | Example | Countries | Description |
|---|---|---|---|---|
country | string | "DK" | DK · NL | The country from the address: DK or NL. |
plate | string | "AB12345" | DK · NL | The number plate in capitals, without spaces or dashes. |
make | string | "Volkswagen" | DK · NL | Make. |
model | string | "Golf" | DK · NL | Model. |
variant | string | "1.5 TSI EVO 150 DSG7" | DK | Variant, as written in the register. |
make_slug | string | "volkswagen" | DK · NL | The make as a slug, as in the register. |
model_slug | string | "golf" | DK · NL | The model as a slug, as in the register. |
catalog_make_slug | string | "volkswagen" | DK · NL | The make in the catalogue. null if the make is not in the catalogue. |
catalog_model_slug | string | "golf" | DK · NL | The model in the catalogue, e.g. id-3 for an ID.3 Pro 150 kW. null if the model is not in the catalogue. |
vehicle_type | string | "Personbil" | DK · NL | Vehicle type in the language of the source. |
vehicle_type_code | string | "car" | DK · NL | Vehicle type as a code. See the codes below. |
body_type | string | "Stationcar" | DK · NL | Body type in the language of the source. |
colour | string | "Rød" | DK · NL | Colour in the language of the source. |
colour_code | string | "red" | DK · NL | Colour as a code. |
doors | integer | 5 | DK · NL | Number of doors. |
seats | integer | 5 | DK · NL | Number of seats, including the driver. |
fuel | string | "Benzin" | DK · NL | Fuel in the language of the source. |
fuel_code | string | "petrol" | DK · NL | Fuel as a code. Hybrids are told apart from plug-in hybrids. |
power_kw | number | 110 | DK · NL | Engine power in kW. Multiply by 1.36 for metric horsepower. |
engine_volume_cc | integer | 1498 | DK · NL | Engine capacity in cm³. |
cylinders | integer | 4 | DK · NL | Number of cylinders. |
kerb_weight_kg | integer | 1310 | DK · NL | Kerb weight in kg. Rarely filled in for Danish cars. |
total_weight_kg | integer | 1830 | DK · NL | Permitted total weight in kg. |
towbar | boolean | true | DK | Whether the vehicle is registered with a towbar. |
max_trailer_weight_kg | integer | 1500 | DK · NL | Maximum braked trailer weight in kg. |
max_trailer_weight_unbraked_kg | integer | 670 | DK · NL | Maximum unbraked trailer weight in kg. |
status | string | "Registreret" | DK | Registration status. |
usage | string | "Privat personkørsel" | DK | Usage. |
first_registration | date | "2019-04-25" | DK · NL | First registration. |
model_year | integer | 2019 | DK | Model year. |
vin | string | "WVWZZZAUZKP000000" | DK | Vehicle identification number (VIN). |
euro_norm | string | "Euro VI" | DK · NL | Euro emission standard. |
co2_g_km | number | 116 | DK · NL | CO₂ emissions in g/km. |
last_inspection | date | "2025-04-01" | DK | Date of the latest inspection. |
next_inspection | date | "2027-04-25" | NL | When the APK (MOT) expires. Netherlands only. |
odometer_km | integer | 77000 | DK | Odometer reading at the latest inspection. |
odometer_date | date | "2025-04-01" | DK | Date of the odometer reading. |
source | string | "dmr" | DK · NL | dmr (Danish Motor Register) or rdw (RDW). |
data_date | date | "2026-11-01" | DK · NL | The date of the data the response is based on. |
Example response
{
"country": "DK",
"plate": "AB12345",
"make": "Volkswagen",
"model": "Golf",
"variant": "1.5 TSI EVO 150 DSG7",
"make_slug": "volkswagen",
"model_slug": "golf",
"catalog_make_slug": "volkswagen",
"catalog_model_slug": "golf",
"vehicle_type": "Personbil",
"vehicle_type_code": "car",
"body_type": "Stationcar",
"colour": "Rød",
"colour_code": "red",
"doors": 5,
"seats": 5,
"fuel": "Benzin",
"fuel_code": "petrol",
"power_kw": 110,
"engine_volume_cc": 1498,
"cylinders": 4,
"kerb_weight_kg": null,
"total_weight_kg": 1830,
"towbar": true,
"max_trailer_weight_kg": 1500,
"max_trailer_weight_unbraked_kg": 670,
"status": "Registreret",
"usage": "Privat personkørsel",
"first_registration": "2019-04-25",
"model_year": 2019,
"vin": "WVWZZZAUZKP000000",
"euro_norm": "Euro VI",
"co2_g_km": 116,
"last_inspection": "2025-04-01",
"next_inspection": null,
"odometer_km": 77000,
"odometer_date": "2025-04-01",
"source": "dmr",
"data_date": "2026-11-01"
} Codes
The code fields always have one of these values, so you can sort without translating. If we do not know the value, the code is other.
vehicle_type_code | car, van, truck, bus, motorcycle, moped, trailer, caravan, tractor, other |
|---|---|
fuel_code | petrol, diesel, electric, hybrid_petrol, hybrid_diesel, plugin_hybrid, lpg, cng, hydrogen, other |
colour_code | black, white, grey, silver, blue, red, green, yellow, orange, brown, beige, purple, other |
Error codes
On an error you get an HTTP status code and a JSON response with the field error. Errors do not count as lookups.
{ "error": "not_found" } | Status | error | Meaning |
|---|---|---|
| 400 | unsupported_country | The country is neither DK nor NL (in the catalogue: dk, nl, fi or all). |
| 400 | invalid_type | A code in ?type= does not exist (catalogue only). |
| 401 | unauthorized | The key is missing, wrong or disabled. |
| 403 | key_paused | The key is paused because of unusual usage. The response has a message. Write to kontakt@platerunner.dk. |
| 404 | not_found | The number plate is not in the register. |
| 429 | rate_limited | More than 20 calls per second. Wait the number of seconds in Retry-After. |
| 429 | monthly_limit_reached | This month’s lookups are used. Buy an extra package or a bigger plan. |
| 502 | upstream_unavailable | RDW is not responding right now (Netherlands only). Try again shortly. |
| 503 | catalog_unavailable | The catalogue is temporarily unavailable. Try again shortly. |
| 503 | dk_data_unavailable | The Danish data is temporarily unavailable. Try again shortly. |
Limits
- At most 20 calls per second per key. Above that, the API answers 429 rate_limited with a Retry-After header.
- The number of lookups per month depends on your plan. Free gives 3,000. The month is the calendar month in UTC.
- Only successful lookups count. A catalogue call counts as one lookup.
- We email you when 80 % and 100 % of the month's lookups are used.
- When the month's lookups are used, the API answers 429 monthly_limit_reached until the month changes, or until you buy an extra package or a bigger plan.
Every response from /v1/plates and /v1/catalog with a valid key, errors included, has three headers with this month's usage:
| Header | Example | Meaning |
|---|---|---|
X-Lookups-Used | 1234 | Lookups used this month, this call included. |
X-Lookups-Limit | 15000 | The month’s limit including extra packages. unlimited on Unlimited. |
X-Lookups-Reset | 2026-12-01 | The first day of next month (UTC), when the lookups start over. |
Examples
The examples read the key from the environment variable PLATERUNNER_KEY.
curl
curl https://api.platerunner.dk/v1/plates/DK/AB12345 \
-H "Authorization: Bearer YOUR_KEY" JavaScript
const response = await fetch('https://api.platerunner.dk/v1/plates/DK/AB12345', {
headers: { Authorization: `Bearer ${process.env.PLATERUNNER_KEY}` },
});
if (response.status === 404) {
// The plate is not in the register
} else if (!response.ok) {
const { error } = await response.json();
throw new Error(error);
}
const vehicle = await response.json();
console.log(vehicle.make, vehicle.model, vehicle.power_kw); PHP
<?php
$ch = curl_init('https://api.platerunner.dk/v1/plates/DK/AB12345');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('PLATERUNNER_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$vehicle = json_decode($body, true);
if ($status === 200) {
echo $vehicle['make'] . ' ' . $vehicle['model'];
} else {
echo 'Error: ' . $vehicle['error'];
} Python
import os
import requests
response = requests.get(
"https://api.platerunner.dk/v1/plates/DK/AB12345",
headers={"Authorization": f"Bearer {os.environ['PLATERUNNER_KEY']}"},
timeout=10,
)
if response.status_code == 200:
vehicle = response.json()
print(vehicle["make"], vehicle["model"], vehicle["power_kw"])
else:
print("Error:", response.json()["error"])