Move from DAWA by changing the base URL
Move an existing DAWA integration to Danadresse with a new base URL and a key, check it with a smoke-test script, and know the known differences.
DAWA closed on 1 October 2026 at 10:00, and dawa.aws.dk and api.dataforsyningen.dk now answer with errors. Danadresse has the same paths, parameters and JSON fields, so for most integrations the migration is two changes: a new domain and an API key.
This guide shows how to make the domain configurable, how to check the switch with a small script, and where our API differs from DAWA today.
1. Change the domain and add a key
| Before | After |
|---|---|
https://dawa.aws.dk | https://api.danadresse.dk |
https://api.dataforsyningen.dk | https://api.danadresse.dk |
| no key | header X-Api-Key: <your key> |
The path after the domain does not change. https://api.dataforsyningen.dk/adresser?postnr=8000 becomes https://api.danadresse.dk/adresser?postnr=8000. The DAWA endpoints live at the root, without /api/v1.
Create a key under Keys. Every call needs a key; without one you get 401 with the code missing_api_key. If you cannot send a header (for example from a spreadsheet or a <script src>), the key can go in the URL as ?api_key=. See Header or api_key in the URL for when that is acceptable.
If many files contain DAWA URLs, migrate-cli can find and replace them for you.
2. Make the base URL configurable
Do not hard-code the domain again. Read it from configuration with https://api.danadresse.dk as the default. Then you can point at a test proxy, a mock in your tests, or another provider without touching the code.
Python:
import os import requests BASE_URL = os.environ.get("DANADRESSE_BASE_URL", "https://api.danadresse.dk").rstrip("/") session = requests.Session() session.headers["X-Api-Key"] = os.environ["DANADRESSE_API_KEY"] def get_address(address_id: str) -> dict: r = session.get(f"{BASE_URL}/adresser/{address_id}", timeout=10) r.raise_for_status() return r.json()
Node 18 or newer:
const BASE_URL = (process.env.DANADRESSE_BASE_URL ?? "https://api.danadresse.dk").replace(/\/$/, ""); const API_KEY = process.env.DANADRESSE_API_KEY; export async function getAddress(id) { const res = await fetch(`${BASE_URL}/adresser/${id}`, { headers: { "X-Api-Key": API_KEY }, }); if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`); return res.json(); }
PHP:
<?php $baseUrl = rtrim(getenv('DANADRESSE_BASE_URL') ?: 'https://api.danadresse.dk', '/'); $apiKey = getenv('DANADRESSE_API_KEY'); function getAddress(string $baseUrl, string $apiKey, string $id): array { $ch = curl_init("$baseUrl/adresser/" . rawurlencode($id)); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["X-Api-Key: $apiKey"], CURLOPT_TIMEOUT => 10, ]); $body = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); curl_close($ch); if ($status !== 200) { throw new RuntimeException("HTTP $status: $body"); } return json_decode($body, true); }
In .NET, put the values in appsettings.json and the key in user secrets or an environment variable:
{
"Danadresse": {
"BaseUrl": "https://api.danadresse.dk"
}
}builder.Services.AddHttpClient("danadresse", client => { client.BaseAddress = new Uri(builder.Configuration["Danadresse:BaseUrl"]!); client.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("DANADRESSE_API_KEY")); });
3. Run a smoke test
A smoke test calls the endpoints your code uses and checks the status and one field you read. Run it after the switch and again in CI. This script makes five calls:
import os import requests BASE_URL = os.environ.get("DANADRESSE_BASE_URL", "https://api.danadresse.dk").rstrip("/") session = requests.Session() session.headers["X-Api-Key"] = os.environ["DANADRESSE_API_KEY"] # (path, parameters, one field your code reads) CHECKS = [ ("/autocomplete", {"q": "Rådhuspladsen 1", "per_side": 1}, "forslagstekst"), ("/adresser/0a3f50ae-b4ee-32b8-e044-0003ba298018", {}, "adressebetegnelse"), ("/adgangsadresser/reverse", {"x": 12.5683, "y": 55.6761}, "adressebetegnelse"), ("/postnumre/8000", {}, "navn"), ("/datavask/adresser", {"betegnelse": "Strandvejen 100, 2900 Hellerup"}, "kategori"), ] failed = 0 for path, params, field in CHECKS: r = session.get(BASE_URL + path, params=params, timeout=10) ok = r.status_code == 200 and field in r.text failed += 0 if ok else 1 print(f"{'OK ' if ok else 'FAIL'} {r.status_code} {path}") print("All checks passed" if failed == 0 else f"{failed} checks failed") raise SystemExit(1 if failed else 0)
Expected output:
OK 200 /autocomplete OK 200 /adresser/0a3f50ae-b4ee-32b8-e044-0003ba298018 OK 200 /adgangsadresser/reverse OK 200 /postnumre/8000 OK 200 /datavask/adresser All checks passed
Add the parameters you use yourself (struktur, srid, format, filters). A parameter we do not know is ignored without an error, so also check that the response has the shape you expect – for example that a filter actually narrowed the result.
4. What differs from DAWA
| Area | DAWA | Danadresse |
|---|---|---|
| Key | None | Required. 401 missing_api_key without one, 401 invalid_api_key for a wrong or revoked key |
| Limits | None fixed | Monthly quota and a per-minute limit. See Limits, quotas and 429 |
| Error format | {"type","title","details"} | Same fields plus code, e.g. "code": "missing_api_key", on every error including 500. See The error format |
href fields | Pointed at DAWA | Point at https://api.danadresse.dk |
| Codes | Zero-padded ("0101", "0800") | The same. Input may be un-padded: kommunekode=101 works |
srid | 4326 and 25832 | The same. Other values give 400 QueryParameterFormatError |
/replikering/udtraek | Streamed JSON array | The same. Add &ndjson for one JSON line per object |
5. Known gaps
Most of DAWA's contract is covered: the endpoints (including /historik/*, naboer, /bebyggelser, /stednavne2 and /vejnavnpostnummerrelationer), both replication forms, format=csv|geojson|geojsonz and JSONP. These values are empty today because we have no source for them. The current list is on Compatibility.
- Fields on adgangsadresser: the keys are all there, but
vejpunkthas no coordinates ([]),bebyggelseris an empty list,brofastisnull, and inadgangspunktthe fieldsid,kilde,tekstretningandændretarenull. bboxandvisueltcenter: empty lists on several area and street endpoints, for example/regioner,/vejstykkerand/navngivneveje.
Address lookup, autocomplete, datavask and reverse geocoding are not affected. If you rely on one of these values, tell us through support with the endpoint and field you need.
Next steps
- Used DAWA's widget? From dawa-autocomplete2.
- Wrote your own autocomplete? Hand-built DAWA autocomplete.
- Do you store address ids? Read status, darstatus and retired addresses.
Related guides
Markdown source Spotted an error? Tell us API-reference (Swagger)