---
operation_id: get_terrain_profile
method: GET
path: /v1/terrain/profile
summary: Höhenprofil entlang einer Polyline
tags: [terrain]
stability: stable
since_version: 0.1.0
auth: none
data_product: terrain
snapshot_aware: true
attribution_block: false
rate_limit_tier: public
related:
  - /v1/terrain/elevation
  - /v1/terrain/datasets
---
# `GET /v1/terrain/profile` — Höhenprofil entlang einer Linie

Sampelt die Geländehöhe (DHHN2016) an N gleichverteilten Punkten entlang einer WGS84-Polyline. Liefert GeoJSON-FeatureCollection mit kumulierten Distanzen + Pro-Tile-Quellen-Tracking.

## Wann verwenden

- Wanderwege / Mountainbike-Strecken-Tools (Höhenprofil-Chart).
- Lineare Infrastruktur-Planung (Glasfaser, Leitungen, Bahn).
- Sichtachsen-Analyse über Gelände.

Für **eine einzelne Punktabfrage** ist `/v1/terrain/elevation` schneller — `/profile` öffnet pro betroffenem Tile eine separate COG-Sample-Operation (Batch-optimiert).

## Examples

### curl — 500 Punkte über 10 km

```bash
curl -s 'https://api.lodapi.de/v1/terrain/profile?coords=13.37,52.51;13.45,52.55&samples=500' \
  | jq '.properties, .features[0]'
```

### Python — Chart-Datenpunkte

```python
import httpx, json

r = httpx.get(
    "https://api.lodapi.de/v1/terrain/profile",
    params={"coords": "13.37,52.51;13.40,52.53;13.45,52.55", "samples": 200},
)
data = r.json()
chart = [
    (f["properties"]["distance_m"], f["properties"]["elevation_m"])
    for f in data["features"]
    if f["properties"]["elevation_m"] is not None
]
print(f"Total length: {data['properties']['total_length_m']:.0f} m, {len(chart)} valid samples")
```

## Parameters

| Parameter | In | Type | Required | Default | Range | Beschreibung |
|---|---|---|---|---|---|---|
| `coords` | query | string | yes | — | ≥ 2 Punkte | `lon1,lat1;lon2,lat2[;...]` WGS84 Grad |
| `samples` | query | int | no | 100 | 2..2000 | Anzahl Sample-Punkte |

## Response

`200 OK · application/json` — GeoJSON-FeatureCollection (RFC 7946) mit Lodapi-Erweiterungen in `properties`.

```json
{
  "type": "FeatureCollection",
  "properties": {
    "datum": "DHHN2016",
    "coords_count": 3,
    "samples": 200,
    "total_length_m": 9543.7,
    "partial": false,
    "failed_tile_ids": []
  },
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [13.37, 52.51] },
      "properties": {
        "elevation_m": 38.4,
        "distance_m": 0.0,
        "source_bl": "be",
        "tile_id": "be_33_387_5821"
      }
    }
  ]
}
```

## Partial-Modus

`properties.partial: true` zeigt an, dass **mindestens ein Sample** außerhalb der Coverage liegt oder bei der COG-Sample-Operation gescheitert ist:
- Diese Features haben `elevation_m: null`, `tile_id: null`.
- `properties.failed_tile_ids[]` listet Tile-IDs, deren Read failed ist (Behörden-Server kurz down, NoData-Cluster).
- Die anderen Features sind weiter valide — die Antwort ist **200**, nicht 502.

## Fehler

| Status | Bedingung |
|---|---|
| `400` | `coords` malformed oder < 2 Punkte |
| `404` | **Alle** Samples außerhalb Coverage |
| `422` | `samples` out of range |
| `502` | DB unerreichbar |

## Stolperdrähte

- **Linien-Länge wird in UTM32N gemessen** (auch wenn die Polyline durch UTM33N-Gebiet geht) — minimaler Längenfehler an Region-Grenzen, unter 0,1 %.
- **`samples` skaliert linear mit Antwortgröße** — 2000 Samples × ~150 Bytes/Feature ≈ 300 KB.
- **Pro-Tile-Batching** macht große Profile sehr schnell, weil ein COG einmal geöffnet wird und alle seine Sample-Punkte zusammen abruft.

## Verwandte Endpoints

- [`GET /v1/terrain/elevation`](./get-terrain-elevation.md) — Punktabfrage.
- [`GET /v1/terrain/datasets`](./list-terrain-datasets.md) — Coverage.