Bosco Labs

Tools › Macro, health & places

Dutch Address Lookup API: BAG postcode, geocode & building data

Coming soon to the Store

Checks 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.

Price$0.002 per resolved address
DomainMacro, health & places
Call itApify API or MCP

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.

Coming soon to the Apify StoreAsk for early access

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

FieldTypeMeaning
schema_versionstringOutput schema version.
inputstringThe input as given: a free-text address, 'POSTCODE number(-to) addition' for postcode queries, or a BAG id.
input_typestringWhich input this row answers: address (free text), postcode, or bag_id.
resolvedbooleantrue = one BAG address (or, for a pand id, one building) was found; only these rows are charged.
match_qualitystringexact: 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_scorenumber | nullPDOK Locatieserver relevance score for free-text matches (relative within one query, higher is better); null for postcode and BAG id lookups.
addressobject | nullThe normalised BAG address. null when not resolved or 'address' is not in include.
bag_idsobjectBAG identifiers of the address. Always present; values null when not resolved.
coordinatesobject | nullPoint of the address (centroid of the unit). null when not resolved or 'coordinates' not in include.
buildingobject | nullThe 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).
candidatesarrayFor 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.
warningsarrayCaveats and failures in plain words an agent can relay; the rest of the row is still valid.
source_urlstring | nullPDOK record the address (or, for a pand id, the building) was read from; null when not resolved.
retrieved_atstringWhen 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

FieldTypeMeaning
addressesarrayDutch 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.
postcodestringA 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.
houseNumberintegerHouse number within postcode, e.g. 1. Only used with postcode. Empty = all numbers in the postcode.
houseNumberTointegerLast house number of a range starting at houseNumber, inclusive, e.g. 20 for 1-20. Needs postcode and houseNumber. Empty = only houseNumber.
houseNumberAdditionstringHouse 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).
bagIdsarray16-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.
includearrayWhich 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_error and 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.

Coming soon to the Apify StoreAsk for early access