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

Go windows: which day and start time (curl)
# 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"]}'

Sends a real request, with your key or the keyless allowance.

Request body

FieldTypeDescription
gpxstringOne line as GPX, one part, at most 120 km and 5,000 points. Or geometry, not both.
geometryobjectA GeoJSON LineString, [lon, lat].
from_datestringYYYY-MM-DD in the route’s own time, today to 7 days ahead. Default today.
daysintegerHow many days, counting from_date itself (today by default): 1 to 7, default 3.
startsarrayLocal start times HH:MM. Default 06:00 to 10:00 hourly. Or give start_from, start_to and start_step_min instead.
start_fromstringFirst start time HH:MM, with start_to and start_step_min, instead of starts.
start_tostringLast start time HH:MM.
start_step_minintegerMinutes between start times.
preferarrayYour 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.
profilestring: hike | run | bikehike uses the calibrated hike time; run and bike need min_per_km or kmh.
pace_factornumberHike only: scales the hike time (1.2 = 20 % slower).
min_per_kmnumberRun: your pace on the flat.
kmhnumberBike: your speed on the flat.
stopsarray

Response

FieldTypeDescription
schemastring: route-windows/1
engineobject
settingsobject
settings_defaultedarrayThe request fields that were not given and took their defaults.
moving_minutesnumberMoving time for the line, stops included.
lineobjectpoints, length_m, heights, terrain_release and samples of the line read.
forecastobject
bestobject or nullid, date_local and start_local of the first window, or null.
windowsarray
skipped_pastintegerStart times already gone today, left out.
notestring
unknownsarray
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. rank is 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"] }
FieldDefault
gpx or geometryone of themOne line (one part), at most 120 km and 5,000 points
from_datetoday at the routeYYYY-MM-DD in the route's own time, from today to 7 days ahead
days31 to 7 days from from_date
starts06:00–10:00 hourlyLocal 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
preferno_thunder, dry, daylight, calmAn ordered list of no_thunder, dry, daylight, calm, warm, cool (not both warm and cool)
profile, pace_factor, min_per_km, kmh, stopsas route weatherThe same rules and words as route weather
callerOptional label

Start times that have already passed are skipped and counted in skipped_past.

Response

FieldMeaning
schemaroute-windows/1
settings, settings_defaultedfrom_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_minutesHow the line is timed (moving time; stops included)
linepoints, length_m, heights, terrain_release, samples
forecastProvider, model runs, issue and fetch times, days, calls
bestid, date_local, start_local of the first window, or null
windows[]In order (below)
skipped_pastStart times already gone
noteIn 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

FieldMeaning
id"<date_local>T<start_local>", e.g. 2026-10-05T07:00: stable, for watches and diffs
rankIts place in the order, 1 first
date_local, start_local, departure, finish_localLocal 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
completeEvery point had its forecast hour
wetsamples_wet (points whose hour holds 0.1 mm or more), samples, precip_mm_max_hour, precip_probability_max_pct
thundersignal_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_cThe lowest feels-like; the temperature range
gust_max_at_highs_kmhThe strongest gust at the points within 150 m of the route's highest point
daylightstart_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

  1. Complete windows come before windows with missing forecast hours.
  2. 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.
  3. Ties go to the earlier window.

Errors

{ "error": { "code", "message" } }.

HTTPcodeWhen
400invalid_requestNot 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
400invalid_gpx, invalid_coordinates, pace_requiredAs route weather
405method_not_allowedAny method but POST (and OPTIONS)
413body_too_large, too_many_pointsOver 1 MB, or over 5,000 points
422too_long, several_parts, no_lineOver 120 km, more than one part, no line
422departure_in_pastfrom_date before today at the route, or every window asked has started
422beyond_forecastfrom_date more than 7 days ahead
503forecast_unavailableThe 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.