GET /v1/terrain/elevation

Geländehöhe an einem WGS84-Punkt aus DGM1

stable seit v0.1.0 terrain auth: api_key · ab hobby

Beispiel-Ergebnis

So sieht die Antwort aus

Geländemodell der Saarschleife bei Mettlach mit Höhenfarben von Blau (Fluss) bis Weiß (Hochfläche). Drei Punkte sind mit ihrer abgefragten Höhe beschriftet: 167,5 m, 288,43 m und 379,4 m.
Drei Punktabfragen an der Saarschleife: Flussniveau, Hang über dem Tal und Hochfläche, jeweils elevation_m in DHHN2016 aus dem saarländischen DGM1 (source_bl sl, Snapshot 2026-06-01). Gerendert aus der echten API-Antwort, kein Mockup. Daten: © GeoBasis DE/LVGL-SL (2026), dl-de/by-2.0 (Wortlaut aus Feld attribution der Antwort)

Aufruf

# Flussniveau → 167.5
curl -G https://api.lodapi.de/v1/terrain/elevation \
  -H "X-API-Key: $LODAPI_KEY" \
  -d lat=49.4969 -d lon=6.5467

# Hang über dem Tal → 288.43
curl -G https://api.lodapi.de/v1/terrain/elevation \
  -H "X-API-Key: $LODAPI_KEY" \
  -d lat=49.4996 -d lon=6.5688

# Hochfläche → 379.4
curl -G https://api.lodapi.de/v1/terrain/elevation \
  -H "X-API-Key: $LODAPI_KEY" \
  -d lat=49.5113 -d lon=6.5218

Antwort des ersten Calls (vollständig)

{
  "elevation_m": 167.5,
  "datum": "DHHN2016",
  "source_bl": "sl",
  "snapshot": "2026-06-01",
  "license": "dl-de-by-2.0",
  "attribution": "© GeoBasis DE/LVGL-SL (2026), dl-de/by-2.0",
  "tile_id": "32_321_5485"
}

Darstellung: CesiumJS. Die Pins stehen auf den zurückgegebenen Höhen, das Gelände darunter ist das Terrain-Mesh aus /v1/terrain-mesh/datasets. Höhenfarben 160–420 m von uns.

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/problem+json, 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/terrain/profile. Wenn du eine Fläche als Mesh brauchst → /v1/terrain-mesh/datasets (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

ParameterInTypeRequiredDefaultRangeBeschreibung
latqueryfloatyes—−90..90WGS84-Breite (Grad)
lonqueryfloatyes—−180..180WGS84-Länge (Grad)
srsquerystringnoEPSG:4326—Räumlicher Bezug. Aktuell nur EPSG:4326.

Response

200 OK · application/json — Schema-Quelle openapi.json (#/components/schemas/ElevationResponse).

Felder:

FeldBeschreibung
elevation_mHöhe in Metern, DHHN2016, gerundet auf 3 Nachkommastellen
datumVertikales Datum (immer DHHN2016 in Phase 1)
source_bl2-Buchstaben-BL-Code des zuständigen Tile
snapshotSnapshot-Datum des DGM1-Quelldatensatzes (ISO 8601)
licenseLizenz-ID (dl-de-zero-2.0, cc-by-4.0, dl-de-by-2.0)
attributionPflicht-Attribution-String für UI-Anzeige
tile_idEindeutige Tile-Kennung (Cache-Key oder Audit-Pfad)

Fehler

StatusBedeutungBedingung
401UnauthorizedKein X-API-Key mitgeschickt (oder Key unbekannt/abgelaufen)
403ForbiddenKey-Tarif unter Hobby
422Unprocessable Entitylat/lon außerhalb Range, srs nicht EPSG:4326 (FastAPI/Pydantic-Validation)
404Not Found, kein TilePunkt außerhalb aller ingested Terrain-Coverages
404Not Found, NoDataTile gefunden, aber Pixel ist NoData (Wasser, Tile-Rand)
502Bad GatewayCOG-Quelle nicht erreichbar (Pass-Through-Modus auf Behörden-Server)
503Service Unavailablerasterio nicht installiert (deploy issue)

Alle Fehler sind im RFC-7807-Format (application/problem+json).

Stolperdrähte

  • Wasserflächen liefern 404 mit Hinweis-Text, nicht 0.0. Mancher PV-Konfigurator interpretiert 0 als „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_bl ist 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/terrain/elevation. Aktuelles Inventar via /v1/terrain/datasets.

Verwandte Endpoints

Verwandt

  • /v1/terrain/datasets
  • /v1/terrain/profile

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.