Pace plan for a course
POST https://api.trailsplits.com/v1/pace-plan
Checked by a live probe Key optional · 500 credits a day without one
Splits every kilometre or mile for one course, from a target time or your pace on the flat: slower where it climbs or descends steeply (effort km = distance km + climb m / 100 + descent m / 300). Each split ends on its mark and names its terrain (steady climb, technical descent, …). Uses the file’s own heights, or the terrain model’s. The engine of the Pace & Split Calculator. A pacing rule, not a physiological model. 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/pace-plan' \
-H "Authorization: Bearer $TRAILSPLITS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"geometry":{"type":"LineString","coordinates":[[7.7475,46.0207],[7.74,46.018],[7.73,46.014],[7.7174,46.0091]]},"target_time":"0:20:00"}' Request body
| Field | Type | Description |
|---|---|---|
gpx | string | One line as GPX. Or geometry, not both. Limits: 5,000 points, 300 km, 1 MB; one part only. |
geometry | object | A GeoJSON LineString, [lon, lat, height?]. |
target_time | string | h:mm:ss, mm:ss or minutes, e.g. "2:30:00". One of target_time, target_seconds or flat_pace_s_per_km. |
target_seconds | number | |
flat_pace_s_per_km | number | Your pace on level ground, seconds per km. |
unit | string: km | mi | Splits every kilometre or mile; paces are always per kilometre. |
Response
| Field | Type | Description |
|---|---|---|
schema | string: pace-plan/1 | |
engine | object | |
settings_defaulted | array | |
unit | string: km | mi | |
target | object | |
course | object | |
effort | object | |
splits | array | |
unknowns | array |
Full response schema (JSON Schema)
{
"type": "object",
"properties": {
"schema": {
"type": "string",
"enum": [
"pace-plan/1"
]
},
"engine": {
"type": "object"
},
"settings_defaulted": {
"type": "array",
"items": {
"type": "string"
}
},
"unit": {
"type": "string",
"enum": [
"km",
"mi"
]
},
"target": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [
"time",
"flat_pace"
]
},
"seconds": {
"type": "number",
"description": "The finish time the splits add up to, to 0.1 s."
},
"flat_pace_s_per_km": {
"type": "number"
}
},
"required": [
"kind",
"seconds"
]
},
"course": {
"type": "object",
"properties": {
"distance_m": {
"type": "number"
},
"gain_m": {
"type": "number"
},
"loss_m": {
"type": "number"
},
"heights": {
"type": "string",
"enum": [
"recorded",
"terrain",
"none"
]
},
"smoothing": {
"type": "string"
}
},
"required": [
"distance_m",
"gain_m",
"loss_m",
"heights",
"smoothing"
]
},
"effort": {
"type": "object",
"properties": {
"rule": {
"type": "string"
},
"flat_pace_s_per_km": {
"type": "number",
"description": "The pace on level ground that the target means on this course."
}
},
"required": [
"rule",
"flat_pace_s_per_km"
]
},
"splits": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"from_m": {
"type": "number"
},
"to_m": {
"type": "number"
},
"distance_m": {
"type": "number"
},
"gain_m": {
"type": "number"
},
"loss_m": {
"type": "number"
},
"pace_s_per_km": {
"type": "number"
},
"seconds": {
"type": "number"
},
"cumulative_seconds": {
"type": "number"
},
"character": {
"type": "string",
"enum": [
"runnable",
"steady climb",
"major climb",
"fast descent",
"technical descent",
"rolling mountain terrain"
]
}
},
"required": [
"label",
"from_m",
"to_m",
"distance_m",
"gain_m",
"loss_m",
"pace_s_per_km",
"seconds",
"cumulative_seconds",
"character"
]
}
},
"unknowns": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"code",
"message"
]
}
}
},
"required": [
"schema",
"engine",
"unit",
"target",
"course",
"effort",
"splits",
"unknowns"
]
}Errors
400, 413, 422, plus the gateway's 401, 429 and 503 (error conventions). A refused request costs no credits.
Contract
Splits for a course, every kilometre or mile, from a target time or from your pace on the flat. They are slower where the course climbs and descends steeply. The trail splits behind the product's name, as an API.
The model
- Effort. Each split's effort in kilometres is its distance, plus 1 km for every 100 m of climb, plus 1 km for every 300 m of descent.
- A target time is shared among the splits in proportion to their effort.
-
A flat pace (your pace on level ground) is multiplied by the whole course's effort to give the target, which is then shared the same way.
target.secondsstates the result. -
Heights are smoothed by a moving average over ±100 m along the line (the router's method) before climb is counted, so GPS jitter is not climb.
-
A file's own heights are used whenever it carries any, as the page uses them. Points without one are filled from their neighbours (
heights_partialwhen under 90 % carry one). -
A file without heights takes the terrain model's at its points (
course.heights: terrain). -
When the terrain model does not answer either, the plan treats the course as flat and says so (
heights_unknown).
-
A file's own heights are used whenever it carries any, as the page uses them. Points without one are filled from their neighbours (
-
What it is not. A pacing rule from race planning, not a physiological model. It knows nothing of surface, altitude, heat or fatigue.
characternames each split's terrain ("steady climb", "technical descent") so a runner can adjust.
Request
{ "gpx": "<gpx…>", "target_time": "2:30:00" }
{ "geometry": { "type": "LineString", "coordinates": [[lon, lat, height?], …] }, "flat_pace_s_per_km": 330 }
{ "gpx": "<gpx…>", "target_seconds": 1500, "unit": "mi" }
| Field | ||
|---|---|---|
gpx or geometry | one of them | One line (a GPX track segment or route, or a GeoJSON LineString), as for route analysis. Limits: 5,000 points, 300 km, 1 MB. A file of several parts is refused: a pace plan is for one course |
target_time | one of the three | A string: "h:mm:ss", "mm:ss" or minutes, e.g. "2:30:00"; minutes and seconds after the first field are under 60 |
target_seconds | The same in seconds | |
flat_pace_s_per_km | Your pace on level ground, 120 to 1,800 s per km (2:00 to 30:00 min/km) | |
unit | km (default) or mi | Splits every kilometre or every mile; paces are always per kilometre |
caller | Optional label for logs and receipts |
Response
| Field | Meaning | ||
|---|---|---|---|
schema | pace-plan/1 | ||
settings_defaulted | unit when not given | ||
unit | km or mi | ||
target | kind (time \ | flat_pace), seconds (the finish time the splits add up to, to 0.1 s), and flat_pace_s_per_km when that was given | |
course | distance_m, gain_m, loss_m (on the smoothed heights), heights (recorded \ | terrain \ | none), smoothing in words |
effort | rule in words, and flat_pace_s_per_km: the pace on level ground that the target means on this course | ||
splits[] | Each ends on its kilometre or mile mark, however far apart the file's points are (the last ends at the finish): label ("1 km", "2 mi", the last one to two decimals), from_m, to_m, distance_m, gain_m, loss_m, pace_s_per_km, seconds, cumulative_seconds, character (runnable, steady climb, major climb, fast descent, technical descent, rolling mountain terrain) | ||
unknowns[] | code, message: heights_unknown, heights_partial, target_very_fast (the target means a flat pace under 2:00 min/km), target_very_slow (over 30:00 min/km) | ||
timing | total_ms |
Errors
{ "error": { "code", "message" } }.
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request | Not JSON, an unknown field, both or neither of gpx/geometry, not exactly one target, a target or unit out of range |
| 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 300 km, or no line of two points |
| 422 | several_parts | More than one part |
| 422 | too_short | Under 0.2 km |
| 422 | budget_exhausted | The job's 25 s budget ran out, also while waiting for terrain heights |
Versioning
Additive fields may appear in pace-plan/1. A change of meaning (another effort rule, for one) is pace-plan/2.