getaddress-dk-api
v1.2.0
Published
TypeScript client for getaddress.dk, the DAWA-compatible Danish address API: autocomplete, adresser, adgangsadresser, reverse geocoding, vejnavne, postnumre, datavask, companies (CVR) and usage. DAWA's paths, parameters, field names and ids.
Maintainers
Readme
getaddress-dk-api
TypeScript client for getaddress.dk, the DAWA-compatible Danish address API — every address in Denmark, from the Danish Address Register (DAR). DAWA's paths, parameters, field names and ids. No dependencies; Node 18+ and every modern browser. Types included.
npm install getaddress-dk-apiUsage
On your server, with your API key:
import Client from 'getaddress-dk-api';
const api = new Client('your-api-key');
// Suggestions as text only: free.
const autocompleteResult = await api.adresserAutocomplete('Amagerbrogade 217A', { kun_tekst: true });
if (autocompleteResult.isSuccess) {
const picked = autocompleteResult.toSuccess()[0]; // the one the user chose
// The address picked: one look-up.
const getResult = await api.adresse(picked.adresse, { struktur: 'mini' });
if (getResult.isSuccess) {
const adresse = getResult.toSuccess();
console.log(adresse.vejnavn, adresse.husnr, adresse.etage, adresse['dør'], adresse.postnr, adresse.postnrnavn);
}
} else {
const failed = autocompleteResult.toFailed();
console.log(failed.status, failed.message);
}CommonJS works too: const { Client } = require('getaddress-dk-api');
Records keep DAWA's Danish field names — vejnavn, husnr, etage, dør, postnr, postnrnavn,
kommunekode, x, y and the rest — so read dør as adresse['dør']. Ids are DAR's UUIDs, the same ids
DAWA gave, so ids you have stored still work.
Suggestions are free; each address picked is one look-up. Pass kun_tekst: true to autocomplete,
adresserAutocomplete or adgangsadresserAutocomplete and each suggestion carries only its text and the
record's id and href, free (rate limited); fetch the one picked with adresse(id) or adgangsadresse(id).
Without it the answer is DAWA's own, records included, and one that suggests addresses is a look-up.
In the browser
The API refuses an API key sent from a web page. In the browser, use a domain token (made in your
console for your site's domain). Pass it where the key would go; the client sends it in the path,
https://api.getaddress.dk/t/{dtoken_…}/autocomplete?q=…, as DAWA widgets do.
For a ready-made address field, use a widget instead of this client: ours,
getaddress-dk-autocomplete, or DAWA's open-source
dawa-autocomplete2 with baseUrl set to
https://api.getaddress.dk/t/{your-domain-token}. Both are supported; see
JavaScript Autocomplete.
import Client from 'getaddress-dk-api';
const api = new Client('dtoken_your-domain-token');
input.addEventListener('input', async () => {
// Free: text-only suggestions.
const result = await api.autocomplete(input.value, { caretpos: input.selectionStart, kun_tekst: true });
if (!result.isSuccess) return;
for (const suggestion of result.toSuccess()) {
// suggestion.type is 'vejnavn', 'adgangsadresse' or 'adresse'
show(suggestion.forslagstekst, suggestion.tekst, suggestion.caretpos);
}
});
// When an address is picked: one look-up.
async function picked(suggestion) {
const result = await api.adresse(suggestion.data, { struktur: 'mini' });
if (result.isSuccess) fill(result.toSuccess());
}Autocomplete
autocomplete is DAWA's combined /autocomplete, the one the dawa-autocomplete2 widget calls: street names
first, then access addresses, then addresses, moving on as the text narrows. Branch on type.
With kun_tekst: true (ours, not DAWA's) the answer is free: an address or access address carries only
{ id, href } in data, and the one picked is fetched with adresse(s.data) or adgangsadresse(s.data) for
one look-up. The types follow the option, so s.data.vejnavn is a compile error on a text-only answer.
const result = await api.autocomplete('Amagerbrogade 217A', { type: 'adresse', postnr: 2300, fuzzy: true, kun_tekst: true });
for (const s of result.toSuccess()) {
if (s.type === 'adresse') console.log(s.tekst, s.data.id); // fetch the one picked: api.adresse(s.data)
if (s.type === 'vejnavn') console.log(s.data.navn);
}Without kun_tekst the answer is DAWA's own, data the address in DAWA's mini structure, and an answer that
suggests addresses costs one look-up; street names are always free.
One kind of thing only:
await api.adresserAutocomplete('Amagerbrogade 217A, kl.', { postnr: 2300, kun_tekst: true }); // [{ tekst, adresse: { id, href } }] free
await api.adresserAutocomplete('Amagerbrogade 217A, kl.', { postnr: 2300 }); // [{ tekst, adresse }] 1 look-up if not empty
await api.adgangsadresserAutocomplete('Amagerbrogade 217A', { kun_tekst: true }); // [{ tekst, adgangsadresse: { id, href } }] free
await api.vejnavneAutocomplete('Amag'); // [{ tekst, vejnavn }] free
await api.postnumreAutocomplete('23'); // [{ tekst, postnummer }] freeAdresser and adgangsadresser
An adresse is a full address, with floor (etage) and door (dør); an adgangsadresse (access address) is
the street, house number and postcode it sits behind. Each fetch is one look-up; an id that is not found costs
nothing.
const nestet = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b'); // struktur=nestet (default)
const mini = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { struktur: 'mini' });
const flad = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { struktur: 'flad', srid: 25832 });
const feature = await api.adresse('3bba05d4-c8c4-4c90-8a64-a4dff11b9d1b', { format: 'geojson' });
const adgang = await api.adgangsadresse('099f3e28-4fb8-4c61-86a1-edff5df52409', { struktur: 'mini' });The return type follows struktur and format: AdresseMini, AdresseFlad, AdresseNestet, or a GeoJSON
Feature. Mini and flad are typed field by field; nestet types the main fields and leaves the nested
registers loose.
Search a page at a time — one look-up per record returned, per_side at most 100. Several values of one
parameter go as an array (sent DAWA's way, joined with |); etage: '' or 'dør': '' means "has none".
const page = await api.adresser({ postnr: 2300, vejnavn: 'Amagerbrogade', husnr: '217A', struktur: 'mini' });
const text = await api.adresser({ q: 'Amagerbrogade 217A, kl. 5, 2300 København S' });
const next = await api.adresser({ kommunekode: '0101', side: 2, per_side: 10, struktur: 'mini' });
const adgange = await api.adgangsadresser({ vejnavn: 'Amagerbrogade', postnr: [2300, 2100] });Reverse geocoding
The access address nearest a point. One look-up; nothing within reach is a 404 that costs nothing.
const nearest = await api.reverse(12.6137425, 55.6490036); // longitude, latitude
const utm = await api.reverse(556488.89, 6323087.65, { srid: 25832, struktur: 'mini' }); // easting, northingDatavask (address cleaning)
An address written any way — misspelt, abbreviated — matched against DAR. One look-up when an address is returned; free otherwise.
const washed = await api.datavaskAdresser('Amagerbrogde 217A, kl. 5, 2300 Kbh S');
const { kategori, resultater } = washed.toSuccess(); // kategori 'A' exact, 'B' safe to use, 'C' uncertain
if (kategori !== 'C') {
const adresse = resultater[0].adresse; // { id: '3bba05d4-…', vejnavn: 'Amagerbrogade', … }
}datavaskAdgangsadresser does the same for access addresses (each result's adgangsadresse). Up to 10
results, best first; vaskeresultat.afstand and forskelle count the edits.
Vejnavne and postnumre
Street names and postcodes. Free, and rate limited.
const streets = await api.vejnavne({ postnr: 2300 }); // every street in 2300, with postcodes and kommuner
const street = await api.vejnavn('Amagerbrogade');
const postnumre = await api.postnumre({ kommunekode: '0101' });
const postnummer = await api.postnummer(2300); // { nr: '2300', navn: 'København S', bbox, … }Companies (CVR)
Active Danish companies from CVR (Det Centrale Virksomhedsregister), by name or CVR number. Suggestions are free and rate limited; a company's record is one look-up (a bad check digit or an unknown company costs nothing).
const found = await api.companies('eksempel bag', { top: 5 }); // legal names first, then binavne
const company = await api.company(found.toSuccess().suggestions[0]); // or api.company('12345674')
const { name, other_names, company_form, industry, address, reklamebeskyttet } = company.toSuccess();
// address.source 'dar': the DAR address CVR points at, with x and y; 'cvr': as CVR registered itA company with reklamebeskyttet: true has asked not to be contacted for direct marketing: you must not use it for
that. Data: Det Centrale Virksomhedsregister (CVR), CC BY 4.0.
Failures
Errors the API reports and network failures are results, never thrown. status is the HTTP status (0 when
no response arrived), message says what went wrong, and a 429 carries retryAfterSeconds. There are two
kinds of error body, and code names either:
- DAWA's errors, exactly as DAWA sent them, in
dawaError({ type, title, details }):QueryParameterFormatError(400),ResourcePathFormatError(404, a malformed id or postcode) andResourceNotFoundError(404). - Our refusals, as problem details in
problem:unauthorized(401),forbidden(403),domain-token-scope(403),domain-token-rate-limit(429), and rate or daily limits (429 withRetry-After).
const result = await api.adresse(id);
if (!result.isSuccess) {
const failed = result.toFailed();
if (failed.isNotFound) { /* no such address — costs nothing */ }
else if (failed.isInvalid) console.log(failed.dawaError.details); // [['id', 'String does not match pattern …']]
else if (failed.isRateLimited) await wait(failed.retryAfterSeconds ?? 60);
else if (failed.isUnauthorized) { /* key missing or unknown, or an API key sent from a browser */ }
else console.log(failed.code, failed.message);
}Usage reports
Pass your admin key as the second argument:
const api = new Client('your-api-key', 'your-admin-key');
const today = await api.usage();
const oneDay = await api.usage(1, 9, 2026);
const range = await api.usageRange(new Date('2026-09-01'), new Date('2026-09-14'));Coming from DAWA
The same paths, parameters, fields and ids as DAWA (api.dataforsyningen.dk), which closes on 1 October 2026:
- Change the host to
https://api.getaddress.dk. - Add your key:
api-key=on the query string from a server, or a domain token in the path (https://api.getaddress.dk/t/{dtoken_…}) for browser code such as dawa-autocomplete2.
Records, field names, ids and error bodies are unchanged, so code that reads DAWA's answers reads ours. A
search now pages (per_side at most 100). See Differences from DAWA.
Options
new Client('your-api-key', 'your-admin-key', {
baseUrl: 'https://api.getaddress.dk', // the API origin
timeoutMs: 30000, // 0 for no timeout
fetch: customFetch // defaults to the global fetch
});Development
npm install
npm testGETADDRESS_DK_KEY=your-api-key npm test also runs a live smoke test (one look-up); set
GETADDRESS_DK_BASE_URL to point it at another host.
Licence
MIT © getAddress()
The MIT licence covers the code only. Address data is from the Danish Address Register (DAR), © Klimadatastyrelsen, licensed CC BY 4.0: credit it where you show it. See the data sources page.
