GET /v1/buildings

Föderierte LoD2-Gebäude-Suche per Bounding-Box

stable seit v0.1.0 buildings auth: none

Beispiel-Ergebnis

So sieht die Antwort aus

3D-Ansicht eines Frankfurter Innenstadt-Blocks mit rund 370 LoD2-Gebäuden, darunter zwei Hochhäuser. Dachflächen sind orange, Wandflächen hell gefärbt.
Frankfurt-Mitte: 6.356 Surface-Features aus 7 Seiten (Cursor-Pagination), nach building_id gruppiert 367 Gebäude. Jedes Polygon ist ein Feature, eingefärbt nach surface_class. Gerendert aus der echten API-Antwort, kein Mockup. Daten: © Hessisches Landesamt für Bodenmanagement und Geoinformation (HLBG) (Wortlaut aus lodapi.attribution der Antwort (dl-de-zero-2.0))

Aufruf

curl -G https://api.lodapi.de/v1/buildings \
  -d bbox=8.66,50.108,8.665,50.111 \
  -d limit=1000

Antwort, Seite 1 (gekürzt)

{
  "type": "FeatureCollection",
  "bbox": [8.66, 50.108, 8.665, 50.111],
  "count": 1000,
  "limit": 1000,
  "features": [
    {
      "type": "Feature",
      "id": "DEHE06200001bugK",
      "geometry": { "type": "MultiPolygon", "coordinates": [[[[8.663959, 50.110996, 123.42], …]]] },
      "properties": {
        "surface_id": 3977613, "building_id": 3977612, "gmlid": "DEHE06200001bugK",
        "surface_class": 709, "bundesland": "he", "lod": "LoD2"
      }
    },
    …
  ],
  "lodapi": {
    "attribution": [{ "bundesland_code": "he", "license_id": "dl-de-zero-2.0", … }],
    "next": "aGU6NDAwMTI5Nw"
  }
}

Darstellung: three.js, Polygone direkt aus der GeoJSON-Antwort trianguliert. Farben: Dach 712 orange, Wand 709 hell; Boden 710 ausgeblendet.

GET /v1/buildings — Gebäude per Bounding-Box

Föderierte GeoJSON-FeatureCollection aller LoD2-Surfaces innerhalb einer WGS84-Bounding-Box. „Föderiert” bedeutet: die API durchsucht alle Bundesländer mit import_finished_at IS NOT NULL parallel und mischt die Ergebnisse. Aus Konsumentensicht: eine API für 16 Bundesländer.

Wichtig — Surface-Level: Jedes Feature ist eine einzelne Surface (Wall/Ground/Roof), nicht ein ganzes Gebäude. Mehrere Surfaces gehören über building_id zum selben Gebäude — zum Rekonstruieren eines Gebäudes nach building_id gruppieren.

Wann verwenden

  • Karten-Frontends, die Gebäude-Footprints + 3D-Geometrie auf einer Region brauchen.
  • Analyse-Scripts (Building-Count pro Stadtteil, Attribut-Filter).
  • 3D-Renderer mit eigener Triangulation (statt fertiges 3D-Tiles aus /v1/tilesets).

Wenn du eine bbox > ~1 km² brauchst → eher /v1/tilesets verwenden (3D-Tiles streamen). /v1/buildings ist für detail-orientierte, kleinflächige Queries.

Examples

curl — kleine bbox Frankfurt-Mitte

curl -s "https://api.lodapi.de/v1/buildings?bbox=8.66,50.108,8.665,50.111&limit=50" | jq '.count, .features[0].properties'

Python — bbox + Pagination

# pip install lodapi
from lodapi import Client

# .iter() folgt dem Cursor (lodapi.next) automatisch über alle Seiten
with Client() as c:
    for feature in c.buildings.iter(bbox=(8.6995, 50.1225, 8.7005, 50.1235), limit=1000):
        print(feature["id"], feature["properties"]["surface_class"])

TypeScript — Cesium-Anbindung

import * as Cesium from "cesium";

const r = await fetch(
  "https://api.lodapi.de/v1/buildings?bbox=8.66,50.108,8.665,50.111&limit=200"
);
const fc = await r.json();
const ds = await Cesium.GeoJsonDataSource.load(fc, { clampToGround: false });
viewer.dataSources.add(ds);

Parameters

ParameterInTypeRequiredDefaultBeschreibung
bboxquerystringyes—WGS84 minLon,minLat,maxLon,maxLat (Komma-separiert)
limitqueryintno1001 ≤ limit ≤ 1000
cursorquerystringno—Opaque cursor aus lodapi.next des vorherigen Calls

