Dutch Address Lookup API: BAG postcode, geocode & building data
Coming soon to the StoreChecks and geocodes Dutch addresses against the BAG, the official Dutch register of addresses and buildings (Kadaster, served by PDOK). Each address comes back normalised with its postcode, BAG ids, WGS84 and RD coordinates, and building details: construction year, use, floor area, status and number of units. Built for AI agents doing real estate, logistics, KYC/KYB, insurance or local-business tasks, and for people cleaning address lists.
Pricing (pay per event): $0.002 per resolved address. Inputs that don't resolve to one address (ambiguous, not found, invalid) are returned too, free of charge.
Questions agents ask
- “Is 'Damrak 1 Amsterdam' a valid address? Give me its postcode, building year, use and floor area, with the source.”
Example
Input
{ "addresses": ["Damrak 1 Amsterdam", "Coolsingel 40, 3011AD Rotterdam", "1012LG 1", "Damrak 18-1 Amsterdam"] }Output
{
"schema_version": "1",
"input": "Damrak 1 Amsterdam",
"input_type": "address",
"resolved": true,
"match_quality": "exact",
"match_score": 11.179252,
"address": {
"display_name": "Damrak 1, 1012LG Amsterdam",
"street": "Damrak",
"house_number": 1,
"house_letter": null,
"house_number_addition": null,
"postcode": "1012LG",
"city": "Amsterdam",
"municipality": "Amsterdam",
"municipality_code": "0363",
"province": "Noord-Holland"
},
"bag_ids": {
"nummeraanduiding_id": "0363200012113669",
"verblijfsobject_id": "0363010012111931",
"object_type": "verblijfsobject",
"pand_ids": ["0363100012185508"]
},
"coordinates": {"lat": 52.37714446, "lon": 4.89803846, "rd_x": 121691.143, "rd_y": 487809.576},
"building": {
"object_type": "verblijfsobject",
"object_id": "0363010012111931",
"object_status": "Verblijfsobject in gebruik",
"use_purposes": ["bijeenkomstfunctie", "logiesfunctie"],
"floor_area_m2": 16100,
"construction_year": 1890,
"building_status": "Pand in gebruik",
"units_in_building": 5,
"pands": [
{
"pand_id": "0363100012185508",
"construction_year": 1890,
"status": "Pand in gebruik",
"units_in_building": 5,
"use_purposes": ["bijeenkomstfunctie", "logiesfunctie", "winkelfunctie"],
"source_url": "https://api.pdok.nl/kadaster/bag/ogc/v2/collections/pand/items?f=json&identificatie=0363100012185508"
}
],
"source_url": "https://api.pdok.nl/kadaster/bag/ogc/v2/collections/verblijfsobject/items?f=json&identificatie=0363010012111931"
},
"candidates": [],
"warnings": [],
"source_url": "https://api.pdok.nl/bzk/locatieserver/search/v3_1/free?q=*:*&fq=nummeraanduiding_id:0363200012113669&fl=*",
"retrieved_at": "2026-11-05T22:43:17+00:00"
}What you get
| Field | Type | Meaning |
|---|---|---|
schema_version | string | Output schema version. |
input | string | The input as given: a free-text address, 'POSTCODE number(-to) addition' for postcode queries, or a BAG id. |
input_type | string | Which input this row answers: address (free text), postcode, or bag_id. |
resolved | boolean | true = one BAG address (or, for a pand id, one building) was found; only these rows are charged. |
match_quality | string | exact: every part of the input agrees with the BAG; probable: one address fits but part of the input differs or is missing (see warnings); ambiguous: several addresses fit (see candidates); not_found: no BAG address fits; invalid_input: not a valid BAG id; source_error: PDOK did not answer. |
match_score | number | null | PDOK Locatieserver relevance score for free-text matches (relative within one query, higher is better); null for postcode and BAG id lookups. |
address | object | null | The normalised BAG address. null when not resolved or 'address' is not in include. |
bag_ids | object | BAG identifiers of the address. Always present; values null when not resolved. |
coordinates | object | null | Point of the address (centroid of the unit). null when not resolved or 'coordinates' not in include. |
building | object | null | The BAG object and the building(s) it lies in. null when not resolved, 'building' not in include, or the BAG OGC API failed (see warnings). |
candidates | array | For ambiguous or not_found rows: up to 3 nearest BAG addresses (display_name, postcode, nummeraanduiding_id, score). Re-run with one of them, or its id in bagIds. Empty when resolved. |
warnings | array | Caveats and failures in plain words an agent can relay; the rest of the row is still valid. |
source_url | string | null | PDOK record the address (or, for a pand id, the building) was read from; null when not resolved. |
retrieved_at | string | When the row was made (ISO 8601, UTC). |
Use with AI agents (MCP)
Add this URL to your MCP client (Claude, Cursor, VS Code, ...) to load the Actor as a tool through the Apify hosted MCP server. It signs you in with OAuth or accepts Authorization: Bearer <APIFY_TOKEN>. It works once the Actor is live on the Apify Store.
https://mcp.apify.com?tools=bosco_labs/dutch-address-lookup
For “Is 'Damrak 1 Amsterdam' a valid address? Give me its postcode, building year, use and floor area, with the source.” the agent passes:
{ "addresses": ["Damrak 1 Amsterdam"] }
Or call the Apify API: POST https://api.apify.com/v2/acts/bosco_labs~dutch-address-lookup/run-sync-get-dataset-items with the input as JSON body. Cost: $0.002 per resolved address.
Input fields
| Field | Type | Meaning |
|---|---|---|
addresses | array | Dutch addresses to check and geocode, one per line, as people write them: street + house number (+ letter or addition) + city, and/or postcode + house number, e.g. "Damrak 1 Amsterdam", "Dam 5B Amsterdam", "Damrak 18-1 Amsterdam", "Coolsingel 40, 3011AD Rotterdam", "1012LG 1". Up to 100 (together with bagIds); repeats are looked up once. One output row per address. Empty = use postcode or bagIds. |
postcode | string | A Dutch postcode, 4 digits + 2 letters, e.g. "1012JS" or "1012 JS". Alone it lists every address in that postcode (one row each, up to 100); with houseNumber it returns that address, with houseNumber + houseNumberTo every address in that range. Empty = not used. |
houseNumber | integer | House number within postcode, e.g. 1. Only used with postcode. Empty = all numbers in the postcode. |
houseNumberTo | integer | Last house number of a range starting at houseNumber, inclusive, e.g. 20 for 1-20. Needs postcode and houseNumber. Empty = only houseNumber. |
houseNumberAddition | string | House letter and/or addition for a single houseNumber, e.g. "B" (5B), "1" (18-1), "H" (8-H), "A2" (1A-2). Empty = all units at that number (one row each). |
bagIds | array | 16-digit BAG identifiers: nummeraanduiding (address, e.g. "0363200012113669"), verblijfsobject (unit, "0363010012111931"), ligplaats/standplaats (berth/pitch) or pand (building, "0363100012185508": building details only, no address). Up to 100 together with addresses. Empty = not used. |
include | array | Which sections to fill: any of "address" (street, postcode, city, municipality, province), "building" (construction year, use purposes, floor area, status, units in the building), "coordinates" (WGS84 + RD New), e.g. ["address", "coordinates"]. BAG ids are always returned. Default (or empty) = all three. Without "building" the run is faster; the price is the same. |
Sources, licence and limits
Where does the data come from? From the BAG (Basisregistratie Adressen en Gebouwen), kept by the municipalities and published by Kadaster. Addresses come from the PDOK Locatieserver and buildings from the PDOK BAG OGC API. Both are updated daily. Each row's source_url points to the PDOK record it was read from.
What is not included? This lookup does not include:
- WOZ (tax) values, energy labels, prices or rents.
- Owners, residents or any other personal data.
- Cadastral parcels, building footprints/polygons, neighbourhood statistics.
- Addresses outside the Netherlands.
floor_area_m2 is the BAG gebruiksoppervlakte of one unit. It is not the plot size and not the full building.
Why is a valid-looking address ambiguous? Usually the number has several units (5A, 5B, 18-1, 18-H) and no letter or addition was given, or the same street and number exist in several places and no city or postcode was given. Add it, or use a candidate's nummeraanduiding_id in bagIds.
Why is construction_year odd sometimes? Construction years are as registered by the municipality. Very old buildings often carry an estimated year (e.g. 1600, 1850).
Are demolished buildings or withdrawn addresses returned? Address search covers current BAG addresses. A pand id of a demolished building still returns its record, with building_status "Pand gesloopt".
Limits?
- 100 addresses + BAG ids per run, and up to 100 addresses per postcode query. A larger postcode result says so in
warnings; narrow the house number range. - PDOK is a free best-effort service. If it does not answer, rows are marked
source_errorand not charged.
Licence and attribution. BAG data: Kadaster, Public Domain Mark 1.0, served by PDOK. No endorsement by Kadaster or PDOK is implied. See LEGAL.md.