Lagedaten.

API-Dokumentation

REST-API für amtliche Bodenrichtwerte — für Integrationen ohne Frontend

Startseite · interaktive Doku (Swagger) · Rate-Limit & Keys · Fehlercodes

Amtliche Originalwerte der Bundesländer — unverändert, mit Quelle, Stichtag und Abrufnachweis. Lagedaten ist ein privater Dienst und keine Behörde.

Überblick

Die API liefert amtliche Bodenrichtwerte (BRW) zu einer deutschen Adresse. Die Adresse wird geokodiert, das Bundesland erkannt und der jeweils zuständige amtliche Geodienst abgefragt — standardmäßig zum aktuellsten Stichtag, auf Wunsch zu einem historischen (Parameter stichtag). Basis-URL ist die Domain dieser Seite, alle Antworten sind JSON (UTF-8). Das Tool ist kostenlos und ohne Key nutzbar; ein API-Key erhöht lediglich die Limits.

Optional je Adresse: das amtliche ALKIS-Flurstück (mit_flurstueck) und ein rechnerischer Bodenwert (mit_bodenwert) — beides derzeit für fünfzehn Länder (BB, BE, BW, HB, HE, HH, MV, NI, NW, RP, SH, SL, SN, ST und TH). Beide Optionen gibt es auch im CSV-Batch.

Hinweis: Bayern (BY) ist derzeit nicht enthalten — Lizenzlage ungeklärt.

Endpunkte

GET /api/v1/abfrage — Einzelabfrage einer Adresse (synchron)

ParameterTypBeschreibung
adresseQuery, Weg 15–300 Zeichen, z. B. Domplatz 1, 39104 Magdeburg
lat, lonQuery, Weg 2Breiten- und Längengrad in WGS84, Dezimalpunkt statt Komma. Beide zusammen, sonst HTTP 400. Dieser Weg fragt keinen Geocoder.
gemarkung, flur,
flurstueck, nenner
Query, Weg 3Amtliche Flurstücks-Kennung. 15 Länder (BB, BE, BW, HB, HE, HH, MV, NI, NW, RP, SH, SL, SN, ST und TH). In den INSPIRE-Ländern (BB, BW, HE, HH, MV, NI, SH, SL) ist statt des Gemarkungsnamens der sechsstellige Gemarkungsschlüssel anzugeben, und die Flur ist dort Pflicht — der amtliche Dienst führt dort keine Gemarkungsnamen. gemarkung und flurstueck (Zähler) sind Pflicht, flur und nenner optional — aber ohne sie ist die Kennung oft mehrdeutig, s. unten.
landQueryBundesland-Kürzel, z. B. NW. Pflicht bei Weg 2 und 3, unzulässig bei Weg 1.
kompaktQuery, optionaltrue = schlanke Antwort ohne roh_payload und Geometrie (für Integrationen)
mit_flurstueckQuery, optionaltrue = amtliches ALKIS-Flurstück an der Adresse ergänzen. 15 Länder (BB, BE, BW, HB, HE, HH, MV, NI, NW, RP, SH, SL, SN, ST und TH) — die übrigen liefern den Bodenrichtwert unverändert, aber kein Flurstück. Enthält seit 08/2026 auch tatsaechliche_nutzung (s. unten).
mit_bodenwertQuery, optionaltrue = rechnerischer Bodenwert (amtliche Fläche × amtlicher BRW, je Zone anteilig). Impliziert mit_flurstueck.
stichtagQuery, optionalJJJJ-MM-TT — historischer Stichtag. Freigegeben für BE, SN, ST, TH. Ohne den Parameter gilt immer der aktuellste Wert.

Drei Zugangswege, ein Endpunkt. Adresse, Koordinate oder Flurstücks-Kennung — genau einer je Anfrage. Zwei gleichzeitig ergeben HTTP 400 statt einer stillen Bevorzugung: welcher gewonnen hätte, wäre von außen nicht erkennbar. Alle übrigen Parameter (kompakt, mit_flurstueck, mit_bodenwert, stichtag) gelten für jeden Weg gleich, und die Antwortform ist identisch.

Warum land bei der Koordinate Pflicht ist. Aus einer Koordinate allein lässt sich das Bundesland hier nicht bestimmen: Wir führen keine Landesgrenzen-Geometrie, und der Geocoder kennt keine Rückwärtssuche. Bliebe raten — an jeder Landesgrenze falsch — oder der Reihe nach zwölf Landesdienste zu befragen. Also wird gefragt statt geraten:

GET /api/v1/abfrage?lat=52.1249036&lon=11.6356315&land=ST

{
  "eingabe_adresse": "52.1249036, 11.6356315",
  "geocode_quelle": "eingabe", "geocode_treffertyp": "koordinate",
  "latitude": 52.1249036, "longitude": 11.6356315,
  "treffer": [
    { "brw_nummer": "03204303", "bodenrichtwert_eur_qm": 900.0,
      "bodenrichtwertzone_name": "Breiter Weg/Hasselbachplatz", "…": "…" },
    { "brw_nummer": "03207541", "bodenrichtwert_eur_qm": 4.45,
      "bodenrichtwertzone_name": "Magdeburg_A", "…": "…" }
  ]
}

Ohne land: fehler_typ: "land_erforderlich". Außerhalb Deutschlands oder mit vertauschten Achsen: koordinate_ausserhalb; kein Zahlenformat (etwa Dezimalkomma): koordinate_ungueltig.

