Multi-stop route total distance calculator
A multi-stop journey is only as complete as the links between its consecutive stops.
Run — free
This calculator accepts the exact order in which places will be visited and a collection of known pairwise distances, then adds only the legs used by that route. It returns a transparent leg-by-leg breakdown alongside the total, and it stops with a clear error when a required connection is absent. Pair entries are treated as undirected, so one distance between two stops works for travel in either direction.
Describe the route and the available distances
Start with the stops array, listing every place in the precise visiting order. Names are matched after surrounding whitespace is removed, but letter case and internal spacing remain significant, so use consistent labels. A stop may appear more than once when a route returns to a depot or revisits a location. Next, provide distance records containing from, to, and distance. Each record describes an unordered pair: a value entered for Depot to Museum is also available for Museum to Depot. Distances must be finite, non-negative numbers, and all values must use the unit selected in distance_unit. The calculator does not convert mixed units because an apparently reasonable total made from kilometers and miles would be misleading. Extra pairs are allowed and ignored when they are not part of the requested visiting order. This makes it practical to submit a reusable distance table while changing only the route sequence. If the same pair appears more than once with different values, the request is rejected instead of silently selecting one of the conflicting measurements.
Understand how the route total is calculated
The calculation walks through the stops from left to right and considers each adjacent pair exactly once. For a sequence of Depot, Museum, Hotel, and Depot, the required legs are Depot–Museum, Museum–Hotel, and Hotel–Depot. The algorithm looks up each pair without regard to direction, adds its distance to a running total, and records the leg in the output. It never chooses a shorter route, inserts an unlisted place, or substitutes a path through another stop. This is a sequence total, not a routing or optimization engine, so the supplied order remains authoritative. Consecutive repeated names contribute a zero-distance leg because no travel occurs between a place and itself. The result includes total_distance, distance_unit, stop_count, leg_count, and the ordered legs used in the sum. A stable precision step limits insignificant floating-point artifacts while preserving useful decimal detail. Because every included value is shown, the total can be audited against the source table without reconstructing which connections the calculator selected.
Handle incomplete route data before it causes trouble
Before returning any total, the calculator verifies that every consecutive pair in the visiting order has a supplied distance. If Museum–Hotel is missing, it identifies those two stop names and rejects the request; it does not treat the gap as zero or return a partial total. That fail-closed behavior is useful in dispatch, itinerary preparation, mileage reimbursement, and delivery planning, where an understated distance can affect schedules or budgets. Correct the named pair, submit the request again, and the same deterministic inputs will always produce the same result. The check covers only legs that the sequence actually uses, so missing values between unrelated stops do not matter. Pairwise inputs can come from a road-distance matrix, a planning spreadsheet, surveyed trail segments, or another trusted source. The calculator does not contact a map provider and cannot determine whether those values reflect current roads, closures, toll restrictions, or a particular vehicle. Validate the source distances separately whenever operational decisions depend on real-world travel conditions.
What you can do with it
Check a delivery run
Add the known depot and customer legs in dispatch order while catching any missing connection before the vehicle leaves.
Total an itinerary
Calculate the length of a planned sequence of attractions, hotels, and transport hubs from a prepared distance table.
Audit mileage calculations
Return the exact legs included in a route total so a reimbursement or planning figure can be checked against its source distances.
FAQ
What does an API request cost?
Each API request costs $0.002. The browser version can run locally without a network call.
Does the calculator find the shortest route?
No. It preserves the visiting order you supply and totals the consecutive legs in that sequence.
Are pairwise distances directional?
No. A distance supplied for A to B is also used for B to A. Conflicting duplicate values for the same unordered pair are rejected.
What happens when a route leg is missing?
The request fails with an invalid-input error naming the two consecutive stops whose distance was not supplied.
Can I mix kilometers and miles?
No. Every distance in one request must already use the selected distance_unit. The capability labels the result but does not convert individual values.
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/travel/route-stop-sequence-distance \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"stops":["Depot","Museum","Hotel","Depot"],"distances":[{"from":"Depot","to":"Museum","distance":4.8},{"from":"Museum","to":"Hotel","distance":3.25},{"from":"Hotel","to":"Depot","distance":6.1}]}'const res = await fetch("https://api.kit.forhosting.com/travel/route-stop-sequence-distance", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"stops": [
"Depot",
"Museum",
"Hotel",
"Depot"
],
"distances": [
{
"from": "Depot",
"to": "Museum",
"distance": 4.8
},
{
"from": "Museum",
"to": "Hotel",
"distance": 3.25
},
{
"from": "Hotel",
"to": "Depot",
"distance": 6.1
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/travel/route-stop-sequence-distance",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"stops": [
"Depot",
"Museum",
"Hotel",
"Depot"
],
"distances": [
{
"from": "Depot",
"to": "Museum",
"distance": 4.8
},
{
"from": "Museum",
"to": "Hotel",
"distance": 3.25
},
{
"from": "Hotel",
"to": "Depot",
"distance": 6.1
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/travel/route-stop-sequence-distance", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"stops":["Depot","Museum","Hotel","Depot"],"distances":[{"from":"Depot","to":"Museum","distance":4.8},{"from":"Museum","to":"Hotel","distance":3.25},{"from":"Hotel","to":"Depot","distance":6.1}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"stops":["Depot","Museum","Hotel","Depot"],"distances":[{"from":"Depot","to":"Museum","distance":4.8},{"from":"Museum","to":"Hotel","distance":3.25},{"from":"Hotel","to":"Depot","distance":6.1}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/travel/route-stop-sequence-distance", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"stops": [
"Depot",
"Museum",
"Hotel",
"Depot"
],
"distances": [
{
"from": "Depot",
"to": "Museum",
"distance": 4.8
},
{
"from": "Museum",
"to": "Hotel",
"distance": 3.25
},
{
"from": "Hotel",
"to": "Depot",
"distance": 6.1
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "travel.route_stop_sequence_distance",
"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
max_stops | 500 |
max_distances | 10000 |
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. |