Skip to main content
V3 is in beta. General availability (GA) is planned for January 2027.
Every plan is built on a travel matrix: the driving time and distance between each pair of locations in your request. You never send that matrix. You send coordinates, and the API looks up real road-network times and distances for them before the search starts. This page covers what you control about that lookup and what you can observe in the response.

What goes into the matrix

Every coordinate the request can route to becomes a matrix location:
  • each job’s location
  • each shipment’s pickup.location and delivery.location
  • each shift’s start and end, whether given inline or as a depots[].id
  • each depot a shift lists in reloads
  • the location of a driver break that is pinned to a place
Identical coordinates are looked up once. Two coordinates count as identical when they match to six decimal places (roughly 10 cm), so a depot shared by fifty vehicles, or ten jobs at one address, add a single location to the matrix. The jobs keep their own identity in the plan. Coordinates are [longitude, latitude] everywhere in the API.

Fields that control travel data

Three request fields decide which travel data a solve uses.
string
default:"tomtom"
Which road-network data prices travel. One of tomtom, osm, tomtom_real_time. See Choosing an engine.
string (RFC 3339)
The instant the traffic lookup is made for. Any UTC offset is accepted. Omit it and travel times reflect typical traffic at the moment the request is processed. Set it to plan tomorrow’s 08:00 routes against morning-rush travel times, or to re-run a past day under its original conditions. Only valid with the tomtom engine.
string
default:"car"
The routing profile for this vehicle: car, truck, or bike, in lowercase; any other value is a 400. Vehicles with different profiles each get their own matrix, so a mixed fleet is planned with the right travel times per vehicle type. The profile changes speeds only: truck carries no dimensions or restrictions, so it does not avoid a low bridge or a weight-limited road.

Choosing an engine

Use tomtom unless you have a reason not to. Choose osm when you want traffic-independent travel times, for example to compare plans across days without traffic moving the numbers. Sending departure_time together with osm or tomtom_real_time is a 400 whose error item points at /problem/travel/departure_time: free-flow data has no traffic to look up, and live traffic is always “now”. See Errors for the error body.

Adjusting travel and service time per vehicle

The matrix is the same for every vehicle on a profile. Two vehicle fields scale time on top of it:
number
default:"1.0"
Travel-speed multiplier, in (0, 5]. Effective travel time is the matrix time divided by speed_factor, so 1.2 models a faster vehicle and 0.8 a slower one. It affects driving only.
number
default:"1.0"
Work-rate multiplier for time spent at stops, in (0, 5]. Effective service time is service_duration_s / service_factor, so values above 1.0 model a crew that works faster. It does not change setup_duration_s, depot handling time, waiting, or breaks. A shift can override it with its own service_factor.

What the matrix drives

The same travel times and distances feed every part of the plan:
  • Feasibility. Time windows, shift hours, and the route limits vehicles[].limits.max_distance_m and vehicles[].limits.max_route_duration_s are all checked against them.
  • Cost. objective.costs.per_travel_km is charged on route distance, and objective.costs.per_route_hour on each route’s start-to-finish span, which includes the driving time between stops.
  • The reported figures. routes[].distance_m, routes[].time.travel_s, and each stop’s travel_s and distance_m come from the matrix, with the vehicle’s speed_factor applied to the times.

What you see in the response

[number, number]
The stop’s coordinate moved to the nearest point on the road network, as [longitude, latitude]. Present when the routing engine could snap the point. A large gap between location and snapped_location means the coordinate you sent is not near a road; a common cause is swapped longitude and latitude.
string
UNREACHABLE_LOCATION when the road network has no connection to or from a job’s location, for example a point on an island with no road link. The solver never routes over a missing connection, so the job comes back unassigned instead. This is a fact about the input, so more solve time will not place it; fix the coordinate.
string
The road geometry of the route, as an encoded polyline at precision 5. Returned only when you set options.polylines to simplified or full. It is traced with the vehicle’s profile, so it follows the same roads the plan was costed on.

Latency and failures

The travel lookup happens before the search and is not counted against options.time_limit_s. Total response time is the lookup plus the search, so the more distinct locations a request has, the longer the lookup takes: the matrix grows with the square of the location count.
  • Travel data can be reused between requests, under three conditions. The request uses the default tomtom engine, sets no departure_time, and has at most 200 distinct locations. Location pairs looked up within the last hour can then be served without a new lookup, which suits dispatch workflows that re-solve the same routes as jobs arrive. Reuse is not guaranteed, so do not size a client timeout on it.
  • Every other request does a fresh lookup. That covers an explicit departure_time, the osm engine, and any request with more than 200 distinct locations. Set departure_time when you are planning for a specific future or past instant, not on every call in a re-solve loop.
  • All coordinates in one request must lie in the same region. A request whose coordinates span more than one region or continent is rejected with 400. When you get this error, check that every coordinate is in [longitude, latitude] order.
  • If the travel data provider cannot be reached on a solve (outage, timeout, overload), the solver still answers: every pair is estimated from straight-line distance with a typical detour factor and speed for the vehicle profile, and the response carries summary.travel_estimated: true. An estimate knows nothing about one-way streets or traffic and can be tens of percent off, so the plan, time-window feasibility and score.violations hold only against it, and no routes[].polyline is returned. Solve again once the provider is back if the plan must hold on the road. Set options.travel_fallback to "fail" to get the error below instead of an estimated plan.
  • Otherwise the request fails. Evaluate and suggest never estimate, and a request the provider rejects is never estimated on any endpoint. The request fails with 502 and code matrix_provider_error; when the provider is temporarily unavailable you get 503 with a Retry-After header. Both are safe to retry.

Constraints

Time windows, route limits, and reachability, all checked against the travel matrix

Performance guide

How lookup time and search time add up to response time

Objective function

How distance and time become cost

Errors

The error body, status codes, and which failures to retry