Slope at the path (experimental)
POST https://api.trailsplits.com/v1/route-slopes
Checked by a live probe Key optional · 500 credits a day without one
Experimental. The stretches of a line where the terrain model at the path is 30° or steeper, in three classes (30–35°, 35–40°, 40° or more), each with the way the slope faces, plus the distance assessed and unknown and links to the official avalanche bulletins whose areas the line touches. It is the slope at the path: not the path’s own gradient, not the slopes above or beside it, not avalanche terrain and not a risk. The terrain model is about 26 m (never 2 m). Unknown is an answer, never flat: terrain_not_float_first means the area’s terrain model is being rebuilt (until about 9 October 2026). Bulletins are links by coarse area, never readings. 2 credits.
Example
# Without a key, leave out the Authorization line (500 credits a day per address).
curl --fail-with-body 'https://api.trailsplits.com/v1/route-slopes' \
-H "Authorization: Bearer $TRAILSPLITS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"geometry":{"type":"LineString","coordinates":[[7.70897,45.99171],[7.70598,45.98992],[7.70144,45.98991],[7.69482,45.98835],[7.69172,45.98857],[7.68236,45.98436],[7.68161,45.98354],[7.6798,45.98287],[7.67891,45.98253],[7.6774,45.98226],[7.67624,45.9823],[7.67478,45.98162]]}}' Request body
| Field | Type | Description |
|---|---|---|
gpx | string | One line as GPX (several parts allowed; distances skip the gaps). Or geometry, not both. Limits: 120 km, 5,000 points, 1 MB. There are no thresholds to set. |
geometry | object | A GeoJSON LineString or MultiLineString, [lon, lat]. |
Response
| Field | Type | Description |
|---|---|---|
schema | string: route-slopes/1 | |
experimental | boolean | |
label | string | "slope at the path" |
engine | object | |
input | object | |
method | object | Horn’s 3 × 3 on the ~26 m terrain model, every 25 m, with the resolution at the line’s latitude. |
classes | array | |
totals | object | |
spans | array | |
runs_from_30 | array | |
unknown_spans | array | |
bulletins | array | |
unknowns | array |
Full response schema (JSON Schema)
{
"type": "object",
"properties": {
"schema": {
"type": "string",
"enum": [
"route-slopes/1"
]
},
"experimental": {
"type": "boolean"
},
"label": {
"type": "string",
"description": "\"slope at the path\""
},
"engine": {
"type": "object"
},
"input": {
"type": "object",
"properties": {
"format": {
"type": "string"
},
"parts": {
"type": "integer"
},
"points": {
"type": "integer"
},
"length_m": {
"type": "number"
},
"gaps_m": {
"type": "array",
"items": {
"type": "number"
}
}
},
"required": [
"length_m"
]
},
"method": {
"type": "object",
"description": "Horn’s 3 × 3 on the ~26 m terrain model, every 25 m, with the resolution at the line’s latitude."
},
"classes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"enum": [
"30_35",
"35_40",
"40_plus"
]
},
"from_deg": {
"type": "number"
},
"to_deg": {
"type": "number",
"nullable": true
}
},
"required": [
"id",
"from_deg"
]
}
},
"totals": {
"type": "object",
"properties": {
"length_m": {
"type": "number"
},
"assessed_m": {
"type": "number"
},
"unknown_m": {
"type": "number"
},
"from_30_m": {
"type": "number"
},
"from_35_m": {
"type": "number"
},
"from_40_m": {
"type": "number"
}
},
"required": [
"length_m",
"assessed_m",
"unknown_m",
"from_30_m",
"from_35_m",
"from_40_m"
]
},
"spans": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from_m": {
"type": "number"
},
"to_m": {
"type": "number"
},
"class": {
"type": "string",
"enum": [
"30_35",
"35_40",
"40_plus"
]
},
"max_slope_deg": {
"type": "number"
},
"aspect": {
"type": "string"
},
"aspect_deg": {
"type": "number"
},
"method": {
"type": "string"
},
"source": {
"type": "string"
},
"resolution_m": {
"type": "number"
}
},
"required": [
"from_m",
"to_m",
"class",
"max_slope_deg"
]
}
},
"runs_from_30": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from_m": {
"type": "number"
},
"to_m": {
"type": "number"
},
"length_m": {
"type": "number"
},
"max_slope_deg": {
"type": "number"
}
},
"required": [
"from_m",
"to_m",
"length_m",
"max_slope_deg"
]
}
},
"unknown_spans": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from_m": {
"type": "number"
},
"to_m": {
"type": "number"
},
"reason": {
"type": "string"
}
},
"required": [
"from_m",
"to_m",
"reason"
]
}
},
"bulletins": {
"type": "array",
"items": {
"type": "object",
"properties": {
"service": {
"type": "string"
},
"area": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"service",
"area",
"url"
]
}
},
"unknowns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
]
}
}
},
"required": [
"schema",
"experimental",
"label",
"engine",
"input",
"classes",
"totals",
"spans",
"runs_from_30",
"unknown_spans",
"bulletins",
"unknowns"
]
}Errors
400, 413, 422, plus the gateway's 401, 429 and 503 (error conventions). A refused request costs no credits.
Contract
It gives the stretches of a line where the terrain model at the path is 30° or steeper, in three classes: 30–35°, 35–40°, and 40° or more. Each stretch comes with the way the slope faces, its method, its source and the real resolution. The answer also gives the distance assessed and the distance unknown, and links to the official avalanche bulletins whose areas the line touches.
What it is, and what it is not.
- Slope at the path. This is the slope of the terrain model where the path runs. It is not the path's own gradient, and it leaves out the slopes above and beside the path. It is therefore not avalanche terrain, not a risk and not a safety claim. A path with no stretch listed can still run below or beside steep slopes.
- A model of about 26 m. The served terrain is Copernicus GLO-30 as TerrainRGB at z12, about 26 m per pixel at 46° N. That holds in Switzerland too: national models patched in are averaged into these pixels, so this is never 2 m. Steps narrower than the window are smoothed and may read lower. The path's mapped position can also be off by some metres.
- Unknown is an output. Where a terrain tile is missing or reads no data, the stretch is unknown and counted as such, never read as flat.
- Bulletins are links. They are listed by coarse area, never read or summarised. The service's own map says which of its regions a slope is in.
Request
{ "gpx": "<gpx…>" }
{ "geometry": { "type": "LineString", "coordinates": [[lon, lat], …] } }
| Field | ||
|---|---|---|
gpx or geometry | one of them | As for route analysis, with a limit of 120 km (a day's tour) and 5,000 points. Several parts are allowed, and distances skip the gaps between them |
caller | Optional label |
There are no thresholds to set: the classes are fixed, so answers compare.
Response
| Field | Meaning |
|---|---|
schema, experimental, label | route-slopes/1, true, slope at the path |
input | format, parts, points, length_m, gaps_m |
geometry_revision | sha256:… of the line as given (to 1e-6°): the line these distances are along |
generated_at | When the answer was made |
method | name (horn_3x3 on ~26 m GLO-30 (float-first), with the spacing of Horn's cells: the z12 pixel, or a multiple of it where pixels are finer than about 26 m, so the window stays about 52 m across at every latitude and the classes compare), description, every_m (25), window_m (across the window, about 52 m), resolution_m (the spacing of Horn's cells at the line's latitude), source, and a note in words |
terrain_release | The float-first terrain release read |
classes | 30_35, 35_40, 40_plus with their bounds in degrees |
totals | length_m, assessed_m, unknown_m, and from_30_m, from_35_m, from_40_m (cumulative: 30° or more, …) |
runs_from_30[] | from_m, to_m, length_m, max_slope_deg: maximal stretches at 30° or more, bridging gaps under 50 m below 30°. An unknown point ends a run. For apps; runs_note says so |
unknown_spans[] | from_m, to_m, reason: no_terrain (a missing tile or no data) or terrain_not_float_first |
bulletins[] | service, area, url: every official avalanche bulletin whose coarse area the line touches. For Europe this always includes EAWS, the directory of all official services. Empty where none is listed |
bulletins_note | In words: links by coarse area, not readings |
unknowns[] | code, message: terrain_tiles_missing (some tiles did not load), terrain_unavailable (no terrain configured) or terrain_not_float_first ("This area's terrain model is being rebuilt; slope classes return when it is.") |
timing | tiles, samples |
Each sample stands for the line halfway to its neighbours, within its part: spans and runs never cross from one part of a file to the next. max_slope_deg is rounded down to a tenth, so it never reads as its class's upper bound. A span is a run of samples in one class, so spans can be as short as 25 m: they are what the model reads. runs_from_30 merges them for display.
Errors
{ "error": { "code", "message" } }.
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request | Not JSON, an unknown field, both or neither of gpx/geometry |
| 400 | invalid_gpx, invalid_coordinates | As for route analysis |
| 405 | method_not_allowed | Any method but POST (and OPTIONS) |
| 413 | body_too_large, too_many_points | Over 1 MB, or over 5,000 points |
| 422 | too_long, no_line | Over 120 km, or no line of two different points |
| 422 | too_large | The line would read more than 120 terrain tiles (a guard; a 120 km line reads a few dozen) |
| 422 | budget_exhausted | The job's 25 s budget ran out waiting for terrain |
Versioning
Additive fields may appear in route-slopes/1. A change of meaning (classes, window, method) is route-slopes/2.