GuideLister & synkronisering
Hvordan holder vi vores egen kopi af adresserne ajour?
Har du dine egne adresser i en database — til en kundeliste, et rutesystem eller et kort — er det spild at hente dem alle igen hver nat. Hent området én gang, og læs derefter kun det, der har ændret sig, fra /v1/aendringer. Feedet har både adresser og bygninger, og det siger selv, hvor langt det rækker.
Kaldene i guiden
På denne side7 trin
Hvad feedet indeholder
Feedet fletter to logs efter det tidspunkt, Grundfast registrerede ændringen, ældste først. De kommer fra forskellige kilder og har forskellig forsinkelse:
| Adresser | Bygninger | |
|---|---|---|
| Hændelser | adresse.oprettet, adresse.aendret, adresse.nedlagt | bygning.tilkommet, bygning.aendret, bygning.udgaaet |
| Kilde | DARs daglige ændringsudtræk | Sammenligning af to udgaver af vores bygningsindeks over BBR |
| Forsinkelse | Typisk et døgn | Typisk få dage — indekset bygges igen, så snart BBR’s samlede udtræk er nyt; se seneste_snapshot |
| Gemmes i | 35 dage | 120 dage |
| Nøgle | adgangsadresse_id | bygning_id (og bfe_nummer, adgangsadresse_id) |
En adresseændring tæller kun, når betegnelse, vejnavn, husnummer, postnummer, kommune eller placering flytter sig. En bygningsændring sammenligner de felter, bygningsindekset har: anvendelse, år, arealer, etager, varme, tag, ydervæg, asbest, olietank, adresse, BFE og koordinat.
Kræver Pro
402. Kaldene på feedet tæller ikke mod kvoten — kun burst-grænsen gælder. Den første indlæsning tæller som almindelige kald.Trin 1: hent området én gang
Notér tidspunktet, før du starter, og hent så alle adgangsadresser i dine kommuner eller postnumre med /v1/adgangsadresser. Listen pagineres med per_side (højst 1.000) og side, og hver side tæller ét kald. Én forespørgsel kan bladre højst 50.000 adresser frem, så del en stor kommune op i postnumre. Hvert hit har adgangsadresse_id — din primærnøgle — og bfe_nummer. Bygningerne kan du hente på samme måde med bygningssøgningen, som kræver Starter for side 2 og frem.
# Notér starttidspunktet — det bliver "siden" i trin 2.
date -u +%Y-%m-%dT%H:%M:%SZ > indlaest.txt
for postnr in 1550 1551 1552; do # dine postnumre
side=1
while :; do
curl -sG "https://api.grundfast.dk/v1/adgangsadresser" \
--data-urlencode "postnr=${postnr}" \
--data-urlencode "per_side=1000" \
--data-urlencode "side=${side}" \
-H "Authorization: Bearer $GRUNDFAST_API_KEY" > "${postnr}-${side}.json"
[ "$(jq '.antal' "${postnr}-${side}.json")" -lt 1000 ] && break
side=$((side + 1))
done
doneTrin 2: læs ændringerne med en cursor
Første gang sender du siden med tidspunktet fra trin 1, så du kun får det, der er registreret efter din indlæsning. Hvert svar har en naeste_cursor, og den husker siden — også når svaret er tomt — så alle senere kald behøver kun cursoren. Gem den i samme transaktion som de ændringer, du har skrevet, og send den som cursor i næste kald. Så springer du aldrig en ændring over og får aldrig den samme to gange. Er flere true, ligger der allerede mere klar; kald igen med det samme. Ellers er du ajour, og næste kørsel kan vente til i morgen.
# Første kald: alt registreret siden indlæsningen
curl -G "https://api.grundfast.dk/v1/aendringer" \
--data-urlencode "kommunekode=0101,0147" \
--data-urlencode "siden=$(cat indlaest.txt)" \
-H "Authorization: Bearer $GRUNDFAST_API_KEY"
# Alle senere kald: fortsæt fra den gemte cursor
curl -G "https://api.grundfast.dk/v1/aendringer" \
--data-urlencode "kommunekode=0101,0147" \
--data-urlencode "cursor=${CURSOR}" \
-H "Authorization: Bearer $GRUNDFAST_API_KEY"{
"antal": 1,
"aendringer": [
{
"type": "adresse",
"id": "adresse:48211",
"haendelse": "adresse.aendret",
"registreret": "2026-10-12T05:10:02.551Z",
"kommunekode": "0101",
"postnr": "1550",
"adgangsadresse_id": "0a3f507a-ec01-32b8-e044-0003ba298018",
"betegnelse": "Rådhuspladsen 1, 1550 København V",
"status": "gaeldende",
"aendrede_felter": ["koordinat"],
"foer": { "betegnelse": "Rådhuspladsen 1, 1550 København V", "koordinat": { "lon": 12.56953, "lat": 55.67568 }, "…": "…" },
"efter": { "betegnelse": "Rådhuspladsen 1, 1550 København V", "koordinat": { "lon": 12.56961, "lat": 55.67571 }, "…": "…" },
"kilde": "DAR_20261012040010"
}
],
"naeste_cursor": "eyJhIjo0ODIxMSwiYiI6MTkwN30",
"flere": false,
"meta": {
"daekning": {
"adresse": {
"daekket_fra": "2026-09-07T05:02:11.004Z",
"senest_opdateret": "2026-10-12T05:10:40.112Z",
"seneste_udtraek": "DAR_20261012040010",
"opbevaring_dage": 35,
"forsinket": false,
"huller": []
},
"bygning": {
"daekket_fra": "2026-06-14T02:00:00.000Z",
"seneste_snapshot": "2026-10-05T00:00:00.000Z",
"opbevaring_dage": 120
}
}
}
}
adresse:<sekvens>ellerbygning:<nr>. Gem det, så en ændring, du allerede har skrevet, ikke skrives to gange.Skriv
efterover din række.foerernullfor en ny adresse,efterernullfor en nedlagt. Feltnavnene iaendrede_felterer de samme som ifoerogefter.Den er uigennemsigtig: send den uændret som
cursornæste gang. En cursor, API’et ikke har udstedt, giver400.Et tomt svar betyder kun "intet nyt", når
forsinketerfalseoghullerer tom.Bygningsændringer findes først, når næste udgave af indekset er indlæst. Her ser du, hvor gammel den nyeste er.
Sådan skriver du en ændring
| Hændelse | Gør dette |
|---|---|
| adresse.oprettet | Indsæt efter med adgangsadresse_id som nøgle. |
| adresse.aendret | Opdatér rækken med efter. Gemmer du BFE, så slå adressen op igen ved en ændret koordinat — adresseændringen bærer ikke BFE-nummeret. |
| adresse.nedlagt | Markér rækken som nedlagt i stedet for at slette den, hvis andre data peger på den. status siger nedlagt eller henlagt. |
| bygning.tilkommet / aendret / udgaaet | Samme mønster på bygning_id. udgaaet betyder, at bygningen ikke længere er registreret som opført — ikke nødvendigvis, at den er revet ned. |
En adresse, der flytter til et andet postnummer eller en anden kommune, hører til området efter ændringen; en nedlagt adresse hører til der, hvor den lå. Følger du flere områder, så vælg dem alle i samme kald, så en flytning mellem dem kommer med.
Webhooks som vækkeur
I stedet for at spørge på et fast klokkeslæt kan du lade Grundfast sige til. Opret et webhook-endpoint i dashboardet med hændelserne adresse.oprettet, adresse.aendret og adresse.nedlagt — og bygning.tilkommet, bygning.aendret og bygning.udgaaet, hvis du også følger bygninger — og et adresseFilter med op til 10 kommunekoder, 50 postnumre, 1.000 adgangsadresse-id’er og 1.000 BFE-numre. Webhooks kræver også Pro. Bygningshændelserne sendes, når næste udgave af bygningsindekset er indlæst — samtidig med, at de dukker op i feedet.
Den robuste opskrift er at bruge leveringen som et signal og feedet som sandheden: verificér signaturen, svar 200 med det samme, og kør så synkroniseringen fra din gemte cursor. En levering, der fejler fem gange, opgives — men det, den bar, ligger stadig i feedet, så du mister intet.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function gyldig(raw: string, header: string | undefined): boolean {
if (!header) return false;
const secret = process.env.GRUNDFAST_WEBHOOK_SECRET ?? '';
const forventet = 'sha256=' + createHmac('sha256', secret).update(raw, 'utf8').digest('hex');
const a = Buffer.from(header);
const b = Buffer.from(forventet);
return a.length === b.length && timingSafeEqual(a, b);
}Huller, forsinkelse og en for gammel cursor
Et tomt svar betyder ikke altid, at intet er ændret. Læs meta.daekning efter hver kørsel og reager på tre tilfælde:
daekning.adresse.forsinketertrue: den daglige opdatering er udeblevet. Feedet er bagud, og et tomt svar siger intet om de seneste dage. Kør igen senere; din cursor er stadig gyldig.daekning.adresse.hullerer ikke tom: et DAR-udtræk blev lagt ind i adresseindekset, men dets ændringer kom ikke i loggen — og blev heller aldrig sendt som webhooks. Listen gælder hele landet, så du kan ikke se, om netop dit område blev ramt. Hent området igen som i trin 1, og sammenlign med din kopi.- Din sidste vellykkede kørsel ligger før
daekket_fra— fx efter en pause på mere end 35 dage. Ændringerne fra mellemtiden er slettet. Start forfra med trin 1.
Kommer du fra DAWA’s replikering?
Det lukkede DAWA havde en replikerings-API, og den findes i en kompatibel udgave under /dawa/replikering/…, så en eksisterende klient kan køre videre med ny base-URL og en nøgle. Hændelserne for adgangsadresser kommer fra den samme log som feedet og holder også 35 dage. Adresser, vejstykker og postnumre har udtræk, men ingen hændelser, og udtrækkene filtrerer ikke på område. Bygger du nyt, er /v1/aendringer det bedre valg: det er afgrænset til dit område, har bygningerne med og fortæller selv om huller. Se DAWA-migrering.
Var denne side nyttig?
Ofte stillede spørgsmål
Pro eller højere, ligesom webhooks og ejendomsovervågning. Kaldene på feedet tæller ikke mod månedens kvote; den første indlæsning af adresserne tæller som almindelige kald.
Adresseændringer i 35 dage og bygningsændringer i 120 dage. Har din integration ligget stille længere, skal du hente området forfra.
Nej. Feedet kræver mindst én kommunekode eller ét postnummer og tager højst 10 kommunekoder og 50 postnumre pr. kald. Følger du flere, så hold en cursor pr. område.
Bygningsændringer findes ved at sammenligne to udgaver af bygningsindekset. Indekset bygges automatisk igen, så snart Datafordeler har udgivet et nyt samlet BBR-udtræk. Udtrækkene udkommer med nogle dages forsinkelse, så en ændring dukker typisk op få dage efter, den er registreret. Feltet seneste_snapshot viser, hvor gammel den nyeste udgave er.
Begge dele virker. Webhooks sparer dig for at spørge. Brug leveringen som signal og hent selve ændringerne fra feedet med din cursor, så mister du intet, hvis en levering fejler.
Prøv det på rigtige data
Gratis op til 5.000 kald/md · intet kreditkort · data fra Klimadatastyrelsen/Datafordeler, CC BY 4.0
Relateret