Hvad vi har shippet
En ærlig, omvendt-kronologisk oversigt over de kapaciteter, der er gået i produktion på Grundfast. Alt herunder er live i dag — den aktuelle driftsstatus pr. komponent kan du se på statussiden.
September 2026
- Forbedring#
Administrativt område på ejendomssiden — og et DAGI-opslag der aldrig virkede
Ejendomssiden viser nu sogn, retskreds, politikreds og opstillingskreds for adressen, slået op på ejendommens eget punkt i DAGI (register #3). Det er svaret på et andet spørgsmål end matrikelnummeret ovenfor: hvilke myndigheder dækker faktisk her. Undervejs fandt vi, at DAGI-registrets geometrilag aldrig havde virket. Lagnavnene var skrevet af dokumentationen og aldrig prøvet mod den rigtige tjeneste, og alle seks var forkerte — lagene hedder dagi_v001:sogneinddeling_current, ikke dagi:Sogneinddeling. Værre var, at fejlen var tavs: et ukendt lagnavn svarer 200 med nul features, hvilket vi læste som "ingen geometri". Havde nogen konfigureret kilden, ville de have fået en tjeneste, der så rigtig ud og aldrig returnerede en eneste polygon. Tre ting mere kom frem, da lagene endelig blev prøvet af. Retskreds og politikreds nøgles på myndighedskode, ikke på retskredskode og politikredskode. Opstillingskreds har slet ingen national kode — dens nummer er kun unikt inden for en storkreds — så den identificeres på navn, og feltet kode er null frem for at gentage navnet og få en manglende oplysning til at se udfyldt ud. Og koderne er nulpolstrede STRENGE, så et opslag på tal ville have fundet nul for hver eneste kommune under 1000. Om selve visningen: et område, der ikke kunne slås op, er FRAVÆRENDE frem for tomt. Hvert punkt på dansk jord ligger i præcis ét sogn, så en tom plads ville sige noget om ejendommen i stedet for om vores opslag — og hele blokken forsvinder derfor, hvis intet blev slået op, i stedet for at vise fire tankestreger.
- Forbedring#
Bindinger, bygningshøjder og enheder på ejendomssiden
Det keyless GET /v1/demo/property — svaret bag hver ejendomsside — bærer nu fem ting, der hele tiden lå i registrene, men aldrig nåede frem til siden. jord er områdeklassificeringen efter jordforureningslovens § 50 a på ejendommens punkt. byggelinjer er alle ti naturbeskyttelses-byggelinjer på ét sted: strandbeskyttelse og klitfredning (§ 15), sø og å (§ 16), skov (§ 17), fortidsminde (§ 18), kirke (§ 19), § 3-natur og § 3-vandløb samt sten- og jorddiger (museumsloven § 29 a). Hvert bygningsfodaftryk bærer hoejde_m — den MÅLTE højde over terræn fra Danmarks Højdemodel, altså 95-percentilen af overfladen inde i fodaftrykket minus medianterrænet under det, som BR18 måler en bygningshøjde. Hver bygning bærer opvarmningsmiddel og supplerende_varme ved siden af varme: installationen siger HVORDAN der varmes op, de to andre siger hvad der brændes, og den, der segmenterer på oliefyr eller varmepumper, læser midlet frem for prosaen. Og hver bygning bærer nu sine enheder — anvendelse, areal, værelser, egen varme og adresse — for et boligareal alene siger ikke, om det er ét hus på 120 m² eller fire lejligheder på 30. Endelig er punktet med i EPSG:25832 ved siden af WGS84, så en landinspektør eller en GIS-import ikke selv skal reprojicere. Tre ting om, hvordan svaret opfører sig, når et register tier. Et byggelinje-opslag, der ikke kunne læses, har inden_for: null og status "utilgaengelig" — det bliver ALDRIG til et nej, for et nej er en målt påstand om, at netop den regel ikke gælder. En TOM byggelinje-liste betyder "vi spurgte ikke / kunne ikke læse", ikke "ingen linjer gælder" — og ejendomssiden viser derfor slet ingen bindings-sektion i det tilfælde frem for en tom. Og et jord-opslag, der fejler, giver jord: null frem for omraadeklassificeret: false, så en nedbrudt WFS aldrig kan skrive "her er ingen jordregler". Et opslag, der ikke når sit budget, gør desuden hele svaret kortlivet i cachen (15 minutter i stedet for 6 timer), så en ejendom, der blev hentet under et udfald, heler sig selv ved næste åbning i stedet for at stå forkert en halv dag. Ejendomssiden viser det hele: en ny sektion "Bindinger på grunden", højde og brændsel på bygningskortet, enhederne foldet ud på den valgte bygning, og en "kort fortalt"-stribe med anvendelse, areal, opførelsesår og varme over identifikatorerne — for den, der lige har søgt sin egen adresse, vil læse hvad stedet ER, før hvad det HEDDER.
August 2026
- Forbedring#
Fredning og bevaringsværdi på hver bygning
Hver bygning i GET /v1/bbr/ejendom/{bfe} bærer nu fredning — om bygningen er FREDET efter bygningsfredningsloven, og dens SAVE-bevaringsværdi 1-9, hvor 1 er højest. Data kommer fra FBB (Fredede og Bevaringsværdige Bygninger, Slots- og Kulturstyrelsen) og joines på bygningens eget id. Feltet følger med i :batch-varianten, i GeoJSON-udgaven og i det keyless demo-svar på /v1/demo/ejendom. Ingen af de to oplysninger står i BBR, og det er hele pointen: har man bygningen fra BBR, mangler man præcis dét, der afgør, om den overhovedet må rives ned eller ændres. Den, der før måtte spørge sin bruger om det, spørger nu registret. Tre ting skal man vide. For det FØRSTE er fredning: null ikke det samme som fredet: false — det første betyder "vi ved det ikke" (ingen FBB-række, eller opslaget kunne ikke gennemføres), det andet er en positiv påstand om, at bygningen ikke er beskyttet. Et opslag, der ikke kan skelne dem, skriver den første ud som den anden. For det ANDET er bevaringsvaerdi null, når bygningen ikke er vurderet: FBB gemmer det som pladsholderne -1 og 0, der tilsammen udgør 92,6 % af registret, og vi oversætter dem til null, så de aldrig kan ende i en UI som "bevaringsværdi 0" eller sortere bedre end 1. En fredet bygning har ofte ingen SAVE-værdi — fredning er ikke en SAVE-karakter, så null på en fredet bygning betyder ikke "ikke bevaringsværdig". For det TREDJE bærer svaret ingen dom: "bevaringsværdig" er en grænse på SAVE-værdien, som KOMMUNEN fastsætter, og de to forhold har hver sin myndighed — Slots- og Kulturstyrelsen for fredningen, kommunen for bevaringsværdien. Vi leverer registrets værdier; den der spørger, anvender sin egen regel.
- Forbedring#
Om-/tilbygningsår på hver bygning
Hver bygning i GET /v1/bbr/ejendom/{bfe} bærer nu om_tilbygningsaar — BBR’s felt 209, året for bygningens seneste om- eller tilbygning — ved siden af opfoerelsesaar. Feltet følger med i :batch-varianten, i GeoJSON-udgaven, i versionshistorikken (/historik) og i det keyless demo-svar på /v1/demo/ejendom. Det er vigtigere, end det lyder, for den der screener en ejendom: et hus opført i 1904 med en tilbygning fra 1968 har den gamle bygningsdel OG en tilbygning midt i PCB-vinduet, og med kun opførelsesåret ser man den forkerte halvdel af huset. Læs de to år som ET UDVIDET interval — en senere tilbygning LÆGGER en æra til, den erstatter ikke opførelsesåret; et hus fra 1950 med en tilbygning fra 2015 skal stadig screenes for asbest. To ting skal man vide om selve tallet. BBR registrerer først et om-/tilbygningsår, når forbedringen udgør mindst 15 % af bygningens værdi før arbejdet (typisk flere m²) — et nyt køkken eller bad udløser det ikke, så feltet er "seneste VÆSENTLIGE om-/tilbygning", ikke "seneste ændring". Og værdien leveres RÅ: BBR bruger 0 og 1000 som uskrevne pladsholdere for "ikke registreret" i årstalsfelter, så begge forekommer, og vi retter dem ikke — et register-API, der stiltiende redigerer registrets værdier, er værre end et, der dokumenterer dem. Kilde: BBR-instruks felt 209.
- Register#
Alle de øvrige byggelinjer — og § 3 — på ét opslag
Nyt endpoint GET /v1/natur/byggelinjer?lon=&lat= svarer på ti spørgsmål i ét kald: strandbeskyttelse og klitfredning (naturbeskyttelseslovens § 15), sø- og åbeskyttelseslinjer (§ 16), skovbyggelinje (§ 17), fortidsmindebeskyttelseslinje (§ 18), kirkebyggelinje (§ 19), § 3-beskyttet naturtype og § 3-beskyttet vandløb, samt beskyttede sten- og jorddiger (museumslovens § 29 a). Ét kald, én afregnet enhed — et tegneværktøj, der slår op på den nye bygnings eget punkt hver gang brugeren trækker i den, skal ikke lave seks rundture for ét spørgsmål. Kilderne er TRE forskellige værter, og det er værd at vide hvorfor: strandbeskyttelseslinjen er ikke et Miljøportal-tema, den er tinglyst PÅ MATRIKLEN af Geodatastyrelsen med én flade pr. jordstykke, og fortidsmindelinjerne kommer fra Slots- og Kulturstyrelsens Fund og Fortidsminder. Netop strandbeskyttelseslinjen er den vigtigste af dem: forbuddet er absolut, det administreres af Kystdirektoratet og ikke af kommunen, og der findes ingen liste over småbygninger, der er undtaget. Nyt i dette register er afstanden: afstand_m er fortegnede meter til nærmeste kant — NEGATIV inde, POSITIV ude — så et tegneværktøj kan sige "flyt bygningen 8 m, så er du ude" i stedet for kun "ja/nej". Den er beregnet i EPSG:25832 og er en bekvemmelighed; inden_for er stadig det autoritative svar på hvilken side man er på. Fælden fra skovbyggelinjerne går igen i sø- og åbeskyttelseslinjerne under et andet navn: linjens egen tilstand står i Kategori_kode, registreringens i Statuskode, og 145 polygoner er ophævede linjer, hvis registrering stadig står som "Gældende / Vedtaget" — svaret læser linjen, ikke registreringen, og de ophævede følger med som dokumentation. Fordi ét kald rører ti registre på tre værter, fejler et nedbrud ikke hele svaret: netop den linje får status "utilgaengelig" og inden_for null, og de øvrige ni svarer som normalt. Et inden_for: false er altså altid målt og aldrig en fejl forklædt som et nej — læs status før inden_for. Svaret bærer BEVIDST ingen dom: der er hverken et kraever_dispensation- eller et forbudt-felt, for hver paragraf har sine egne undtagelser, de ligner ikke hinanden, og § 3-beskyttelsen er oven i købet deklaratorisk — et areal kan være beskyttet uden at stå i registret, og et registreret areal kan vise sig ikke at være beskyttet, fordi beskyttelsen følger naturen på stedet frem for kortet. Vi rapporterer linjen; I kender projektet. Keyless demo på /v1/demo/byggelinjer, med i SDK’et (gf.naturByggelinjer(lon, lat)) og som MCP-værktøj.
- Ny#
Terrænkoter i DVR90 — til situationsplanen
Nye endpoints GET /v1/dhm/kote, POST /v1/dhm/kote:batch og GET /v1/dhm/profil. Terrænkoten var der allerede som terraen_m på /v1/dhm/punkt; det, der manglede, var alt det, der gør et tal brugbart på et dokument. Hvert DHM-svar bærer nu sit højdesystem (system: "DVR90", system_epsg: 5799), griddets opløsning (oploesning_m: 0,4 m), hvordan værdien er taget ud af rasteret (metode: "naermeste_celle" — cellen koordinatet falder i, ikke interpoleret) og modellens specificerede lodrette nøjagtighed (usikkerhed_m: 0,05 m). En kote uden højdesystem kan kommunen ikke kontrollere: DVR90 og den gamle DNN er ikke det samme, og forskellen er op mod ~10 cm alt efter hvor i landet man står. Usikkerheden er produktets landsdækkende tal, ikke en fejlmargin for netop dit punkt — under træer og over vand er terrænet interpoleret over tyndere data. /v1/dhm/kote:batch tager op til 50 punkter i ét kald, fx hjørnerne af en tegnet bygning plus nærmeste skelpunkt: de ligger inden for få meter af hinanden og deles derfor om ét rasteropslag, så otte hjørner koster upstream to kald i stedet for seksten. Det afregnes pr. dedupliceret punkt — præcis som otte enkeltopslag — og er som det eneste :batch-endpoint ikke en plan-feature. /v1/dhm/profil svarer med terrænet langs en ret linje og fald_m, altså hvor meget grunden falder fx fra vej til skel bagest; begge endepunkter er altid med, også når linjen ikke er et helt antal trin lang, for det er netop de to koter et skråt højdegrænseplan diskuteres mellem. Et punkt uden data er altid null og aldrig 0 — 0 m DVR90 er en helt plausibel kote kystnært, så en fejl, der lander som 0, ville være usynlig — og et punkt, der slet ikke kunne besvares, havner i fejl frem for at stå i punkter med en tom kote ved siden af de rigtige. Vi svarer med terrænet, ikke med en dom om byggeretten. To ting at være opmærksom på for jer, der allerede kalder /v1/dhm/punkt: opslaget læser nu den native 0,4 m-celle, koordinatet falder i, i stedet for et 3×3-udsnit resamplet omkring punktet — samme terræn, men læst af den celle modellen faktisk udstiller, så det samme koordinat kan flytte sig en centimeter eller to, godt inden for modellens egne 0,05 m. Og et raster, vi ikke kan afkode — eller som mangler georeferencen — svarer nu 502 i stedet for 200 med null: et manglende svar må ikke ligne “der er ingen data her”, for det er noget, man kan handle på. Et ægte punkt uden dækning (fx på havet) er stadig 200 med null. Med i SDK’et (gf.dhmKote, gf.dhmKoter, gf.dhmProfil).
- Ny#
Målt bygningshøjde på hele ejendommen i ét kald
Nyt endpoint GET /v1/dhm/bygninger/:bfe giver den målte højde på hver enkelt bygning på en ejendom. Højden måles i højdemodellens celler INDE i bygningens GeoDanmark-fodaftryk — ikke i BBR’s registrerede punkt, som ikke altid ligger inde i polygonen, og hvor et opslag ved siden af huset måler græsplænen. tag_m er 95-percentilen af overfladen, ikke maksimum: ét træ, der hænger ind over taget, trækker et maksimum flere meter op, mens det knap rører en percentil over hundredvis af tagceller. terraen_m er medianen af terrænet under samme celler, med terraen_min_m/terraen_max_m ved siden af, så faldet under en bygning på en skrånende grund kan ses i stedet for at forsvinde i et gennemsnit. hoejde_m er forskellen. Alle koter er DVR90, og system og metode står i selve svaret, ikke kun i dokumentationen. En højde er enten MÅLT eller null med en aarsag — den er aldrig 0 som stand-in for "ukendt", og den gættes aldrig ud fra BBR’s etageantal. Kald det på ejendommen, ikke på bygningen: hele ejendommens bygninger dækkes normalt af ét rasteropslag, så en ejendom med 49 bygninger koster to opslag mod upstream i stedet for 98. Med i SDK’et (gf.dhmBygninger(bfe)) og som MCP-værktøj.
- Forbedring#
Skovbyggelinje: nyt felt usikker på svaret
GET /v1/natur/skovbyggelinje bærer nu et usikker-felt. Registreringskolonnen i dai:skovbyggelinjer har en tilstand, der hverken er et ja eller et nej: 326 polygoner står som "Ukendt", og 12 er kun forslag eller kladder. De tæller stadig med i skovbyggelinje — § 17 trækker linjen, kommunen kortlægger den bare, så en uafklaret kortlægning er ikke et uafklaret forbud — men usikker: true markerer nu, at ingen VEDTAGET registrering står bag netop det ja, så det kan bekræftes hos kommunen. Ligger der en vedtaget registrering blandt polygonerne ved punktet, er usikker false, og det er den polygon, der rapporteres i polygon. Feltet er additivt: eksisterende integrationer læser samme booleans som før.
- Register#
Skovbyggelinjer (naturbeskyttelseslovens § 17)
Nyt endpoint GET /v1/natur/skovbyggelinje?lon=&lat= svarer på, om en koordinat ligger inden for en registreret skovbyggelinje — bufferzonen på 300 m omkring skov, hvor § 17 forbyder bebyggelse. Kilden er Danmarks Miljøportals DAI-lag dai:skovbyggelinjer. Laget rummer både de linjer der gælder og de 1872 der er ophævet, og de to ting står i hver sin kolonne: 1532 polygoner har registreringsstatus "Gældende / Vedtaget" på en byggelinje der er ophævet. Svaret skiller dem ad — polygon er den linje der gælder, ophaevede er dem der er ophævet, med kommunens egen afgørelse som link hvor den findes. Et "skovbyggelinje: false" er et målt svar og aldrig et nedbrud forklædt som et nej: kan laget ikke nås, fejler kaldet i stedet. Registret KORTLÆGGER reglen — linjen følger af loven, og kommunen kan reducere eller ophæve den ved afgørelse. Keyless demo på /v1/demo/natur, med i SDK’et (gf.naturSkovbyggelinje(lon, lat)) og som MCP-værktøj.
- Register#
Områdeklassificering (jordforureningslovens § 50 a)
Nyt endpoint GET /v1/jord/omraadeklassificering?lon=&lat= svarer på, om en koordinat er omfattet af kommunens områdeklassificering — og om den ligger i et analysefrit delområde. Kilden er Danmarks Miljøportals DAI-lag dai:omr_klassificering, og svaret bærer registrets egen kode og tekst (3 = område med krav om analyser; 1/2 = analysefrit område) plus den ansvarlige kommune og dens eget link, så jordregulativet kan slås efter. Et "omraadeklassificeret: false" er et målt svar og aldrig et nedbrud forklædt som et nej: kan laget ikke nås, fejler kaldet i stedet. Vejledende — kommunens jordregulativ er det juridiske grundlag. Keyless demo på /v1/demo/jord, med i SDK’et (gf.jordOmraadeklassificering(lon, lat)) og som MCP-værktøj.
Juli 2026
- Register#
Ortofoto-tiles & Kort-visning
Nyt endpoint GET /v1/orto/tile/:z/:x/:y leverer SDFI-luftfoto som standard web-mercator XYZ-tiles (256×256 JPEG, EPSG:3857) — drop-in i Leaflet/MapLibre/OpenLayers, samme nøgle og metering som resten. En keyless demo på /v1/demo/orto/tile/:z/:x/:y driver en ny Kort · 2D · 3D-skifter i situationsplanen på hver ejendomsside (luftfoto med matrikel- + bygningsomrids ovenpå). Orienterings-backdrop, ikke målfast; luftfotoet er vejledende (© SDFI).
- Ny#
TypeScript-SDK live på npm
Den fuldt typede klient er udgivet: npm i @grundfast/sdk (offentlig, ESM + CJS, nul runtime-dependencies). GrundfastClient dækker hele API-fladen — hvert register, DAWA-drop-in-laget, GeoDanmark-fodaftryk, historik/?asOf, batch og eksport — med typecheckede svar (ingen any) og en indbygget kontrakt-drift-garanti mod API’et. Se SDK-referencen for hver metode.
- Ny#
Historik & point-in-time (bitemporal)
De danske registre er bitemporale, og det er nu udstillet: ?asOf=<dato> på et opslag giver posten, som den var registreret på den dag, og /historik giver hele versionstidslinjen (nyeste først, hver version med registrering/virkning-stempler). Live for BBR, DAR (adresser) og Matriklen — og med i SDK’et (gf.ejendom(bfe, asOf), gf.ejendomHistorik(bfe) m.fl.).
- Ny#
MCP-server til AI-agenter
POST /mcp — en stateless MCP-server (JSON-RPC 2.0) udstiller 12 værktøjer over registrene (BBR, Matriklen, DAR, CVR, DHM, Stednavne + GeoDanmark) til Claude Code, Claude Desktop, Cursor og enhver MCP-klient. Autentificér med din egen gf_-nøgle; kald måles, faktureres og rate-limites præcis som REST.
- Register#
BBR: bygningens etageantal
BBR-rollup’en bærer nu bygningens etageantal (antal_etager / byg054AntalEtager), verificeret mod live upstream.
- Ny#
Ægte test-sandbox for gf_test_-nøgler
gf_test_-nøgler er nu en rigtig sandbox: de rammer de rigtige registre, faktureres aldrig, tæller ikke mod din plan-allowance og er capped på 25.000 kald/md via en separat kvote. Hvert svar bærer X-Grundfast-Environment: test — sikker at droppe i CI og staging.
- Ny#
Webhooks, bulk-eksport & batch
Udgående HMAC-signerede webhooks med retry, asynkron bulk-eksport (CSV / NDJSON / GeoJSON) og :batch-paritet for Matrikel, DAR og DAGI.
- Forbedring#
Præcis reverse på lokal parcelgeometri
Self-harvestet jordstykke-geometri i egen database med PostGIS gør reverse (koordinat → BFE) præcist via ST_Contains, med celle- og point-in-polygon-fallback.
- Register#
GeoDanmark-bygningsfootprints
Nyt endpoint GET /v1/geodanmark/bygninger/:bfe leverer footprint-polygoner pr. bygning i WGS84, koblet fra BFE.
Juni 2026
- Register#
CVR — virksomhed på nummer
Register #8 er live: GET /v1/cvr/:cvr slår en virksomhed op på CVR-nummer via CVR-entitetsmodellen.
- Ny#
DAWA-kompatibelt drop-in-lag
autocomplete, datavask, reverse geocoding (/v1/adgangsadresser/reverse — nærmeste adgangsadresse til en koordinat), postnumre, vejnavne, ejerlav og adresse→BFE (jordstykker) genudstillet i den velkendte form oven på DAR — en drop-in-erstatning for DAWA-adressefladen.
- Forbedring#
Realtids-forbrug i dashboardet
Et live “Live forespørgsler”-feed og et sub-routet dashboard (Overblik, API-konsol, Nøgler, Forbrug, Fakturering, Indstillinger).
- Ny#
Adresse-søgning med autocomplete
GET /v1/adresse/search: hurtig DAR-native adresse-autocomplete via et lokalt pg_trgm-indeks.
- Register#
DAR live (adresse) — grundlaget for DAWA-migreringen
Adresseregistret er live på DAR/v3 med en cachet SLA-mirror og BBR-enrichment — fundamentet under drop-in-laget, der erstatter DAWA.
- Ny#
Selvbetjent billing & SLA-mirror
Stripe-baserede planer (Free / Starter / Pro / Scale) med metered overforbrug, og en read-through cache-mirror med serve-stale på tværs af registrene.
- Ny#
Selvbetjening, nøgler & de første registre
Session-auth, self-serve gf_live_/gf_test_-nøgler, dashboard, og de første registre (BBR, Matriklen) bag én bearer-nøgle.
Versionering & udfasning
API’et er versioneret under /v1. Additive, bagudkompatible ændringer — nye felter og nye endpoints — ruller løbende og annonceres her. Brydende ændringer ville udkomme under en ny version (fx /v2) frem for at ændre /v1 under dine fødder, og eventuelle udfasninger varsles her i ændringsloggen, før de træder i kraft. Den annoncerede udfasning af DAWA — som Grundfast er drop-in-erstatning for — er beskrevet på DAWA-siden.
Se også
Ofte stillede spørgsmål
Hvordan er API’et versioneret?
Grundfast-API’et er versioneret under /v1. Additive, bagudkompatible ændringer (nye felter og nye endpoints) ruller løbende og annonceres i denne ændringslog. Brydende ændringer ville udkomme under en ny version (fx /v2) — ikke ved at ændre /v1 under dine fødder.
Hvordan varsles udfasninger (deprecations)?
Udfasninger annonceres her i ændringsloggen med et varsel, før de træder i kraft, så du har tid til at tilpasse din integration. Vi fjerner ikke et /v1-endpoint uden forudgående besked.