Eine Flurstücksnummer ist nicht eindeutig. Gemessen am 2026-09-03 an den amtlichen Diensten: In der Gemarkung Köln tragen 19 Flurstücke die Nummer 344 — in 19 verschiedenen Fluren. Auch Gemarkung + Flur + Zähler kann mehrdeutig sein, wo ein Nenner existiert (Magdeburg, Flur 145, Nummer 5008 → 4 Flurstücke). Bleibt die Kennung mehrdeutig, wird keines ausgewählt:

GET /api/v1/abfrage?land=NW&gemarkung=Köln&flurstueck=344

{ "fehler_typ": "flurstueck_mehrdeutig",
  "mehrdeutige_flurstuecke": ["05495803500344______", "05495800100344______", "…"] }

Weitere Fehlertypen dieses Weges: flurstueckssuche_fuer_land_nicht_verfuegbar (Land ohne ALKIS), flurstueckskennung_unvollstaendig, flurstueck_nicht_gefunden, flurstueck_ohne_geometrie. gemarkung nimmt den Klartext (Köln) oder den Gemarkungsschlüssel (054958); führende Nullen der Flur werden ergänzt.

Historischer Stichtag. Die Abfrage ist geografisch adressiert: „welcher amtliche Wert galt an diesem Punkt zu diesem Stichtag?“ — nicht „was machte Zone X über die Jahre?“. Zonennummern und -zuschnitte sind über Jahrgänge nicht stabil, ein Join über die Nummer würde verschiedene Flächen vermischen.

Ein nicht vorhandener Stichtag wird nie stillschweigend durch den nächstgelegenen oder aktuellen Wert ersetzt. Stattdessen:

{
  "fehler_typ": "stichtag_nicht_verfuegbar",
  "stichtag_angefragt": "2016-01-01",
  "verfuegbare_stichtage": ["2016-12-31", "2018-12-31", "2020-12-31", "2022-01-01"],
  "treffer": []
}

Für ein Land ohne Historie-Freigabe: fehler_typ: "historie_fuer_land_nicht_verfuegbar". Achtung: die Länder mischen die Stichtagskonvention — Thüringen führt 2008–2020 als JJJJ-12-31 und erst ab 2022 als JJJJ-01-01. 2016-01-01 ist dort leer, 2016-12-31 liefert einen Wert. JJJJ-12-31 und 01.01.(JJJJ+1) sind verschiedene Ermittlungszeitpunkte (§ 196 Abs. 1 Satz 5 BauGB, geändert zum 23.06.2021) und werden nicht zusammengelegt.

Tatsächliche Nutzung. Das Flurstück führt tatsaechliche_nutzung — eine Liste aus nutzungsart (Klartext des Katasters), funktion (sofern geführt) und flaeche_qm (Anteil). Quelle ist das amtliche ALKIS-Feld tntxt; es liegt unverändert auch im roh_payload.

"tatsaechliche_nutzung": [
  {"nutzungsart": "Fläche besonderer funktionaler Prägung",
   "funktion": "Öffentliche Zwecke", "flaeche_qm": 310.0}
]

Wichtige Abgrenzung: Die tatsächliche Nutzung ist nicht der Entwicklungszustand nach § 3 ImmoWertV, und sie wird von uns auch nicht in einen übersetzt. Sie wird ausschließlich ausgegeben — es werden daraus keine Bodenrichtwertzonen gefiltert, ausgewählt oder gewichtet. Ein baureifes, unbebautes Grundstück kann im Kataster als Grünland geführt sein; der Umkehrschluss trägt also nicht. Mehrere Nutzungen je Flurstück sind der Normalfall und werden vollständig ausgegeben.

Bodenwert. ist_amtlich ist immer false: amtlich sind die beiden Eingangswerte (Fläche, Bodenrichtwert), die Multiplikation und Flächenaufteilung sind unsere Berechnung. bodenwert_gesamt_eur ist null, wenn Zonen dieselbe Fläche überdecken — dann sind die Teilwerte alternative Wertansätze, keine Summanden, und Addieren wäre fachlich falsch. Der Grund steht maschinenlesbar in abdeckung und im Klartext in hinweise.

Beispielantwort (gekürzt):

{
  "eingabe_adresse": "Domplatz 1, 39104 Magdeburg",
  "geocode_status": "ok",
  "longitude": 11.6339,
  "latitude": 52.1250,
  "treffer": [
    {
      "bodenrichtwert_eur_qm": 250.0,
      "stichtag": "2024-12-31",
      "bodenrichtwertzone_name": "...",
      "quelle": { "land": "ST", "dienst_bezeichnung": "..." },
      "attribution": {
        "bereitsteller": "(c) GeoBasis-DE / LVermGeo ST (...)",
        "lizenz": "dl-de/by-2-0",
        "lizenz_uri": "https://www.govdata.de/dl-de/by-2-0"
      },
      "modified": "Schema normalisiert, Werte unveraendert"
    }
  ],
  "fehler": null
}

Jeder Treffer trägt die lizenzpflichtige attribution (Bereitsteller · Lizenz · URI) und den Änderungshinweis modified. Diese sind bei jeder Weiterverwendung mitzuführen.

POST /api/v1/batch — Datei-Abruf starten (asynchron)

