Go windows: which day and start time
POST https://api.trailsplits.com/v1/route-windows
Checked by a live probe Key optional · 500 credits a day without one 3 credits per call
For one day’s line, the next 1–7 days × start times, each window with its forecast facts at the hour you reach each point: wet points, thunderstorm signal and the lowest height it reaches, the lowest feels-like, gusts at the highs, daylight at the start and finish. Ordered by the preferences you give (no_thunder, dry, daylight, calm, warm, cool), each window saying why it sits where it does. An ordering of facts, never a safety score; the thunderstorm signal is the model’s codes or storm energy, not that a storm will happen; snow and closures are not in it. One forecast fetch for all windows. 3 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-windows' \
-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]]},"days":3,"prefer":["no_thunder","dry","daylight"]}' 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]. |
from_date | string | YYYY-MM-DD in the route’s own time, today to 7 days ahead. Default today. |
days | integer | How many days, counting from_date itself (today by default): 1 to 7, default 3. |
starts | array | Local start times HH:MM. Default 06:00 to 10:00 hourly. Or give start_from, start_to and start_step_min instead. |
start_from | string | First start time HH:MM, with start_to and start_step_min, instead of starts. |
start_to | string | Last start time HH:MM. |
start_step_min | integer | Minutes between start times. |
prefer | array | Your preferences in order; default no_thunder, dry, daylight, calm. Not both warm and cool. Windows equal on every preference go to the earlier one, so add calm (or warm, cool) to separate them. |
profile | string: hike | run | bike | hike uses the calibrated hike time; run and bike need min_per_km or kmh. |
pace_factor | number | Hike only: scales the hike time (1.2 = 20 % slower). |
min_per_km | number | Run: your pace on the flat. |
kmh | number | Bike: your speed on the flat. |
stops | array |
Response
| Field | Type | Description |
|---|---|---|
schema | string: route-windows/1 | |
engine | object | |
settings | object | |
settings_defaulted | array | The request fields that were not given and took their defaults. |
moving_minutes | number | Moving time for the line, stops included. |
line | object | points, length_m, heights, terrain_release and samples of the line read. |
forecast | object | |
best | object or null | id, date_local and start_local of the first window, or null. |
windows | array | |
skipped_past | integer | Start times already gone today, left out. |
note | string | |
unknowns | array |
Full response schema (JSON Schema)
{
"type": "object",
"properties": {
"schema": {
"type": "string",
"enum": [
"route-windows/1"
]
},
"engine": {
"type": "object"
},
"settings": {
"type": "object"
},
"settings_defaulted": {
"type": "array",
"items": {
"type": "string"
},
"description": "The request fields that were not given and took their defaults."
},
"moving_minutes": {
"type": "number",
"description": "Moving time for the line, stops included."
},
"line": {
"type": "object",
"description": "points, length_m, heights, terrain_release and samples of the line read."
},
"forecast": {
"type": "object"
},
"best": {
"type": "object",
"nullable": true,
"description": "id, date_local and start_local of the first window, or null."
},
"windows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "\"<date_local>T<start_local>\": stable, for watches and diffs."
},
"rank": {
"type": "integer"
},
"date_local": {
"type": "string"
},
"start_local": {
"type": "string"
},
"departure": {
"type": "string"
},
"finish_local": {
"type": "string"
},
"complete": {
"type": "boolean"
},
"wet": {
"type": "object",
"additionalProperties": true
},
"thunder": {
"type": "object",
"additionalProperties": true,
"description": "Signal points (thunder codes 95–99 or CAPE ≥ 1,000 J/kg): the model’s signal, not that a storm will happen."
},
"feels_like_min_c": {
"type": "number",
"nullable": true
},
"temp_c": {
"type": "array",
"items": {
"type": "number",
"nullable": true
}
},
"gust_max_at_highs_kmh": {
"type": "number",
"nullable": true
},
"daylight": {
"type": "object",
"additionalProperties": true
},
"why": {
"type": "array",
"items": {
"type": "string"
},
"description": "One sentence per preference, in your order. Complete windows first; then each preference; ties go to the earlier window."
}
},
"required": [
"id",
"rank",
"date_local",
"start_local",
"complete",
"why"
]
}
},
"skipped_past": {
"type": "integer",
"description": "Start times already gone today, left out."
},
"note": {
"type": "string"
},
"unknowns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
]
}
}
},
"required": [
"schema",
"engine",
"settings",
"best",
"windows",
"unknowns"
]
}Errors
400, 413, 422, 503, plus the gateway's 401, 429 and 503 (every error code). A refused request costs no credits.
Contract
Which day and start time this week? For one day's line, the next 1–7 days × start times. Each window carries its forecast facts at the hour you reach each point:
- wet points;
- thunderstorm signal, and the lowest height it reaches;
- the lowest feels-like;
- gusts at the highs;
- daylight at the start and the finish.
The windows are ordered by the preferences you give, and each one says why it sits where it does.
What it is, and what it is not.
-
An ordering of facts, never a safety score. There is no "go / no go" and no number for how good a window is.
rankis only the order your preferences give. - Model output. The forecast is weather-forecast/1, as in route weather. The thunderstorm signal is the model's thunder codes (95–99) or its storm energy (CAPE ≥ 1,000 J/kg), not a forecast that a storm will happen.
-
Not in it. Clouds hiding the sun, snow on the ground, and closures. The answer says so in
unknowns.
Request
A flat object: every field is optional except the line.
{ "gpx": "<gpx…>" }
{ "geometry": { "type": "LineString", "coordinates": [[lon, lat], …] }, "days": 3, "starts": ["06:00", "08:00"], "prefer": ["dry", "daylight"] }
| Field | Default | |
|---|---|---|
gpx or geometry | one of them | One line (one part), at most 120 km and 5,000 points |
from_date | today at the route | YYYY-MM-DD in the route's own time, from today to 7 days ahead |
days | 3 | 1 to 7 days from from_date |
starts | 06:00–10:00 hourly | Local start times HH:MM, at most 24. Or give start_from and start_to (HH:MM) with start_step_min (30–240, default 60) instead |
prefer | no_thunder, dry, daylight, calm | An ordered list of no_thunder, dry, daylight, calm, warm, cool (not both warm and cool) |
profile, pace_factor, min_per_km, kmh, stops | as route weather | The same rules and words as route weather |
caller | Optional label |
Start times that have already passed are skipped and counted in skipped_past.
Response
| Field | Meaning |
|---|---|
schema | route-windows/1 |
settings, settings_defaulted | from_date, days, starts, prefer, timezone (the IANA zone of the start, from the forecast) and utc_offset_seconds (its offset on from_date) |
profile, pace, moving_minutes | How the line is timed (moving time; stops included) |
line | points, length_m, heights, terrain_release, samples |
forecast | Provider, model runs, issue and fetch times, days, calls |
best | id, date_local, start_local of the first window, or null |
windows[] | In order (below) |
skipped_past | Start times already gone |
note | In words: an ordering of facts, not a score |
unknowns[] | code, message: those of route weather, plus windows_incomplete, offset_unknown, closures_not_assessed and snow_not_assessed |
A window
| Field | Meaning |
|---|---|
id | "<date_local>T<start_local>", e.g. 2026-10-05T07:00: stable, for watches and diffs |
rank | Its place in the order, 1 first |
date_local, start_local, departure, finish_local | Local times; departure with its own offset: each window, and each arrival in it, takes the zone's offset at that moment, so a range across a daylight-saving change (Europe on 25 October, North America on 1 November) stays on the clock |
complete | Every point had its forecast hour |
wet | samples_wet (points whose hour holds 0.1 mm or more), samples, precip_mm_max_hour, precip_probability_max_pct |
thunder | signal_samples (thunder code or CAPE ≥ 1,000 J/kg), coded_samples, cape_max_jkg, signal_min_elevation_m (the lowest point with a signal) |
feels_like_min_c, temp_c | The lowest feels-like; the temperature range |
gust_max_at_highs_kmh | The strongest gust at the points within 150 m of the route's highest point |
daylight | start_after_civil_dawn_min and finish_before_civil_dusk_min (negative means in the dark), and polar where the sun does not rise or set |
why[] | One sentence per preference, in your order: the facts that placed it |
The order
- Complete windows come before windows with missing forecast hours.
-
Then each preference in your order, lower first:
-
no_thunder: signal points. -
dry: wet points, then the chance of rain in bands of 20 % (a few points of chance never outrank darkness). -
daylight: any minute walked before civil dawn or after civil dusk counts, then the minutes in steps of 15 (a start 4 minutes before dawn is not daylight). -
calm: gusts at the highs, in steps of 10 km/h. -
warm: the lowest feels-like, highest first, in steps of 2 °C. -
cool: the highest temperature, lowest first, in steps of 2 °C.
-
- Ties go to the earlier window.
Errors
{ "error": { "code", "message" } }.
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request | Not JSON, an unknown field (a departure is set per window, so it is refused), a bad date, days, start or preference, and route weather's own rules |
| 400 | invalid_gpx, invalid_coordinates, pace_required | As route weather |
| 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, no line |
| 422 | departure_in_past | from_date before today at the route, or every window asked has started |
| 422 | beyond_forecast | from_date more than 7 days ahead |
| 503 | forecast_unavailable | The forecast did not answer |
Versioning
Additive fields may appear in route-windows/1. A change of meaning, such as the facts, the criteria or their order, is route-windows/2.