---
operation_id: list_buildings_bbox
method: GET
path: /v1/buildings
summary: Föderierte LoD2-Gebäude-Suche per Bounding-Box
tags: [buildings]
stability: stable
since_version: 0.1.0
auth: none
data_product: buildings
snapshot_aware: true
attribution_block: true
rate_limit_tier: public
related:
  - /v1/buildings/{gmlid}
  - /v1/buildings/3d.glb
  - /v1/tilesets
---
# `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

```bash
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

```python
import httpx

def fetch_all_buildings(bbox: str, limit: int = 1000):
    cursor = None
    while True:
        params = {"bbox": bbox, "limit": limit}
        if cursor:
            params["cursor"] = cursor
        r = httpx.get("https://api.lodapi.de/v1/buildings", params=params)
        r.raise_for_status()
        data = r.json()
        yield from data["features"]
        cursor = data["lodapi"]["next"]
        if not cursor:
            break

for feature in fetch_all_buildings("8.66,50.108,8.69,50.13"):
    print(feature["id"], feature["properties"]["surface_class"])
```

### TypeScript — Cesium-Anbindung

```ts
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

| Parameter | In | Type | Required | Default | Beschreibung |
|---|---|---|---|---|---|
| `bbox` | query | string | yes | — | WGS84 `minLon,minLat,maxLon,maxLat` (Komma-separiert) |
| `limit` | query | int | no | 100 | 1 ≤ limit ≤ 1000 |
| `cursor` | query | string | no | — | Opaque cursor aus `lodapi.next` des vorherigen Calls |

## Response

`200 OK · application/json` — GeoJSON-FeatureCollection. Schema-Quelle [`openapi.json`](../openapi/openapi.json).

```json
{
  "type": "FeatureCollection",
  "bbox": [8.66, 50.108, 8.665, 50.111],
  "count": 47,
  "limit": 100,
  "features": [
    {
      "type": "Feature",
      "id": "DEHE_LOD2_45292_GMLID_1",
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [[[ [8.661, 50.108, 105.2], ... ]]]
      },
      "properties": {
        "surface_id": 12345678,
        "building_id": 987654,
        "gmlid": "DEHE_LOD2_45292_GMLID_1",
        "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:

| Feld | Bedeutung |
|---|---|
| `source` | Behörden-/Geobasis-Stelle (z.B. „HLBG", „BezReg Köln") |
| `license` | DL-DE/Zero 2.0, CC BY 4.0 oder DL-DE BY 2.0 |
| `url` | Lizenz-URL für Verweis im UI |
| `tiles_count` | nicht 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](../guides/attribution.md)).

## 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](../../api/README.md#versions--stabilitäts-modell)). 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-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).
- **`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

- [`GET /v1/buildings/{gmlid}`](./get-building-detail.md) — Single-Building-Detail.
- [`GET /v1/buildings/3d.glb`](./get-buildings-glb.md) — bbox → einzelnes GLB-Mesh.
- [`GET /v1/tilesets`](./list-tilesets-bbox.md) — 3D-Tiles-Streaming für große Flächen.