ParameterTypBeschreibung
dateimultipart/form-data, PflichtCSV oder XLSX, max. 1 MB. Excel wird am Inhalt erkannt (ZIP-Signatur), nicht am Dateinamen; maßgeblich ist das erste Tabellenblatt, höchstens 5000 Zeilen.
Die 1 MB gelten für die hochgeladene Datei. Bei einer XLSX ist das das komprimierte ZIP — deshalb wird die Zeilenzahl zusätzlich beim Lesen begrenzt.
mit_flurstueckForm-Feld, optionaltrue = ALKIS-Flurstück je Adresse (15 Länder, alle außer Bayern)
mit_bodenwertForm-Feld, optionaltrue = rechnerischer Bodenwert je Adresse; impliziert mit_flurstueck
stichtagForm-Feld, optionalJJJJ-MM-TT — gilt für den gesamten Lauf, gleiche Regeln wie bei /api/v1/abfrage

Antwort: { "job_id": "abc123...", "adressen": 12, "status": "wartet", "optionen": {...} }

Die Zusatzoptionen verlängern den Lauf spürbar (je Adresse weitere amtliche Abrufe). Die XLSX enthält dann die Flurstücks- und Bodenwertspalten sowie das Detailblatt Bodenwert mit einer Zeile je Teilfläche.

GET /api/v1/vorlagen — welche Spalten eine Datei tragen darf

Je Zugangsweg (adresse, koordinate, flurstueck): die kanonischen Spaltennamen, welche davon Pflicht sind, eine Beispielzeile und erkannte_namen — alle Schreibweisen, die der Upload akzeptiert (etwa breitengrad für lat). Der Zugangsweg muss nicht angegeben werden; er wird an den Spaltenüberschriften erkannt. Ohne Rate-Limit: Der Endpunkt fragt keinen Landesdienst, er beschreibt das eigene Format.

GET /api/v1/vorlage?modus=…&format=csv|xlsx — Mustervorlage als Datei

Kopfzeile plus eine echte, prüfbare Beispielzeile — die Datei lässt sich unverändert wieder hochladen. Sie wird aus derselben Tabelle erzeugt, die der Upload auswertet; eine gepflegte Beispieldatei würde beim nächsten Spaltennamen unbemerkt veralten. Die CSV ist semikolon-getrennt und trägt ein BOM, damit Excel sie in deutscher Systemumgebung mit einem Doppelklick richtig öffnet.

GET /api/v1/batch/{job_id} — Job-Status abfragen

Antwort enthält status (wartet/laeuft/fertig/fehler), verarbeitet, treffer, fehler.

GET /api/v1/batch/{job_id}/download?format=xlsx|json — Ergebnis herunterladen

Liefert die XLSX- bzw. JSON-Datei. Verfügbar, sobald status = fertig.

GET /api/v1/batch/{job_id}/vorschau?limit=20 — Ergebnis-Vorschau (JSON)

GET /api/v1/flurstueck — Flurstück per amtlichem Kennzeichen

ParameterTypBeschreibung
kennzeichenQuery, PflichtALKIS-flstkennz, z. B. 150938145050080001__
mit_bodenwertQuery, optionaltrue = rechnerischer Bodenwert je Flurstück

Das Land wird aus den ersten beiden Stellen abgeleitet (05 = NW, 15 = ST); andere Präfixe liefern HTTP 400 mit klarer Meldung. Das Kennzeichen ist fix 20-stellig und rechts mit Unterstrichen aufgefüllt — kürzere Eingaben werden serverseitig aufgefüllt.

GET /api/v1/flurstueck — auch per Koordinate (seit 2026-09-05)

ParameterTypBeschreibung
kennzeichenQueryALKIS-Kennzeichen (20-stellig). Entweder dies oder lat+lon — beides zusammen ergibt HTTP 400.
latQueryBreitengrad (WGS84). Das Bundesland wird aus der Ausdehnung der beiden ALKIS-Dienste bestimmt; ein Punkt außerhalb ergibt HTTP 400 mit land_ohne_alkis.
lonQueryLängengrad (WGS84).

enthaelt_punkt beachten. Trifft die Koordinate kein Flurstück — Straße, Gewässer, außerhalb des Landes —, liefert der amtliche Dienst nicht nichts, sondern das nächstgelegene Flurstück mit enthaelt_punkt: false. Wer das ungeprüft übernimmt, gibt für einen Klick auf den Asphalt wortlos das Nachbargrundstück aus. Der Wert wird deshalb unverändert durchgereicht statt hier gefiltert — der Aufrufer soll die Lage sehen.

GET /api/v1/flurstueck?lat=51.4818&lon=7.2162

{ "kennzeichen": null, "land": "NW", "anzahl": 1,
  "flurstuecke": [ { "flurstueckskennzeichen": "05110700600396______",
                     "gemarkung_name": "Bochum", "flaeche_amtlich_qm": 1202.0,
                     "enthaelt_punkt": true, "geometrie_wgs84": { "…": "…" } } ] }

GET /api/v1/flurstueck/bereich — alle Flurstücke eines Kartenausschnitts

ParameterTypBeschreibung
bboxQuery, Pflichtwest,sued,ost,nord in WGS84. Höchstens 1000 Flurstücke je Anfrage — unsere Grenze gegen die Nutzlast, nicht die des Dienstes: Der liefert bei COUNT=5000 alle 2274 eines Quadratkilometers (gemessen 2026-09-06).

Eine Zeichenvorlage, keine Auskunft. Dieser Endpunkt liefert Umrisse, damit eine Karte ein Flurstück beim Zeigen hervorheben und per Klick auswählen kann — eine Kachelebene ist ein Bild und gibt das nicht her. Bewusst ohne roh_payload: Das archivierte Original ist hier nutzlos und machte den größten Teil der Antwort aus (gemessen 1,7 kB je Flurstück). Wer einen Wert braucht, holt das Flurstück über /api/v1/flurstueck oder den Lagedaten-Auftrag erneut — dort kommt es mit vollständiger Belegkette.

gekappt: true heißt, die Obergrenze wurde erreicht und im Ausschnitt können weitere Flurstücke liegen, die nicht dabei sind. Der Dienst selbst sagt das nicht — er meldet numberMatched="unknown". Liegt der Ausschnitt außerhalb der angebundenen Länder, kommt land: null und eine leere Liste, ohne dass ein Landesdienst befragt wird.

GET /api/v1/flurstueck/bereich?bbox=7.2133,51.4809,7.2191,51.4827

{ "land": "NW", "anzahl": 216, "gekappt": false,
  "flurstuecke": [ { "flurstueckskennzeichen": "05110701500301______",
                     "flaeche_amtlich_qm": 106.0, "lage_bez": "…",
                     "gemarkung_name": "Bochum",
                     "geometrie_wgs84": { "…": "…" } } ] }

GET /api/v1/flurstueck/nachbarn — angrenzende Flurstücke

ParameterTypBeschreibung
kennzeichenQuery, PflichtALKIS-flstkennz des Ausgangsflurstücks, z. B. 054958030003440017__

15 Länder; das Präfix im Kennzeichen entscheidet (01 SH, 02 HH, 03 NI, 04 HB, 05 NW, 06 HE, 07 RP, 08 BW, 10 SL, 11 BE, 12 BB, 13 MV, 14 SN, 15 ST, 16 TH). Berlin führt das Kennzeichen 18-stellig, die übrigen 20-stellig. In Hamburg und Hessen ist die Suche über das Kennzeichen nicht möglich — deren amtlicher Dienst kann nicht nach Attributen filtern; dort führt nur der Weg über lat/lon, und die Antwort sagt das mit fehler_typ: kennzeichensuche_nicht_moeglich; andere Präfixe liefern HTTP 400. Ermittelt über fes:Touches am amtlichen ALKIS-Dienst — kein Pufferabstand, kein Toleranzwert. Das Ausgangsflurstück selbst ist nicht in der Liste. Jeder Nachbar trägt geometrie_wgs84 für die Karte.

Grenze: Bei mehrteiligen Flurstücken wird der größte Teil abgefragt; Nachbarn, die nur an einen Nebenteil grenzen, können fehlen. Das steht auch als hinweis in der Antwort.

GET /api/v1/flurstueck/nachbarn?kennzeichen=054958030003440017__

{ "kennzeichen": "054958030003440017__", "land": "NW", "anzahl": 10,
  "nachbarn": [ { "flurstueckskennzeichen": "05495803000304______",
                  "flaeche_amtlich_qm": 92.0, "lage_bez": "Domkloster 4",
                  "geometrie_wgs84": { "…": "…" } } ] }

GET /api/v1/bodenwert/auswahl — Bodenwert mehrerer Flurstücke, getrennt je Zone

ParameterTypBeschreibung
kennzeichenQuery, PflichtEin oder mehrere ALKIS-Kennzeichen, durch Komma getrennt. Höchstens 25 je Anfrage, und alle im selben Bundesland — sonst HTTP 400.
Rechnen Sie mit rund 7 Sekunden je Flurstück: Die Fläche wird beim Landesdienst mit zwölf Punkten abgetastet, mit Pacing. 25 Flurstücke sind also über zwei Minuten in einer Anfrage — für größere Auswahlen ist /api/v1/lagedaten gedacht, das als Auftrag läuft.

15 Länder. Keine Gesamtsumme über Zonen hinweg — und das ist keine Lücke, sondern die Entscheidung: Eine Summe über mehrere Bodenrichtwertzonen stünde in keinem amtlichen Dokument, und wo die Zonen verschiedene Entwicklungszustände tragen, vermischte sie Bauland mit Land- und Forstwirtschaft. Innerhalb einer Zone wird summiert — dort wird derselbe amtliche Bodenrichtwert auf mehrere Flächen angewendet, das ist keine neue Ableitung.

zonen_ueberlappen: true heißt: dasselbe Flurstück liegt in mehreren Zonen, die Flächen der Zonengruppen sind also nicht disjunkt. Wer die Zonensummen dann addierte, zählte dieselbe Fläche doppelt. In Sachsen-Anhalt ist das der Regelfall — großflächige Zonen der Land- und Forstwirtschaft liegen dort über den kleinräumigen Bauland-Zonen.

GET /api/v1/bodenwert/auswahl?kennzeichen=150938145050080001__,15093814505011______

{ "land": "ST", "anzahl_flurstuecke": 3, "anzahl_zonen": 2,
  "zonen": [
    { "brw_nummer": "03204303", "bodenrichtwertzone_name": "Breiter Weg/Hasselbachplatz",
      "bodenrichtwert_eur_qm": 900.0, "flaeche_qm": 897.0, "bodenwert_eur": 807300.0,
      "flurstuecke": ["150938145050080001__", "…"] },
    { "brw_nummer": "03207541", "bodenrichtwertzone_name": "Magdeburg_A",
      "bodenrichtwert_eur_qm": 4.45, "flaeche_qm": 897.0, "bodenwert_eur": 3991.65,
      "flurstuecke": ["150938145050080001__", "…"] }
  ],
  "zonen_ueberlappen": true,
  "flurstuecke_in_mehreren_zonen": ["150938145050080001__", "…"],
  "hinweis_keine_gesamtsumme": "Je Zone wird getrennt ausgewiesen. …" }

Der Bodenwert ist rechnerisch, nicht amtlich: amtliche Fläche × amtlicher Bodenrichtwert. Amtlich sind nur die Eingangswerte.