Response

200 OK · application/json — GeoJSON-FeatureCollection. Schema-Quelle openapi.json.

{
  "type": "FeatureCollection",
  "bbox": [8.66, 50.108, 8.665, 50.111],
  "count": 47,
  "limit": 100,
  "features": [
    {
      "type": "Feature",
      "id": "DEHE06200001chAX",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [[[ [8.661, 50.108, 105.2], ... ]]]
      },
      "properties": {
        "surface_id": 12345678,
        "building_id": 987654,
        "gmlid": "DEHE06200001chAX",
        "surface_class": 712,
        "bundesland": "he",
        "lod": "LoD2"
      }
    }
  ],
  "lodapi": {
    "attribution": [
      {
        "source": "HLBG",
        "license": "DL-DE/Zero 2.0",
        "url": "https://www.govdata.de/dl-de/zero-2-0",
        "tiles_count": 1
      }
    ],
    "next": "aGU6MTIzNDU2Nzg="
  }
}

Attribution

Jede Antwort enthält lodapi.attribution[] mit einem Eintrag pro Bundesland, das in den features[] vorkommt. Die Felder:

FeldBedeutung
sourceBehörden-/Geobasis-Stelle (z.B. „HLBG”, „BezReg Köln”)
licenseDL-DE/Zero 2.0, CC BY 4.0 oder DL-DE BY 2.0
urlLizenz-URL für Verweis im UI
tiles_countnicht verwendet bei /v1/buildings (immer 1)

Frontend-Pflicht: Bei license != DL-DE/Zero 2.0 muss der source-String sichtbar in der Map-Footer-Zeile stehen (siehe Attribution-Guide).

Cursor-Pagination

/v1/buildings verwendet opaque cursor pagination statt OFFSET, weil OFFSET auf großen PostGIS-bbox-Resultaten pathologisch langsam ist. Der Cursor ist ein base64-codiertes <bundesland>:<surface_id>-Tupel — clients sollten ihn als opak behandeln.

Achtung: Der Cursor ist federation-aware (breaking change ggü. Phase-1-Clients, siehe README). Cursor aus altem Format führen zu 400.

Stolperdrähte

  • limit > 1000 → 422. Validation Error, RFC-7807-Format.
  • bbox ohne korrekte 4 Komma-Werte → 400 mit Hinweis auf minLon,minLat,maxLon,maxLat.
  • bbox außerhalb des WGS84-Wertebereichs → 422 (problem+json), z.B. bbox=200,100,201,101: lon muss in -180..180, lat in -90..90 liegen. Gilt für jeden bbox-Endpoint. (Bis 2026-08-31 war das ein nackter 500 aus ST_Transform, T-0087.)
  • bbox-Area-Limit gibt es nicht auf /v1/buildings — aber: bei sehr großen bboxen werden viele Pages gezogen. Für Großflächen-Use-Cases ist /v1/tilesets der richtige Pfad (3D-Tiles streamen statt FeatureCollection).
  • Sehr dichte Innenstadt-bboxen (≳1–2 km²) → 504 (problem+json), wenn die Query das 12s-Budget reißt. Reaktion: bbox verkleinern/vierteln oder limit senken. (Bis 2026-07 war das ein nackter 500.)
  • next liegt unter lodapi.next, nicht top-level — null = letzte Page.
  • features[0].properties.bundesland ist der unprefixte 2-Buchstaben-Code ("he", "nrw", …), keinerlei BL-Prefix in den IDs in dieser Property.
  • Surface-Level, nicht Building-Level: ein Feature = eine Surface. properties.surface_class ist die CityGML-ObjectClass-ID: 709 = WallSurface, 710 = GroundSurface, 712 = RoofSurface. Zum Rekonstruieren eines kompletten Gebäudes die Features nach building_id gruppieren (oder direkt /v1/buildings/{gmlid} für die aggregierte Geometrie nutzen).
  • Nur Geometrie + Klassifikation: Die Properties sind {surface_id, building_id, gmlid, surface_class, bundesland, lod}. Per-Building-Sachattribute sind im Slim-Datenbestand nicht enthalten; ältere Feldnamen wie roof_type/tile_x/tile_y/feature_id existieren nicht.

Verwandte Endpoints

Verwandt

  • /v1/buildings/{gmlid}
  • /v1/buildings/3d.glb
  • /v1/tilesets

Bereit?

Der erste Call geht sofort.

LoD2-Gebäude für alle 16 Bundesländer, kostenlos und ohne Konto. Pro auf Anfrage 30 Tage testen.