Grade-adjusted pace calculator
Grade-adjusted pace, often shortened to GAP, estimates the flat pace that would require roughly the same energy as a run on a steady incline or decline.
Run — free
Enter an observed pace in seconds per kilometre and a signed grade percentage: positive for uphill, negative for downhill. The calculator applies a published polynomial running-cost curve and returns a flat-equivalent pace, a correction factor, and the modeled energy cost. It is deterministic and useful for comparing efforts, but it does not replace heart-rate, power, terrain, weather, or individual performance data.
Enter pace and grade consistently
Provide the observed pace as total seconds per kilometre. For example, a five-minute kilometre is 300 seconds. Grade is the signed vertical change divided by horizontal distance and multiplied by 100, so a climb gaining five metres over 100 horizontal metres is approximately +5%. Use a negative number for a descent. The calculator expects both fields because a pace without terrain cannot be adjusted, while terrain without an observed pace does not describe a running result. Use the average grade only for a reasonably consistent segment. A route that repeatedly alternates between steep climbs and descents should be divided into sections, calculated separately, and then combined by time or distance. Averaging a rolling route into zero percent can hide substantial climbing cost and downhill behavior. GPS elevation is often noisy over short segments, so prefer a mapped or smoothed grade when possible. The accepted range is deliberately limited to practical running slopes from −45% to +45%, and pace must fall between one and sixty minutes per kilometre.
Understand the polynomial correction
The calculation uses the Minetti polynomial energy-cost curve: cost equals 155.4g⁵ − 30.4g⁴ − 43.3g³ + 46.3g² + 19.5g + 3.6, where g is grade written as a decimal rather than a percentage. At zero grade the modeled cost is 3.6 joules per kilogram per metre. The correction factor is that flat cost divided by the cost at the supplied grade, and the observed seconds per kilometre are multiplied by this factor. An uphill cost above the flat value therefore produces a faster flat-equivalent pace. Moderate downhill running can also produce a faster equivalent pace than the observed pace, but the relationship is not a mirror image because descending has braking, impact, and muscle-damage costs. The returned energy cost is the polynomial value, not a direct calorie measurement. Results are rounded only after the full calculation, keeping repeated requests stable. This method describes energetic equivalence under its model; it does not claim that every runner can reproduce the adjusted pace on a track.
Interpret GAP as a comparison tool
Use grade-adjusted pace to compare segments or training efforts that would otherwise look misleading on a pace chart. A slow uphill split may represent a strong effort, while a fast descent may not be as demanding as its raw pace suggests. GAP is most informative when surfaces, altitude, wind, fatigue, and segment length are broadly comparable. Trail footing, sharp turns, stairs, mud, heat, and technical descending can dominate the result because the formula sees only pace and average grade. Individual running economy also varies, especially on steep descents where skill and eccentric muscle tolerance matter. Treat small differences as noise rather than as proof that one session was better. For structured analysis, preserve the raw pace and grade beside the adjusted output so the estimate remains auditable. The browser and API use the same pure JavaScript solver, and an API request costs $0.002. This makes the result suitable for repeatable logs and pipelines, while coaches and athletes should still interpret it alongside perceived exertion, heart rate, and the purpose of the workout.
What you can do with it
Compare hilly intervals
Convert each steady hill repetition to a flat-equivalent pace before comparing efforts across slopes.
Review race splits
Explain why uphill kilometres look slow and downhill kilometres look fast without discarding the original split data.
Normalize a training log
Add deterministic GAP values to running records so similar sessions can be reviewed on a common pace scale.
FAQ
What does the calculator cost?
Each API request costs $0.002; the on-page browser calculation uses the same solver.
Should downhill grade be negative?
Yes. Enter a descent as a negative percentage and an ascent as a positive percentage.
Why must pace be entered in seconds per kilometre?
A single numeric unit keeps the API unambiguous. Multiply minutes by 60 and add the remaining seconds.
Does GAP predict my actual flat race pace?
No. It estimates energetic equivalence from pace and grade only; fitness, terrain, wind, altitude, and fatigue still matter.
Can I use one average grade for a rolling route?
Only with caution. Separate climbs and descents are better calculated as individual segments because their costs are asymmetric.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/health/grade-adjusted-pace \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"pace_seconds_per_km":300,"grade_percent":5}'const res = await fetch("https://api.kit.forhosting.com/health/grade-adjusted-pace", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"pace_seconds_per_km": 300,
"grade_percent": 5
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/health/grade-adjusted-pace",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"pace_seconds_per_km": 300,
"grade_percent": 5
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/health/grade-adjusted-pace", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"pace_seconds_per_km":300,"grade_percent":5}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"pace_seconds_per_km":300,"grade_percent":5}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/health/grade-adjusted-pace", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"pace_seconds_per_km": 300,
"grade_percent": 5
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "health.grade_adjusted_pace",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
min_pace_seconds_per_km | 60 |
max_pace_seconds_per_km | 3600 |
min_grade_percent | -45 |
max_grade_percent | 45 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |