GET /api/bodenrichtwertFür Entwickler
Request
GET https://api.bodenrichtwert.ai/api/bodenrichtwert
Authorization: Bearer brw_pat_...
Query-Parameter
| Name | Pflicht | Typ | Beschreibung |
|---|---|---|---|
address | ja | string | Vollständige Adresse mit PLZ und Ort |
nutzungsart | nein | W | M | G | S | L | F | SO | Filter auf eine oder mehrere Nutzungsarten — Parameter mehrfach anhängen (?nutzungsart=W&nutzungsart=G), nicht kommagetrennt. Ohne Angabe: kein Filter, alle an der Adresse vorhandenen Nutzungsarten werden zurückgegeben |
format | nein | json | xml | Antwortformat, Default json. Siehe XML-Format |
Nutzungsart-Codes:
| Code | Nutzungsart |
|---|---|
W | Wohnbaufläche |
M | Gemischte Baufläche |
G | Gewerbliche Baufläche |
S | Sonderbaufläche (z. B. Kliniken, Schulen) |
L | Landwirtschaftliche Fläche |
F | Forstwirtschaftliche Fläche |
SO | Sonstige Fläche |
Response (200 OK)
bodenrichtwerte ist ein Array und enthält alle an der Koordinate gefundenen Nutzungsarten, sortiert W, M, G, S, L, F, SO — außer der Request filtert mit nutzungsart auf einen oder mehrere bestimmte Codes, dann enthält es nur die passenden Einträge. Reales Beispiel für „Platz d. Menschenrechte 1, 30159 Hannover" mit explizitem ?nutzungsart=S — die Koordinate liegt in der Sonderbaufläche des Regierungsviertels:
{
"address_input": "Platz d. Menschenrechte 1, 30159 Hannover",
"address_resolved": "Platz der Menschenrechte 1, 30159 Hannover - Mitte",
"coordinates": { "lat": 52.368, "lon": 9.737 },
"bodenrichtwerte": [
{
"nutzungsart": "Sonderbaufläche",
"code": "S",
"brw_euro_pro_m2": 800,
"stichtag": "2025-01-01",
"gemeinde": "Hannover",
"gutachterausschuss": "",
"bodenrichtwertnummer": "04305204",
"zonenbezeichnung": "Regierungsviertel"
}
],
"cache_hit": false,
"attribution": {
"text": "© Daten der Gutachterausschüsse für Grundstückswerte 2025, dl-de/by-2-0",
"license_url": "https://www.govdata.de/dl-de/by-2-0",
"year": 2025
},
"disclaimer": "Der Bodenrichtwert ist ein gutachterlicher Orientierungswert — kein Verkehrswert, kein Verkaufspreis, keine Rechtsberatung."
}
Dieselbe Koordinate liegt auch in der flächendeckenden Forst-Zone der Stadt (bodenrichtwertnummer: "04309601"). Mit ?nutzungsart=S&nutzungsart=F (Parameter zweimal anhängen, nicht kommagetrennt) liefert ein einzelner Request beide Einträge zusammen; ganz ohne nutzungsart wären zusätzlich alle anderen an der Koordinate vorhandenen Nutzungsarten enthalten.
Response-Felder pro Bodenrichtwert
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
nutzungsart | string | ja | Menschenlesbare Bezeichnung (z. B. „Wohnbaufläche") |
code | string | ja | Kurz-Code, Enum W | M | G | S | L | F | SO |
brw_euro_pro_m2 | number | ja | Bodenrichtwert in Euro pro Quadratmeter |
stichtag | string | ja | Stichtag im ISO-Format YYYY-MM-DD |
gemeinde | string | ja | Gemeindename |
gutachterausschuss | string | ja | Name des Gutachterausschusses (in NI/einigen Ländern upstream leer — bleibt als Leerstring erhalten) |
bodenrichtwertnummer | string | optional | Eindeutige Zonen-ID (BRN) — stabil pro Koordinate, zitierfähig im Gutachten |
zonenbezeichnung | string | optional | Zonenname (BZN), meist Ortsteil oder Quartier, z. B. „Regierungsviertel" oder „Stederdorf W" |
bauweise | string | optional | Bauweise (BAW), z. B. „offen" / „geschlossen" |
geschossflaechenzahl | number | optional | Geschossflächenzahl (GFZ) |
grundflaechenzahl | number | optional | Grundflächenzahl (GRZ) |
vollgeschosszahl | number | optional | Anzahl Vollgeschosse (VGZ) |
baumassenzahl | number | optional | Baumassenzahl (BMZ) — meist in dichter Gewerbe-/Hochhausbebauung |
wertrel_geschossflaechenzahl | number | optional | Wertrelevante GFZ (WGF) — die vom Gutachterausschuss für den BRW angesetzte Referenz-GFZ. Notwendig, wenn ein Grundstück mit abweichender GFZ umgerechnet werden soll. |
Fehler
Alle Fehler folgen demselben Format: { "error": "<code>", "message": "<Beschreibung>", "status": <HTTP-Status> }.
| Status | Code | Bedeutung |
|---|---|---|
400 | missing_address | Query-Parameter address fehlt |
400 | invalid_nutzungsart | Ungültiger nutzungsart-Code — gültig sind W, M, G, S, L, F, SO |
400 | invalid_format | Ungültiger format-Wert — gültig sind json und xml |
401 | missing_token | Authorization: Bearer <token>-Header fehlt |
401 | invalid_token | Token ungültig oder abgelaufen |
402 | limit_reached | Monatslimit erreicht — Plan upgraden |
402 | payment_past_due | Letzte Zahlung fehlgeschlagen — Zahlungsdaten im Dashboard aktualisieren |
404 | address_not_found | Adresse konnte nicht geokodiert werden |
404 | no_data | Für diese Koordinate liegt kein Bodenrichtwert vor |
429 | rate_limit_exceeded | Zu viele Requests pro Minute (120/min IP-Limit) — Retry-After-Header beachten |
451 | restricted_state | SH/SN/BY — aktuell keine Daten verfügbar |
503 | service_error | Datenquelle temporär nicht erreichbar |
500 | processing_error | Unerwarteter Fehler bei der Verarbeitung |
XML-Format
Mit ?format=xml kommt dieselbe Antwort als application/xml; charset=utf-8 zurück. Gedacht ist das für Clients, die kein JSON parsen können — allen voran Google Sheets =IMPORTXML(), wofür es ein eigenes Cookbook gibt.
Die Abbildung ist strukturell 1:1: jeder JSON-Key wird zu einem gleichnamigen Element, mit derselben Verschachtelung. Die Feldtabellen oben gelten damit unverändert auch für XML. Zwei Konventionen ergeben sich aus dem Format:
- Wurzelelement ist
<response>— JSON-Objekte haben keinen Namen, XML braucht einen. - Einträge des Arrays
bodenrichtwertestehen in<bodenrichtwert>-Elementen.
Optionale Felder fehlen im XML genau dort, wo sie auch im JSON fehlen.
<?xml version="1.0" encoding="UTF-8"?>
<response>
<address_input>Platz d. Menschenrechte 1, 30159 Hannover</address_input>
<address_resolved>Platz der Menschenrechte 1, 30159 Hannover - Mitte</address_resolved>
<coordinates>
<lat>52.368</lat>
<lon>9.737</lon>
</coordinates>
<bodenrichtwerte>
<bodenrichtwert>
<nutzungsart>Sonderbaufläche</nutzungsart>
<code>S</code>
<brw_euro_pro_m2>1300</brw_euro_pro_m2>
<stichtag>2026-01-01</stichtag>
<gemeinde>Hannover</gemeinde>
<gutachterausschuss>Gutachterausschuss für Grundstückswerte Hannover</gutachterausschuss>
</bodenrichtwert>
</bodenrichtwerte>
<cache_hit>false</cache_hit>
<attribution>
<text>© Daten der Gutachterausschüsse für Grundstückswerte 2026, dl-de/by-2-0</text>
<license_url>https://www.govdata.de/dl-de/by-2-0</license_url>
<year>2026</year>
</attribution>
<disclaimer>Amtlicher Bodenrichtwert gemäß dl-de/by-2-0. Gutachterlicher Orientierungswert — kein Verkehrswert, kein Verkaufspreis, keine Rechtsberatung. Stichtag pro Eintrag beachten.</disclaimer>
</response>
Fehler nutzen dieselben Element-Namen wie der JSON-Fehler-Body und behalten ihren HTTP-Status — ein gesperrtes Bundesland bleibt auch im XML-Modus ein 451:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<error>restricted_state</error>
<message>Schleswig-Holstein stellt aktuell keine Bodenrichtwerte bereit.</message>
<status>451</status>
</response>
Zwischenspeicherung
Antworten werden in Cloudflare KV zwischengespeichert (Schlüssel: brw:v5:SHA-256(lat,lon)), unabhängig vom nutzungsart-Filter — intern wird immer der vollständige Datensatz einer Koordinate zwischengespeichert, gefiltert wird bei jedem Read. Liegt bereits ein Ergebnis vor, ist die Response identisch; das Feld cache_hit: true im Response-Body zeigt das an. Die Key-Version sorgt dafür, dass Einträge mit älterer Semantik automatisch ignoriert werden.
Ein Eintrag hat zwei Fenster:
| Alter des Eintrags | Verhalten | Felder in der Response |
|---|---|---|
| bis 24 Stunden | wird direkt ausgeliefert, ohne Rückfrage bei der amtlichen Quelle | cache_hit: true |
| 24 Stunden bis 30 Tage | wird ausgeliefert und im Hintergrund erneuert | cache_hit: true, cache_stale: true |
| älter als 30 Tage | wird verworfen, der Wert wird frisch geholt | cache_hit: false |
cache_stale ist nur vorhanden, wenn es zutrifft — bei einer frisch geprüften Antwort fehlt das Feld ganz (wie jedes optionale Feld dieser API). Es bedeutet nicht, dass der Wert falsch ist: Bodenrichtwerte werden zu einem Stichtag veröffentlicht — mindestens alle zwei Jahre, in vielen Bundesländern jährlich —, und der stichtag pro Eintrag bleibt der maßgebliche Bezugspunkt. Es bedeutet, dass wir den Wert seit über einem Tag nicht mehr gegen die amtliche Quelle prüfen konnten.
Der Zweck des zweiten Fensters ist ein Ausfall der amtlichen Quelle: Statt 503 service_error bekommst du den letzten bekannten Wert, als solchen gekennzeichnet. Ist die Quelle wieder erreichbar, erneuert die erste Abfrage den Eintrag im Hintergrund, und die nächste antwortet wieder ohne cache_stale.