GET /api/v1/grundsteuer — Grundsteuer B für ein unbebautes Grundstück

ParameterTypBeschreibung
landTextLänderkürzel. Sechzehn Rechtslagen: fünf Länder haben ein eigenes Modell, vier eigene Steuermesszahlen.
hebesatz_prozentZahlDer Hebesatz der Gemeinde. Ohne ihn wird bis zum Messbetrag gerechnet — der ist gemeindeunabhängig.
flaeche_qm, bodenrichtwert_eur_qmZahlDer einfache Fall: ein Grundstück, eine Zone. Maßgeblich ist der Wert zum 1. Januar 2022 (§ 266 BewG), nicht der heutige.
teilText, mehrfachJe qm:brw:bezeichnung. Liegt ein Flurstück in mehreren Zonen, setzt das Finanzamt jeden Teil mit dem Wert seiner Zone an. Leerer Bodenrichtwert = für diese Zone fehlt der Stichtag; der Teil wird als Lücke ausgewiesen, nicht weggelassen.

Das Ergebnis ist eine Überschlagsrechnung nach der gesetzlichen Formel, kein Bescheid. Den Grundsteuerwert stellt das Finanzamt fest. Nur unbebaute Grundstücke — bebaute brauchen Wohnfläche, Baujahr und Gebäudeart, die kein offener Dienst führt.

GET /api/v1/kaufnebenkosten — Grunderwerbsteuer, Notar, Grundbuch, Maklerrichtwert

ParameterTypBeschreibung
kaufpreisZahlDie Gegenleistung (§ 8 GrEStG) — nicht Bodenrichtwert × Fläche
landTextLänderkürzel, z. B. NW. Ohne Land keine Steuer — es wird nicht geraten.
objektartTextgrundstueck (Vorgabe), wohnung_efh, sonstiges
mit_makler, makler_prozentbool, ZahlProvision abschalten oder eigenen Käuferanteil setzen
{ "summe": 58539.96, "summe_ohne_annahmen": 29979.96, "anteil_prozent": 14.63,
  "bloecke": [ { "bezeichnung": "Grunderwerbsteuer", "betrag": 26000.0,
                 "ist_annahme": false, "grundlage": "6,5 % — Gesetz über die Festsetzung …" },
               { "bezeichnung": "Maklerprovision (Käuferanteil)", "betrag": 28560.0,
                 "ist_annahme": true,  "grundlage": "7,14 % — Richtwert, kein festgesetzter Satz" } ] }

Drei Arten von Wahrheit in einer Antwort, und sie sind unterscheidbar. ist_annahme trennt den Richtwert (Maklerprovision, frei verhandelbar) von den gerechneten Beträgen: Die Grunderwerbsteuer ist ein amtlich festgesetzter Satz, die Notar- und Grundbuchgebühren folgen dem GNotKG (Tabelle B nach § 34). summe_ohne_annahmen nennt zusätzlich, was übrig bleibt, wenn man nur dem Gerechneten traut.

Keine Steuer- oder Rechtsberatung. Nicht enthalten sind Auslagen und die Finanzierungsgrundschuld — sie hängt am Darlehensbetrag, nicht am Kaufpreis.

GET /api/v1/laender — aktive Länder, Limits & Quellenvermerke

Das Feld aufrufer zeigt, welche Limits für Sie gelten (erkannt/anonym) — ideal zum Prüfen Ihres Keys.

aufrufer.verbleibend nennt je Topf (teuer, guenstig), wie viel Ihres Stundenkontingents noch frei ist und in wie vielen Sekunden der nächste Platz frei wird. Diese Auskunft kostet nichts — dieser Endpunkt hat kein Limit. Das ist der Unterschied zu den X-RateLimit-Kopfzeilen: Die stehen an der Antwort des teuren Endpunkts, und der zählt jede Anfrage mit. Wer seinen Rest dort erfragt, gibt dafür einen Abruf aus.

datenlage weist je Land aus, was der amtliche Dienst wirklich hergibt: geometrie (Zonenfläche für die Karte), klartext (Klartext oder nur amtliche Codes), historie (ist stichtag freigegeben) und zeitreihe (zusätzlich mit Zonenfläche je Stichtag). Die Listen historie_laender und zeitreihe_laender geben dasselbe kompakt.

wertentwicklung_laender ist eine andere Angabe und deckt sich absichtlich nicht mit zeitreihe_laender: Sie nennt die Länder, für die wir einen fertigen Verlauf mitliefern — er hängt an den Zonen der Antwort (zeitreihe je Zone) und kostet keine zusätzliche Abfrage. Nordrhein-Westfalen steht nur hier, weil sein Abfragedienst keine Historie führt, das Land die Jahrgänge aber zum Download stellt. Sachsen-Anhalt steht nur in zeitreihe_laender, weil sein Dienst zwar stichtagsgenau antwortet, aber keinen Massenabruf erlaubt.

GET /api/v1/marktdaten/liegenschaftszinssatz — amtlicher Liegenschaftszinssatz

ParameterTypBeschreibung
agsQuery, alternativ PflichtAmtlicher Gemeindeschlüssel, 8-stellig, z. B. 05315000 (Köln)
gaaQuery, alternativ PflichtKennung des Gutachterausschussgebiets, z. B. 11400
teilmarktQuery, optionalEin Teilmarkt, z. B. mfh. Ohne Angabe kommen alle elf

