Skip to content

Optimized Routing

Free

Starter

Standard

Professional

Optimized routing helps you save time and cut travel costs by finding an optimal route between multiple locations. This is also known as the Traveling Salesman Problem. THe optimized routing endpoint will re-order intermediate destinations between the start and end in an optimal order for a single vehicle. This lets you make deliveries, sales calls, and more as quickly and cheaply as possible. (If you're solving fleet routing problems, check out the time/distance matrix API).

Optimized routing includes the same versatility as standard routing, with features including:

  • Access restrictions for trucks, buses, golf carts, and other specialized vehicle types
  • Vehicle attributes (weight, height, width, top speed, etc.)
  • Prefer or avoid highways, toll roads, and ferries
  • Number of passengers, for HOV lane usage
  • Hill avoidance for bicycles, motor scooters, and pedestrians
  • Support for guidance in over 25 languages

Endpoint: https://api.stadiamaps.com/optimized_route/v1

Example Code

Installation Instructions

The Stadia Maps JavaScript/TypeScript SDK is available for any package manager that supports the npm registry.

NPM Downloads

npm install @stadiamaps/api
yarn add @stadiamaps/api
bun add @stadiamaps/api
import { RoutingApi, Configuration, OptimizedRouteRequest, instanceOfRouteResponse, instanceOfOsrmRouteResponse } from '@stadiamaps/api';

// If you are writing for a backend application or can't use domain-based auth,
// then you'll need to add your API key like so:
// 
// const config = new Configuration({ apiKey: "YOUR-API-KEY" }); (1)
// You can also use our EU endpoint to keep traffic within the EU using the basePath option:
// const config = new Configuration({ basePath: "https://api-eu.stadiamaps.com" });
// const api = new RoutingApi(config);
const api = new RoutingApi();

const locationA = {
    "lon": -76.306572,
    "lat": 40.042072
};
const locationB = {
    "lon": -76.781559,
    "lat": 39.992115
};
const locationC = {
    "lon": -76.6956,
    "lat": 39.984519
};
const req: OptimizedRouteRequest = {
    locations: [
        locationA,
        locationB,
        locationC,
        locationA
    ],
    costing: "auto",
    costingOptions: {
        auto: {
            useHighways: 0.3
        }
    },
    units: DistanceUnit.Mi
};
const res = await api.optimizedRoute({ optimizedRouteRequest: req });

if (instanceOfRouteResponse(res)) {
  // TODO: Process the response (default format)
} else if (instanceOfOsrmRouteResponse(res)) {
  // TODO: Process the response (for navigation requests where your request options include format: "osrm"
}
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

The Stadia Maps Python SDK is available through any package manager that supports PyPi.

PyPI - Downloads

pip install stadiamaps
poetry add stadiamaps
import os
import stadiamaps
from stadiamaps.rest import ApiException

# You can also use our EU endpoint to keep traffic within the EU like so:
# configuration = stadiamaps.Configuration(host="https://api-eu.stadiamaps.com")
configuration = stadiamaps.Configuration()

# Configure API key authentication (ex: via environment variable). (1)
configuration.api_key['ApiKeyAuth'] = os.environ["API_KEY"]

with stadiamaps.ApiClient(configuration) as api_client:
    # Create an instance of the API class
    api_instance = stadiamaps.RoutingApi(api_client)

    try:
        location_a = {"lat": 40.042072, "lon": -76.306572}
        location_b = {"lat": 39.992115, "lon": -76.781559}
        location_c = {"lat": 39.984519, "lon": -76.6956}
        req = stadiamaps.OptimizedRouteRequest(
            id="optimized_route",
            locations=[
                stadiamaps.Coordinate.from_dict(location_a),
                stadiamaps.Coordinate.from_dict(location_b),
                stadiamaps.Coordinate.from_dict(location_c),
                stadiamaps.Coordinate.from_dict(location_a),
            ],
            costing=stadiamaps.MatrixCostingModel.AUTO,
            costing_options=stadiamaps.CostingOptions(auto=stadiamaps.AutoCostingOptions(use_highways=0.3)),  # Take the scenic route ;)
            units=stadiamaps.DistanceUnit.MI
        )

        # NOTE: Usable properties vary depending on the format parameter of the request!
        # The standard (compact) format includes an id, trip, and alternates.
        # The OSRM (navigation details in a single response) format uses the routes and waypoints parameters.
        res = api_instance.optimized_route(req).actual_instance
    except ApiException as e:
        # Add your error handling here
        print("Exception when calling the Stadia Maps API: %s\n" % e)
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

If aren't already using Maven Central, add the repository in your Gradle build script.

repositories {
    mavenCentral()
}

Then, add the API package and its dependencies.

build.gradle.kts
dependencies {
    val retrofitVersion = "2.11.0"

    // API package
    implementation("com.stadiamaps:api:3.2.1")

    // Dependencies
    implementation("com.squareup.moshi:moshi-kotlin:1.14.0")
    implementation("com.squareup.moshi:moshi-adapters:1.14.0")
    implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
    implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
    implementation("com.squareup.retrofit2:converter-moshi:$retrofitVersion")
    implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion")
}
build.gradle
dependencies {
    def retrofitVersion = "2.11.0"

    // API package
    implementation 'com.stadiamaps:api:3.2.1'

    // Dependencies
    implementation 'com.squareup.moshi:moshi-kotlin:1.15.1'
    implementation 'com.squareup.moshi:moshi-adapters:1.15.1'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
    implementation "com.squareup.retrofit2:retrofit:${retrofitVersion}"
    implementation "com.squareup.retrofit2:converter-moshi:${retrofitVersion}"
    implementation "com.squareup.retrofit2:converter-scalars:${retrofitVersion}"
}

Our API package is available on Maven Central. All you need to do is add a few dependencies to your pom.xml.

pom.xml
<properties>
    <retrofit.version>2.9.0</retrofit.version>
</properties>

<dependencies>
    <!-- API package -->
    <dependency>
        <groupId>com.stadiamaps</groupId>
        <artifactId>api</artifactId>
        <version>3.2.1</version>
    </dependency>

    <!-- Dependencies -->
    <dependency>
        <groupId>com.squareup.moshi</groupId>
        <artifactId>moshi-kotlin</artifactId>
        <version>1.15.1</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.moshi</groupId>
        <artifactId>moshi-adapters</artifactId>
        <version>1.15.1</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>logging-interceptor</artifactId>
        <version>4.10.0</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>retrofit</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-moshi</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-scalars</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
</dependencies>
// Imports (at the top of your source file; we've used some wildcard imports for simplicity)
import com.stadiamaps.api.apis.*
import com.stadiamaps.api.auth.ApiKeyAuth
import com.stadiamaps.api.infrastructure.*
import com.stadiamaps.api.models.*

// Set your API key (from an environment variable in this case) (1)
val apiKey = System.getenv("STADIA_API_KEY") ?: throw RuntimeException("API Key not set")

// Defining the host is optional and defaults to https://api.stadiamaps.com
// You can also use our EU endpoint to keep traffic within the EU like so:
// val client = ApiClient(baseUrl = "https://api-eu.stadiamaps.com")
val client = ApiClient()
client.addAuthorization("ApiKeyAuth", ApiKeyAuth("query", "api_key", apiKey))

// Configure a service for the group of APIs we want to talk to
val service = client.createService(RoutingApi::class.java)

// Set up the request.
// Note: this code is blocking for demonstration purposes.
// If you're using Kotlin with coroutines,
// you can also use these asynchronously within suspend functions.
// Synchronous code can enqueue a callback to avoid blocking
// (you'll definitely want to do one of these instead when on the main thread of an app).
// See the docs for details: https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html
val locations = listOf(
    Coordinate(40.042072, -76.306572), Coordinate(39.992115, -76.781559), Coordinate(39.984519, -76.6956), Coordinate(40.042072, -76.306572)
)
val costingOptions = CostingOptions(auto = AutoCostingOptions(useHighways = 0.3))  // Take the scenic route ;)
val req = OptimizedRouteRequest(
    id = "route",
    locations = locations,
    costing = MatrixCostingModel.auto,
    costingOptions = costingOptions,
    units = DistanceUnit.mi,
    language = ValhallaLanguages.enMinusGB
)
val res = service.optimizedRoute(req).execute()

if (res.isSuccessful) {
    println("Found result: ${res.body()}")
} else {
    println("Request failed with error code ${res.code()}")
}
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

Our Swift SDK is distributed using the Swift Package Manager (SPM). Apple's documentation shows how to add a Swift Package dependency to your Xcode project. On the Add Package screen, you can find our package by its repository URL: https://github.com/stadiamaps/stadiamaps-api-swift.

import StadiaMaps

// This setup code can go anywhere before you actually make an API call (typically in your app init)
func setupStadiaMapsAPI() {
    // Set your API key (1)
    StadiaMapsAPI.customHeaders = ["Authorization": "Stadia-Auth YOUR-API-KEY"]
    // Optionally use our EU endpoint to keep traffic within the EU
    // StadiaMapsAPI.basePath = "https://api-eu.stadiamaps.com"
}

// This function demonstrates how to call the Stadia Maps API.
// If you have not yet adopted async/await in your Swift codebase, you can use the Task API
// to call async functions in a non-async context: https://developer.apple.com/documentation/swift/task.
func myFunction() async throws {
    let locationA = Coordinate(lat: 40.042072, lon: -76.306572)
    let locationB = Coordinate(lat: 39.992115, lon: -76.781559)
    let locationC = Coordinate(lat: 39.984519, lon: -76.6956)
    let req = OptimizedRouteRequest(units: .mi,
                                    id: "optimized_route",
                                    locations: [
                                        locationA,
                                        locationB,
                                        locationC,
                                        locationA,
                                    ],
                                    costing: .auto,
                                    costingOptions: CostingOptions(auto: AutoCostingOptions(useHighways: 0.3)))  // Take the scenic route :)
    let res = try await RoutingAPI.optimizedRoute(optimizedRouteRequest: req)

    // Do something with the response...
    print(res)
}
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

Composer

To install the package via Composer, add stadiamaps/stadiamaps-api-php to your composer.json:

{
  "require": {
    "stadiamaps/stadiamaps-api-php": "1.*"
  }
}

Then run composer install.

Manual Installation

You can also download the files manually and include autoload.php in your scripts:

<?php
require_once('/path/to/OpenAPIClient-php/vendor/autoload.php');
<?php
// use or require, depending on your installation method.

// Configure API key authorization (replace with your Stadia Maps API key) (1)
$config = OpenAPI\Client\Configuration::getDefaultConfiguration()->setApiKey('api_key', 'YOUR-API-KEY');
// You can also use our EU endpoint to keep traffic within the EU using setHost:
// $config = Configuration::getDefaultConfiguration()->setApiKey('api_key', 'YOUR-API-KEY')->setHost('https://api-eu.stadiamaps.com');

$apiInstance = new OpenAPI\Client\Api\RoutingApi(
    new GuzzleHttp\Client(),
    $config
);

try {
    $locationA = (new Coordinate())->setLat(40.042072)->setLon(-76.306572);
    $locationB = (new Coordinate())->setLat(39.992115)->setLon(-76.781559);
    $locationC = (new Coordinate())->setLat(39.984519)->setLon(-76.6956);
    $req = (new OptimizedRouteRequest())
        ->setId('optimizedRoute')
        ->setLocations([$locationA, $locationB, $locationC, $locationA])
        ->setCosting(CostingModel::AUTO)
        ->setUnits(DistanceUnit::MI)
        ->setCostingOptions((new CostingOptions())
            ->setAuto((new AutoCostingOptions())->setUseHighways(0.3)));
    $result = $apiInstance->optimizedRoute($req);
} catch (Exception $e) {
    // Add your error handling here
    echo 'Exception when calling the Stadia Maps API: ', $e->getMessage(), PHP_EOL;
}
  1. Learn how to get an API key in our authentication guide.
curl -X POST -H "Content-Type: application/json" -d '{
    "locations": [
        {
            "lon": -76.306572,
            "lat": 40.042072
        },
        {
            "lon": -76.781559,
            "lat": 39.992115
        },
        {
            "lon": -76.6956,
            "lat": 39.984519
        },
        {
            "lon": -76.306572,
            "lat": 40.042072
        }
    ],
    "costing": "auto",
    "costing_options": {
        "auto": {
            "use_highways": 0.3
        }
    },
    "units": "miles"
}' "https://api.stadiamaps.com/optimized_route/v1?api_key=YOUR-API-KEY"

Turn-by-Turn Navigation

If you are building a turn-by-turn navigation experience such as a driver app or in-dash navigation, our routing APIs are up to the task! Just set the format parameter to "osrm" in your request to get a variety of navigation aids in a single API request:

  • Instruction banners
  • Spoken prompts
  • Speed limits (where available)
  • Intersection information (including lane guidance, where available)

Our next-generation navigation SDK, Ferrostar, makes it easy to build interactive turn-by-turn guidance experiences. On major platforms like iOS and Android, Ferrostar handles the API integration for you. And, unlike existing solutions, the UI components are built with SwiftUI and Jetpack Compose. So if even if you're designing a bespoke interface, you won't need to start from scratch.

Service Limits

The following limits apply to optimized routing requests.

Costing/mode of travel Max locations per route Max b-line distance between all locations
Automobile, bus, truck, and taxi 50 400 kilometers
All others 50 200 kilometers

Complementary APIs

Optimized routing uses geographic coordinates to specify the locations. If you have human-readable addresses, you can use our forward geocoding and structured geocoding APIs to convert to latitude and longitude.

If you're trying to do rich vehicle routing problem (VRP) optimizations across a fleet, our time/distance matrix API can be used as input to a number of solvers, including VROOM and OptaPlanner.

Next Steps