Route brief
POST https://api.trailsplits.com/v1/route-brief
Checked by a live probe Key optional · 500 credits a day without one Heavy: 1 at a time on Free
One call for one day’s line: route analysis, weather at arrival time, sun and shade, places along the route and snow evidence, picked with include, each the same answer its own endpoint gives. On top, notices are fact codes placed along the line (a ford, a stretch tagged T4, 7 km without mapped water, a thunderstorm in the model at the hour you get there), each with its part and source. Notices are facts, never advice, gear or a safety score; snow_observed is never "now". A part that fails is null with the reason in unknowns. Heavy request; 10 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-brief' \
-H "Authorization: Bearer $TRAILSPLITS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"geometry":{"type":"LineString","coordinates":[[6.97178,45.79266],[6.98409,45.80185],[6.98629,45.80488],[6.98231,45.80634],[6.9782,45.80782],[6.9784,45.81286],[6.98961,45.82424],[7.00303,45.82901],[7.0139,45.83525],[7.02084,45.83669],[7.02859,45.84621],[7.03402,45.84664]]},"include":["analysis","places"]}' Request body
| Field | Type | Description |
|---|---|---|
gpx | string | One line as GPX, one part, at most 120 km and 5,000 points. Or geometry, not both. |
geometry | object | A GeoJSON LineString, [lon, lat]. |
include | array | The parts to give; default all. |
departure | string | ISO 8601 with offset, six hours ago to 16 days ahead. Required with weather or sun, refused without them. |
profile | string: hike | run | bike | |
pace_factor | number | |
min_per_km | number | |
kmh | number | |
stops | array |
Response
| Field | Type | Description |
|---|---|---|
schema | string: route-brief/1 | |
engine | object | |
include | array | |
settings_defaulted | array | |
line | object | |
notices | array | |
analysis | object or null | As POST /v1/route-analysis answers, or null (see unknowns). |
weather | object or null | As POST /v1/route-weather answers (with sun when included), or null. |
places | object or null | As POST /v1/route-places answers, or null. |
snow | object or null | The snow evidence along the line, or null (snow_not_assessed below 800 m outside the snow months). |
unknowns | array |
Full response schema (JSON Schema)
{
"type": "object",
"properties": {
"schema": {
"type": "string",
"enum": [
"route-brief/1"
]
},
"engine": {
"type": "object"
},
"include": {
"type": "array",
"items": {
"type": "string"
}
},
"settings_defaulted": {
"type": "array",
"items": {
"type": "string"
}
},
"line": {
"type": "object",
"properties": {
"length_m": {
"type": "number"
},
"points": {
"type": "integer"
}
},
"required": [
"length_m",
"points"
]
},
"notices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "A fact code, such as ford, via_ferrata, difficulty_t4_or_harder, off_mapped_paths, no_mapped_water_km, snow_observed, thunderstorm_forecast, storm_energy_cape, freezing_temperature, strong_gusts, beyond_civil_twilight. New codes may appear; ignore unknown ones."
},
"from_m": {
"type": "number"
},
"to_m": {
"type": "number"
},
"value": {
"type": "number",
"nullable": true
},
"unit": {
"type": "string",
"nullable": true
},
"rule": {
"type": "string",
"nullable": true
},
"part": {
"type": "string"
},
"source": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"from_m",
"to_m",
"part",
"source",
"message"
]
}
},
"analysis": {
"type": "object",
"nullable": true,
"description": "As POST /v1/route-analysis answers, or null (see unknowns)."
},
"weather": {
"type": "object",
"nullable": true,
"description": "As POST /v1/route-weather answers (with sun when included), or null."
},
"places": {
"type": "object",
"nullable": true,
"description": "As POST /v1/route-places answers, or null."
},
"snow": {
"type": "object",
"nullable": true,
"description": "The snow evidence along the line, or null (snow_not_assessed below 800 m outside the snow months)."
},
"unknowns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"part": {
"type": "string"
},
"code": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
]
}
}
},
"required": [
"schema",
"engine",
"include",
"line",
"notices",
"unknowns"
]
}Errors
400, 413, 422, 503, plus the gateway's 401, 429 and 503 (error conventions). A refused request costs no credits.
Contract
One call for one day's line, with include picking the parts:
- route analysis;
-
route weather, with the sun and shade when
sunis included; - places along the route;
Each part is the same answer its own endpoint gives for the same line and settings. On top of them, notices[] holds fact codes, each with a position on the line, a value where one applies, the part it comes from and its source.
What it does not do. Notices are facts, never advice. There is no gear list, no safety score and no avalanche or risk judgement. An app turns the codes into its own words: a long stretch without mapped water may become "carry water" in one app and nothing in another.
Request
{ "gpx": "<gpx…>", "departure": "2026-10-04T07:00:00+02:00" }
{ "geometry": { "type": "LineString", "coordinates": [[lon, lat], …] }, "include": ["analysis", "places", "snow"] }
| Field | ||
|---|---|---|
gpx or geometry | one of them | One line (one part), at most 120 km (one day) and 5,000 points |
include | default all but slopes | Any of analysis, weather, sun, places, snow, and slopes, which is only given when asked for (experimental, route-slopes-v1) |
departure | with weather or sun | As for route weather: an ISO time with its offset, from six hours ago to 16 days ahead. Refused without weather or sun |
profile | hike (default), run, bike | Used by analysis and weather |
pace_factor, min_per_km, kmh, stops | As for route weather; only with weather or sun | |
caller | Optional label |
Each part checks its own fields with its own rules and words, as its endpoint does.
Response
| Field | Meaning |
|---|---|
schema | route-brief/1 |
include, settings_defaulted | The parts given, and the fields not given |
line | length_m, points |
notices[] | In order along the line (by start, then end). Each has code, from_m, to_m, value and unit where one applies, rule for a notice that compares a value, part, source and message |
analysis, weather, places, snow, slopes | Each included part as its endpoint answers it (without the engine stamp), or null when that part could not be had (see unknowns). With sun, the weather part carries sun |
unknowns[] | part, code, message: a part that failed, with its own refusal code (e.g. forecast_unavailable, places_unavailable, snow_unavailable). budget_exhausted: the part was still running at the job's deadline, and its late result is dropped. snow_not_assessed: the line stays below 800 m outside the snow months, with the reason in words. The brief answers with the parts it has |
Notice codes
| Code | From | When | Source |
|---|---|---|---|
ford, aid, via_ferrata | analysis | A mapped ford, aided passage (ladders, ropes, rungs) or via ferrata on the matched line; value its length in m | OpenStreetMap way |
difficulty_t4_or_harder | analysis | The hardest stretch is tagged T4 or harder | OpenStreetMap sac_scale |
off_mapped_paths | analysis | A stretch of 200 m or more follows no mapped path | Map matching on OpenStreetMap |
no_mapped_water_km | places | The longest stretch without mapped drinking water is 5 km or more; value in km. Mapped is not running | OpenStreetMap through the places index |
snow_observed | snow | A run of points observed as snow, with its heights. Said with the evidence's own date (the oldest along the line) when it has one; v1 tiles carry none, so it says "the latest satellite and model observation", which can be days old (cloud), and names the 14-day mosaic when used. Never "current", never a forecast for the day you walk | TrailSplits snow evidence (satellite and model) |
thunderstorm_forecast | weather | The model codes a thunderstorm (95–99) at the hour you reach points of a section; value the samples | weather-forecast/1 and its model |
storm_energy_cape | weather | The model's CAPE reaches 1,000 J/kg or more in a section: what its atmosphere could support, not that a storm will happen | weather-forecast/1 |
freezing_temperature | weather | The forecast reaches 0 °C or below at the hour you get there | weather-forecast/1 |
strong_gusts | weather | Gusts of 60 km/h or more | weather-forecast/1 |
beyond_civil_twilight | sun | A stretch walked with the sun more than 6° below the horizon, by the sun's position alone | NOAA solar position |
The slopes part adds no notices while it is experimental. New codes may be added in route-brief/1; an app ignores codes it does not know. A changed meaning of a code is route-brief/2.
Errors
{ "error": { "code", "message" } }, from the brief or from a part's own request rules.
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request | An unknown field, a part not listed, departure missing with weather or sun, or given without them, pace fields without weather or sun, and each part's own request errors |
| 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, several_parts, no_line | Over 120 km, more than one part, or no line |
| 422 | departure_in_past, beyond_forecast | As for route weather |
| 503 | overloaded | The worker's heavy-job queue is full |
A part's failure inside the job (the forecast down, the budget out) is not an error of the brief: that part is null and unknowns says why.
Versioning
Additive fields and new notice codes may appear in route-brief/1. A change of meaning is route-brief/2.