Adresse or adgangsadresse? The data model

Understand the difference between adresse and adgangsadresse, their ids and kvh/kvhx keys, how autocomplete's type relates to them, and which id to store.

4 min Level: Beginner ✓ Code tested

Danish addresses exist on two levels: the adgangsadresse (access address) is the door onto the street, and the adresse is the single dwelling or unit behind that door. Both have their own id and their own endpoint. Mix them up and you get 404 or empty lists, so it pays to get the difference straight from the start.

The two concepts

Adgangsadresse (access address)Adresse (unit)
What is it?An entrance: street name, house number and postcodeA unit: access address plus floor and door
ExampleRådhuspladsen 1, 4200 SlagelseRådhuspladsen 1, st. th, 4200 Slagelse
Endpoint/adgangsadresser, /adgangsadresser/{id}/adresser, /adresser/{id}
CoordinateYes, adgangspunkt.koordinaterInherits the access address's
Keykvh (12 characters)kvhx (19 characters)

A stairwell in a block of flats is one access address with many addresses, one per flat. A detached house is typically one access address with one address whose etage (floor) and dør (door) are null. Data about the building (BBR, cadastre, municipality, parish, coordinate) belongs to the access address. Data about the single dwelling (for example the BBR unit) belongs to the address.

The ids

Both ids are UUIDs, and they are different. An address response contains the access address as an embedded object, so you get both ids in one call:

JSON#adresse-shape
{
  "id": "0a3f50ae-b4ee-32b8-e044-0003ba298018",
  "kvhx": "03301407___1_st__th",
  "etage": "st",
  "dør": "th",
  "adressebetegnelse": "Rådhuspladsen 1, st. th, 4200 Slagelse",
  "adgangsadresse": {
    "id": "0a3f5084-62c3-32b8-e044-0003ba298018",
    "kvh": "03301407___1",
    "husnr": "1",
    "adressebetegnelse": "Rådhuspladsen 1, 4200 Slagelse",
    "adgangspunkt": {"koordinater": [11.35623868, 55.40464424]}
  }
}

The response is shortened. In struktur=flad, struktur=mini and in the autocomplete suggestions' data, the access address's id is called adgangsadresseid.

Fetch an address and every other address behind the same door:

Python#same-building
import os
import requests

API = "https://api.danadresse.dk"
headers = {"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}

r = requests.get(f"{API}/adresser/0a3f50ae-b4ee-32b8-e044-0003ba298018",
                 headers=headers, timeout=10)
r.raise_for_status()
adresse = r.json()
adgang = adresse["adgangsadresse"]
print("adresse id:       ", adresse["id"], "kvhx", adresse["kvhx"])
print("adgangsadresse id:", adgang["id"], "kvh ", adgang["kvh"])

r = requests.get(f"{API}/adresser",
                 params={"adgangsadresseid": adgang["id"], "struktur": "mini"},
                 headers=headers, timeout=10)
r.raise_for_status()
for unit in r.json():
    print(" -", unit["betegnelse"])

kvh and kvhx

Before the UUIDs, addresses were identified by codes. Many older systems still store them, and the API can look them up:

  • kvh (12 characters) = municipality code (4) + street code (4) + house number (4, padded with leading _). 03301407___1 is municipality 0330, street 1407, house number 1.
  • kvhx (19 characters) = kvh + floor (3, padded with leading _) + door (4, padded with leading _). 03301407___1_st__th is the ground floor, right-hand door.
Shell#kvh-lookup
curl -s "https://api.danadresse.dk/adgangsadresser?kvh=03301407___1" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"

For a specific unit, use /adresser?kvhx=03301407___1_st__th. A kvh that is not 12 characters gives 400 with the code invalid_kvh. A kvhx that is not 19 characters gives invalid_kvhx.

The street code is only unique within a municipality, and house numbers can be renumbered. Use kvh and kvhx to match old data, and store the UUID from then on.

Autocomplete and type

/autocomplete works in three steps while the user types: first street names, then house numbers (access addresses), then floors and doors (addresses). Each suggestion has a type field, and the meaning of data.id depends on it:

type in the suggestiondata.id isLook up with
vejnavnno id, only data.navnKeep typing
adgangsadressethe access address's id/adgangsadresser/{id}
adressethe address's id. data.adgangsadresseid is the access address's/adresser/{id}

The type parameter locks the step:

  • type=adresse always returns addresses (units), even when the user has only typed street and house number.
  • type=adgangsadresse stops at the house number and never asks for floor and door. adgangsadresserOnly=true does the same.
  • type=vejnavn returns street names only.

Always read type on the chosen suggestion before using data.id. Without type in the call, the same field can hold an access address id one moment and an address id the next.

The wrong id on the wrong endpoint

The ids are not interchangeable. An access address id on /adresser/{id} gives:

JSON#wrong-endpoint
{
  "type": "ResourceNotFoundError",
  "title": "Adresse 0a3f5084-62c3-32b8-e044-0003ba298018 not found",
  "details": null,
  "code": "not_found"
}

The other way round the API is more forgiving: an address id on /adgangsadresser/{id} answers with the access address the unit belongs to. The response's id is then the access address's id, not the id you sent.

On lists the wrong id gives an empty list: /adresser?id=<access address id> finds nothing. Use /adresser?adgangsadresseid=<id> to find the units behind a door.

The enrichment endpoints under /api/v1/enrich/adresser/{id}/… accept both kinds of id. An address id is looked up on the access address it belongs to, so dagi, bbr and climate, for example, give the same answer for every flat behind the same door.

Which id should you store?

You need the address forStore
Delivery, invoicing, a specific flatThe address's id
Maps, distance, municipality, parish, BBR, cadastreThe access address's id
A customer register where you do not know whichBoth, and which type the user chose

Also store the address text (adressebetegnelse) as it was when the user chose it. Addresses can be renamed or retired, and then it helps to know what it said. More in Store the address id and status, darstatus and retired addresses.

Next steps

Related guides

Markdown source Spotted an error? Tell us API-reference (Swagger)

Try it with a free key

2,000 calls/month on the free plan. No credit card.

Create account →