Liegenschaftszinssätze nach § 21 Abs. 2 ImmoWertV, je Gutachterausschussgebiet und Teilmarkt. Genau einer der Parameter ags oder gaa ist anzugeben — beide oder keiner liefert HTTP 400. Der Wert ist aus einem Berichtszeitraum abgeleitet, nicht von einem Stichtag; deshalb heißt das Feld berichtszeitraum und nicht stichtag.

Ein Wert liegt genau dann vor, wenn wert gefüllt ist. Ist es leer, nennt fehlanzeige den amtlichen Grund — „kein Markt“ und „zu wenige Fälle“ sind verschiedene Auskünfte, keine davon ist eine Null. Ist unsicher gesetzt, hat der Herausgeber den Zinssatz selbst so gekennzeichnet. fundstelle nennt Datei, Zeile und Feld, beleg_sha256 die Prüfsumme der Quelldatei — damit ist jeder Wert im Original wiederfindbar.

Derzeit ausschließlich Nordrhein-Westfalen, siehe abgedeckte_laender. Ein Gemeindeschlüssel außerhalb liefert HTTP 404 mit fehler_typ = gemeinde_nicht_abgedeckt — nie eine Näherung aus einem Nachbargebiet. Sind auf der Instanz noch keine Marktdaten erfasst, antwortet der Endpunkt mit HTTP 503 und fehler_typ = bestand_leer, nicht mit einem leeren Ergebnis.

curl "https://www.lagedaten.de/api/v1/marktdaten/liegenschaftszinssatz?ags=05315000&teilmarkt=mfh"

{
  "gebiet": {
    "kennung": "11400", "name": "Köln", "gemeindeschluessel": "05315000",
    "gutachterausschuss": "Der Gutachterausschuss für Grundstückswerte in der Stadt Köln"
  },
  "berichtszeitraum": { "von": "2024-01-01", "bis": "2024-12-31" },
  "anzahl_teilmaerkte": 1,
  "davon_mit_wert": 1,
  "liegenschaftszinssaetze": [
    {
      "teilmarkt": "mfh",
      "teilmarkt_klartext": "Mehrfamilienhäuser (inkl. gewerblicher Anteil bis 20% des Rohertrages)",
      "wert": 2.9, "einheit": "prozent",
      "spanne_von": null, "spanne_bis": null,
      "fehlanzeige": null, "unsicher": false,
      "standardabweichung": 1.0, "fallzahl": 92.0,
      "fundstelle": "lzs.csv, Zeile 24, Feld mfh_lzs",
      "beleg_sha256": "0080c6ca2976ac660655e30d7b6fe4658c4780abc55d01e88db4640e728fc7d6",
      "abrufzeitpunkt": "2026-08-27T13:56:16+00:00"
    }
  ],
  "abgedeckte_laender": ["NW"],
  "quelle": "https://www.opengeodata.nrw.de/produkte/infrastruktur_bauen_wohnen/boris/GMD/GMDNRW_CSV.zip",
  "attribution": "(c) GeoBasis NRW",
  "lizenz": "dl-de/zero-2.0",
  "lizenz_uri": "https://www.govdata.de/dl-de/zero-2-0"
}

GET /api/v1/marktdaten/teilmaerkte — Teilmarkt-Kürzel im Klartext

Ohne Parameter. Liefert die Zuordnung der elf Kürzel für teilmarkt: efh, zfh, rhdhh, dreifh, mfh, ggg, handel, buero, gegi, we_s, we_v. Kürzel und Bezeichnung stammen aus der amtlichen Erläuterung des Herausgebers (allgemein_erlaeuterung.xlsx, Blatt lzs) — übernommen ohne den dort angehängten Zusatz „, Liegenschaftszinssatz“, der die Spalte benennt und nicht den Teilmarkt. Die Bezeichnungen sind teils lang und fachlich abgegrenzt (ggg etwa nennt den gewerblichen Anteil, der ihn gegen mfh abgrenzt); sie werden hier nicht gekürzt wiedergegeben, sondern sind beim Endpunkt abzurufen.

GET /health — Health-Check (status, version, zeit)

Suchen (verorten, nicht abrufen)

POST /api/v1/suche — mehrere Eingaben auf einmal verorten

Zwei Schritte statt einem. Dieser Endpunkt sagt, wo etwas liegt und — in den fünfzehn ALKIS-Ländern — welches Flurstück dort ist. Er liefert keinen Bodenrichtwert und keinen Bodenwert: Die kosten zusammen rund 7 Sekunden je Flurstück, und beim Suchen will niemand darauf warten. Sie kommen danach, gesammelt, über /api/v1/lagedaten.

Fehler stehen je Zeile, nicht für die ganze Anfrage — eine unauffindbare Adresse reißt die anderen nicht mit. Höchstens 10 Zeilen; für längere Listen gibt es den Stapelabruf.

Ohne Flurstück (nur Bayern hat kein angebundenes ALKIS) kommt nur die Position zurück. Das ist kein Fehler: Der Punkt allein genügt, um beim Abrufen den Bodenrichtwert an dieser Stelle zu holen.

POST /api/v1/suche
{ "auftraege": [ { "modus": "adresse", "adresse": "Domkloster 4, 50667 Köln" },
                 { "modus": "adresse", "adresse": "Kleine Johannisstraße 4, 20457 Hamburg" },
                 { "modus": "koordinate", "lat": 52.1247, "lon": 11.6350, "land": "ST" } ] }

