GET /v1/terrain/elevation — Punktabfrage Geländehöhe
Liefert die Geländehöhe (DHHN2016, m über NHN) an einem WGS84-Punkt. Die API routet die Anfrage über einen PostGIS-Spatial-Index auf den zuständigen DGM1-Tile und sampelt das Pixel via GDAL/rasterio mit HTTP-Range-Request auf dem Cloud-Optimized GeoTIFF. Kein Bundesland ist hartcodiert — Punkte überall in Deutschland funktionieren, sofern Lodapi den DGM1-Layer für die zuständige Region ingested hat.
Zugang
Ab Tarif Hobby, mit API-Key im Header X-API-Key. Ohne Key antwortet der Endpoint mit 401, mit einem Key unter Hobby mit 403 (beides application/, mit Link auf Key bzw. Tarife). Einen Testkey bekommst du in einer Minute unter lodapi.de/key: 7 Tage gültig, Pro-Umfang, ohne Registrierung. Die Beispiele unten lesen den Key aus der Umgebungsvariable LODAPI_KEY.
Wann verwenden
- Höhenkote für einen Adresspunkt holen (z.B. für PV-Konfigurator, Statik-Vorabprüfung).
- Karten-UI mit Hover-Tooltip „Höhe an Cursor-Position”.
- Geo-Pipeline: LoD2-Gebäude auf Geländehöhe normieren (Z-Differenz Gebäude-First-Floor – Terrain).
Wenn du viele Punkte entlang einer Linie sampeln willst → /v1/. Wenn du eine Fläche als Mesh brauchst → /v1/ (3D-Tiles-Mesh-Tilesets).
Examples
curl — Brandenburger Tor
curl -s -H "X-API-Key: $LODAPI_KEY" \
'https://api.lodapi.de/v1/terrain/elevation?lat=52.5163&lon=13.3777' | jq
{
"elevation_m": 34.95,
"datum": "DHHN2016",
"source_bl": "bb",
"snapshot": "2025-12-18",
"license": "dl-de-zero-2.0",
"attribution": "© SenStadt Berlin (DL-DE/Zero 2.0)",
"tile_id": "bb_33_388_5818"
}
Python — Adresse → Höhe
# pip install lodapi
import os
from lodapi import Client, NotFoundError
def elevation_at(c: Client, lat: float, lon: float) -> float | None:
try:
return c.terrain.elevation(lat=lat, lon=lon).elevation_m
except NotFoundError:
return None # außerhalb der Coverage oder NoData (Wasserfläche)
with Client(api_key=os.environ["LODAPI_KEY"]) as c:
print(elevation_at(c, 52.5163, 13.3777)) # → 34.95
TypeScript — Cesium-Integration
async function clampToGround(lon: number, lat: number) {
const url = new URL("https://api.lodapi.de/v1/terrain/elevation");
url.searchParams.set("lat", String(lat));
url.searchParams.set("lon", String(lon));
// Key nur serverseitig oder in internen Tools einbetten, nie in öffentlichem Frontend-Code.
const r = await fetch(url, { headers: { "X-API-Key": LODAPI_KEY } });
if (r.status === 404) return null;
const { elevation_m } = await r.json();
return Cesium.Cartesian3.fromDegrees(lon, lat, elevation_m);
}
Parameters
| Parameter | In | Type | Required | Default | Range | Beschreibung |
|---|---|---|---|---|---|---|
lat | query | float | yes | — | −90..90 | WGS84-Breite (Grad) |
lon | query | float | yes | — | −180..180 | WGS84-Länge (Grad) |
srs | query | string | no | EPSG:4326 | — | Räumlicher Bezug. Aktuell nur EPSG:4326. |
Response
200 OK · application/ — Schema-Quelle openapi.json (#/).
Felder:
| Feld | Beschreibung |
|---|---|
elevation_m | Höhe in Metern, DHHN2016, gerundet auf 3 Nachkommastellen |
datum | Vertikales Datum (immer DHHN2016 in Phase 1) |
source_bl | 2-Buchstaben-BL-Code des zuständigen Tile |
snapshot | Snapshot-Datum des DGM1-Quelldatensatzes (ISO 8601) |
license | Lizenz-ID (dl-de-zero-2.0, cc-by-4.0, dl-de-by-2.0) |
attribution | Pflicht-Attribution-String für UI-Anzeige |
tile_id | Eindeutige Tile-Kennung (Cache-Key oder Audit-Pfad) |
Fehler
| Status | Bedeutung | Bedingung |
|---|---|---|
401 | Unauthorized | Kein X-API-Key mitgeschickt (oder Key unbekannt/abgelaufen) |
403 | Forbidden | Key-Tarif unter Hobby |
422 | Unprocessable Entity | lat/lon außerhalb Range, srs nicht EPSG:4326 (FastAPI/Pydantic-Validation) |
404 | Not Found, kein Tile | Punkt außerhalb aller ingested Terrain-Coverages |
404 | Not Found, NoData | Tile gefunden, aber Pixel ist NoData (Wasser, Tile-Rand) |
502 | Bad Gateway | COG-Quelle nicht erreichbar (Pass-Through-Modus auf Behörden-Server) |
503 | Service Unavailable | rasterio nicht installiert (deploy issue) |
Alle Fehler sind im RFC-7807-Format (application/).
Stolperdrähte
- Wasserflächen liefern
404mit Hinweis-Text, nicht0.0. Mancher PV-Konfigurator interpretiert0als „Meereshöhe” — der bewusste 404 verhindert das. - Tile-Rand-Pixel werden 0.6 m einwärts gesampelt (siehe ADR-0009 §Edge-Cases) — sonst gibt es zwischen zwei benachbarten Tiles minimale Sprünge.
- CRS-Wechsel für östliche BL (BB/SN/MV/BE) erfolgt automatisch (UTM33N statt UTM32N). Aus Konsumentensicht: WGS84 rein, NHN raus.
source_blist die BL-Zuordnung des Datensatzes, nicht zwingend des Standorts. An Bundesländer-Grenzen kann ein Punkt im BB-Tile liegen, obwohl er administrativ noch zu BE gehört.
Live-Coverage
Stand 2026-06: alle 16 Bundesländer (16/16) via /v1/. Aktuelles Inventar via /v1/.
Verwandte Endpoints
GET /— Coverage + Snapshot-Stand.v1/ terrain/ datasets GET /— Linien-Sampling für mehrere Punkte.v1/ terrain/ profile