{ "anzahl": 3, "ergebnisse": [
    { "eingabe": "Domkloster 4, 50667 Köln", "land": "NW", "lat": 50.94…, "lon": 6.95…,
      "flurstueck": { "flurstueckskennzeichen": "054958030003440017__", "…": "…" },
      "fehler_typ": null },
    { "eingabe": "Kleine Johannisstraße 4, 20457 Hamburg", "land": "HH",
      "flurstueck": null, "fehler_typ": null },
    { "eingabe": "52.1247, 11.635", "land": "ST",
      "flurstueck": { "flurstueckskennzeichen": "15093814510224______", "…": "…" } } ] }

Lagedaten-Auftrag (Fortschritt statt Wartezeit)

POST /api/v1/lagedaten — Eingabe und ausgewählte Flurstücke in einem Auftrag

Der Weg, den die Oberfläche seit dem 2026-09-05 benutzt. Er nimmt einen Zugangsweg (Adresse, Koordinate oder Flurstückskennung) und eine Liste bereits bekannter Kennzeichen, legt einen Auftrag an und antwortet sofort. Der Fortschritt wird abgeholt.

Warum ein Auftrag und keine Sofortantwort: Ein Flurstück kostet rund 7 Sekunden, weil seine Fläche beim amtlichen Dienst abgetastet wird. 25 Flurstücke wären über zwei Minuten — das überlebt keine HTTP-Anfrage. Der Auftrag meldet stattdessen nach jedem Schritt, wie weit er ist: verarbeitet von adressen ist ein gemessener Anteil, keine Zeitschätzung.

POST /api/v1/lagedaten
{ "auftraege": [ { "modus": "adresse", "adresse": "Domkloster 4, 50667 Köln" } ],
  "kennzeichen": ["05110700600396______"],
  "stichtag": null }

{ "job_id": "a1b2c3d4e5f6", "positionen": 14, "status": "wartet" }

GET /api/v1/lagedaten/{job_id} — Fortschritt und Ergebnis

Ohne Rate-Limit, damit ein Fortschrittsbalken sich nicht selbst ins Limit fragt. status ist wartet (es läuft bereits ein anderer Abruf — wir fragen die amtlichen Dienste bewusst nur nacheinander), laeuft, fertig oder fehler.

Einheiten statt einer Flurstücksliste: Ausgewählte Flurstücke, die sich berühren, erscheinen als ein verbund. Das ist eine selbst gewählte Zusammenstellung und kein amtliches Grundstück — das Liegenschaftskataster führt keinen Grundstücksbegriff dieser Art. Die Antwort trägt deshalb immer die Zusammensetzung mit; die Fläche ist die Summe der amtlichen Einzelflächen. Innerhalb eines Verbunds gilt die Zonenregel unverändert: getrennt je Zone, keine Gesamtsumme darüber hinweg.

GET /api/v1/lagedaten/a1b2c3d4e5f6

{ "status": "fertig", "adressen": 27, "verarbeitet": 27,
  "ergebnis": {
    "land": "NW",
    "eingabe": { "…": "das gewohnte Abfrage-Ergebnis, oder null" },
    "einheiten": [
      { "verbund": { "anzahl_flurstuecke": 2, "flaeche_amtlich_qm": 2307.0,
                     "kennzeichen": ["05110700600396______", "05110700800196______"],
                     "hinweis": "Zusammengefasst wurden Flurstücke, die sich berühren. …" },
        "zonen": [ { "brw_nummer": "801", "bodenrichtwert_eur_qm": 2000.0, "…": "…" } ] } ],
    "nicht_gefunden": [] } }

Rate-Limit & API-Keys

ZugangAdressen/BatchAnfragen/StundeZählung
anonym10030pro IP-Adresse
mit gültigem API-Key500100pro Schlüssel

Der Key wird per Header X-API-Key: <key> übergeben; alternativ Authorization: Bearer <key>. Jede Antwort enthält die Header X-RateLimit-Limit und X-RateLimit-Remaining. Firmenkunden hinter einem gemeinsamen Proxy werden pro Schlüssel gezählt, nicht pro IP.

Einen Test-Key können Sie formlos per E-Mail anfragen: kontakt@lagedaten.de.

CSV-Format für Batch-Uploads

CSV (UTF-8 oder Latin-1), eine Adresse je Zeile. Erste Zeile darf die Kopfzeile adresse sein (optional). Duplikate werden entfernt. Maximal 1 MB.

adresse
Domplatz 1, 39104 Magdeburg
Aegidientorplatz 1, 30159 Hannover
Rathausstraße 15, 10178 Berlin

Trennzeichen: Komma und Semikolon werden erkannt — das Semikolon ist die Voreinstellung von Excel in deutscher Systemumgebung. Erkannt wird es über die Häufigkeit in der gesamten Datei; ist das Ergebnis nicht eindeutig, wird das Komma angenommen und in der Antwort als unsicher gekennzeichnet.

Mehrere Spalten: Trägt die Kopfzeile adresse (an beliebiger Stelle, Groß-/Kleinschreibung egal), wird nur diese Spalte gelesen — eine Objekt-ID oder Fläche daneben wandert nicht in die Adresse. Ist adresse die einzige Spalte, dürfen die Adressen selbst Kommas enthalten; die Felder einer Zeile werden dann zusammengefügt. Ohne erkennbare Kopfzeile werden die Felder einer Zeile ebenfalls zusammengefügt. Steht die Adresse über mehrere Spalten verteilt (etwa adresse;plz;ort), wird nur adresse gelesen — dann gehört die vollständige Adresse in eine einzige Spalte.

Die Antwort sagt, was verstanden wurde. POST /api/v1/batch liefert ein Feld gelesen mit erkanntes_trennzeichen, adressspalte, gelesene_zeilen, duplikate_entfernt, kopfzeile_verworfen und beispiel_erste_adresse. An der Beispieladresse ist auf einen Blick zu sehen, ob die Datei richtig gelesen wurde — bevor der Lauf durch ist.

"gelesen": {
  "gelesene_zeilen": 42, "duplikate_entfernt": 2,
  "erkanntes_trennzeichen": ";", "trennzeichen_sicher": true,
  "adressspalte": "adresse", "kopfzeile_verworfen": false,
  "beispiel_erste_adresse": "Domplatz 1, 39104 Magdeburg",
  "modus": "adresse", "ignorierte_spalten": []
}

Drei Suchmodi auch im Batch. Welchen eine Datei benutzt, ergibt sich aus ihren Spaltenüberschriften — erkannt werden (Groß-/Kleinschreibung egal):

ModusErkannte SpaltennamenGilt für
adresseadresse, address, adressenalle Länder
koordinatelat, latitude, breitengrad, breite · lon, lng, long, longitude, laengengrad, laenge · dazu land bzw. bundeslandalle Länder, land erforderlich
flurstueckgemarkung · flur · flurstueck, flurstuecksnummer, zaehler · nenner · land15 Länder

Eine Datei benutzt genau einen Modus. Stehen Spalten mehrerer Modi nebeneinander, gewinnt der spezifischere (Koordinate vor Flurstück vor Adresse) und die übergangenen werden in ignorierte_spalten genannt — eine Datei mit adresse und lat/lon wäre sonst eine Wundertüte: Welcher Weg gelaufen ist, sähe man erst am Ergebnis. modus nennt den erkannten Weg, beispiel_erste_adresse zeigt die erste gelesene Eingabe im Klartext.

lat,lon,land
52.1249036,11.6356315,ST
50.941357,6.958307,NW

gemarkung,flur,flurstueck,nenner,land
Köln,030,344,17,NW

Copy-&-Paste-Beispiele

curl

# Einzelabfrage, ohne Key
curl "https://IHRE-DOMAIN/api/v1/abfrage?adresse=Domplatz%201%2C%2039104%20Magdeburg"

# Einzelabfrage, mit API-Key
curl -H "X-API-Key: IHR_KEY" \
  "https://IHRE-DOMAIN/api/v1/abfrage?adresse=Domplatz%201%2C%2039104%20Magdeburg"

# Batch-Upload (mit Key via Bearer)
curl -H "Authorization: Bearer IHR_KEY" \
  -F "datei=@adressen.csv" \
  "https://IHRE-DOMAIN/api/v1/batch"

Python (requests)

import requests

BASIS = "https://IHRE-DOMAIN"

# ohne Key
r = requests.get(f"{BASIS}/api/v1/abfrage",
                 params={"adresse": "Domplatz 1, 39104 Magdeburg"})
print(r.json())

# mit Key
kopf = {"X-API-Key": "IHR_KEY"}
r = requests.get(f"{BASIS}/api/v1/abfrage",
                 params={"adresse": "Domplatz 1, 39104 Magdeburg"},
                 headers=kopf)
print(r.headers.get("X-RateLimit-Remaining"), r.json())

# Batch mit Key
with open("adressen.csv", "rb") as f:
    r = requests.post(f"{BASIS}/api/v1/batch",
                      files={"datei": f}, headers=kopf)
job = r.json()["job_id"]

JavaScript (fetch)

const BASIS = "https://IHRE-DOMAIN";

// ohne Key
const r1 = await fetch(
  `${BASIS}/api/v1/abfrage?adresse=` +
  encodeURIComponent("Domplatz 1, 39104 Magdeburg"));
console.log(await r1.json());

// mit Key
const r2 = await fetch(
  `${BASIS}/api/v1/abfrage?adresse=` +
  encodeURIComponent("Domplatz 1, 39104 Magdeburg"),
  { headers: { "X-API-Key": "IHR_KEY" } });
console.log(r2.headers.get("X-RateLimit-Remaining"), await r2.json());

// Batch mit Key
const fd = new FormData();
fd.append("datei", dateiObjekt);   // File aus 
const r3 = await fetch(`${BASIS}/api/v1/batch`,
  { method: "POST", body: fd, headers: { "X-API-Key": "IHR_KEY" } });

Fehlercodes

CodeBedeutung
400Ungültige Eingabe (keine Adressen erkannt oder zu viele Adressen im Batch)
401Ungültiger API-Key
404Job oder Ergebnis nicht gefunden
413Upload zu groß (max. 1 MB)
429Rate-Limit überschritten (siehe X-RateLimit-*-Header)

Fehler werden als JSON { "detail": "..." } mit deutscher Meldung zurückgegeben. Ein Abruffehler erscheint nie als „0 Treffer“, sondern als Fehler-/Hinweistext im jeweiligen Ergebnis.

Quellenvermerkspflicht

Die gelieferten Werte stammen unverändert aus amtlichen Diensten der Bundesländer und stehen unter Lizenzen wie dl-de/by-2-0 bzw. dl-de/zero-2.0. Bei jeder Weiterverwendung der Daten sind die zugehörigen Quellen-/Namensnennungen mitzuführen. Die vollständige Liste liefert GET /api/v1/laender (Feld quellenvermerke) und steht in jedem Export. Maschinenlesbar liegt sie je Treffer im Feld attribution vor.

Geocoding: Koordinaten stammen von © OpenStreetMap-Mitwirkenden (ODbL), ermittelt über Nominatim / Photon — bei Weitergabe von Koordinaten mitzuführen.