To plan a truck route with an API, choose a truck travel mode whose weight and height limits cover your vehicle, send the stops as waypoints, and let the API reorder them; for several trucks, let a route planner assign stops by capacity, equipment and delivery windows. The difference from car routing is not cosmetic. In our Boston test, a car route used Storrow Drive, a parkway closed to trucks, while every mode from medium_truck up took Boylston Street and Atlantic Avenue instead. This post walks from that single truck route to a two-truck delivery plan, with real requests and responses from the Geoapify Routing API and Route Planner API.
Key takeaways
- Truck modes: pick the smallest of six truck modes whose fixed weight and height limits cover your vehicle; custom dimensions are not request parameters.
- One truck, many stops:
optimize_stops=truereordered five Boston stops and cut amedium_truckroute from 33.2 km to 24.5 km. - A fleet: the Route Planner API assigns jobs to trucks by
delivery_capacity,capabilitiesandtime_windows, and reports what did not fit inissues.unassigned_jobs. - Data: routes follow OpenStreetMap restrictions, so a driver or dispatcher check stays part of the process.
On this page
What Changes When the Vehicle Is a Truck?
A truck route has to respect restrictions that a car route ignores: weight limits, low bridges, height-restricted underpasses and roads closed to commercial vehicles. The shortest legal path for a car is often not legal for a truck at all.
Boston shows this clearly. Storrow Drive runs along the Charles River and is the obvious fast link between Boston University and downtown. According to the Massachusetts Department of Conservation and Recreation (DCR), Storrow Drive, Soldiers Field Road and Memorial Drive are closed to trucks, buses and other oversized vehicles, with bridge clearances as low as about nine feet. DCR also warns that many GPS and navigation apps do not account for vehicle height.
We requested the same trip, from Commonwealth Avenue near the BU Bridge (42.3505,-71.1054) to the North End (42.3647,-71.0542), by car and in the truck modes:
| Mode | Distance | Time | Main roads |
|---|---|---|---|
drive | 6.38 km | 10 min | Storrow Drive (3.1 km), Cambridge Street, Hanover Street |
medium_truck, truck, heavy_truck, truck_dangerous_goods, long_truck | 6.46 km | 12 min | Boylston Street (2.2 km), Atlantic Avenue (1.2 km), Essex Street |
The truck route is only about 80 meters longer and two minutes slower, but it stays off the parkway. Test the mode on the roads that matter to your fleet, and choose it by your real vehicle, not by the label.
drive follows Storrow Drive, a parkway closed to trucks, while medium_truck takes Boylston Street and Atlantic Avenue. Routes from the Geoapify Routing API. Map data © OpenStreetMap contributors, map © Geoapify.Which Truck Mode Matches Your Vehicle?
A truck travel mode is a routing profile with fixed vehicle limits. The Routing API documents six truck modes next to drive in its travel mode reference:
| Mode | Max weight | Max height | Description |
|---|---|---|---|
drive | 3.5 t | 1.6 m | Passenger car |
light_truck | 3.5 t | 3.2 m | Light truck, for example a small delivery truck or camping car |
medium_truck | 7.5 t | 4.1 m | Medium-size truck |
truck | 22 t | 4.1 m | Truck |
heavy_truck | 40 t | 4.1 m | Heavy truck |
truck_dangerous_goods | 22 t | 4.1 m | Truck carrying dangerous goods |
long_truck | 22 t | 4.1 m | Long truck with a maximum length of 34 m |
Rule of thumb: pick the smallest mode whose limits cover your vehicle. An 18-tonne rigid truck that is 3.9 m high exceeds medium_truck (7.5 t) but fits truck (22 t, 4.1 m). A 3.0 m high, 3.5 t van fits light_truck.
The limits are fixed per mode. The Routing API has no parameters for a custom weight, height, width or axle load, so a 30-tonne vehicle should use heavy_truck rather than truck. If your fleet needs a custom vehicle profile, contact Geoapify to discuss it.
How Do You Request a Truck Route?
A truck route is a regular Routing API GET request with a truck mode. The other parameters tune how the route is chosen and how much detail comes back. Here is the Boston trip again as a REST request:
curl "https://api.geoapify.com/v1/routing?waypoints=42.3505,-71.1054%7C42.3647,-71.0542&mode=medium_truck&type=less_maneuvers&avoid=tolls:0.8&traffic=approximated&max_speed=80&details=route_details&format=json&apiKey=YOUR_API_KEY"What each parameter does, according to the Routing API documentation:
| Parameter | Value | Effect |
|---|---|---|
waypoints | lat,lon|lat,lon | Stops in latitude, longitude order, separated by | (encoded as %7C) |
mode | medium_truck | Truck profile with 7.5 t / 4.1 m limits |
type | less_maneuvers | Balanced route with extra penalties for maneuvers; default is balanced; supported for drive, truck modes and bus |
avoid | tolls:0.8 | Avoid toll roads with importance 0.8 on a 0 to 1 scale; ferries, highways and location:lat,lon are also available |
traffic | approximated | Lowers speeds on potentially heavy-loaded roads; default free_flow assumes no traffic |
max_speed | 80 | Caps vehicle speed in km/h; range 10 to 252, default for trucks is 90 |
details | route_details | Adds per-step road attributes |
The traffic model mainly changes ETAs in a dense city. With the same parameters but no traffic, this route took about 12 minutes; with traffic=approximated the API returned about 43 minutes for the same 6,459 m path, a conservative, congested-roads estimate. Use the Routing API playground to compare settings on a map before you code them.
With details=route_details, each step carries road attributes that matter for trucks: road_class, speed_limit, truck_limit (the speed limit for trucks), tunnel, bridge, lane_count and more. This step is the bridge on Boylston Street:
Simplified response:
{
"results": [
{
"distance": 6459,
"distance_units": "meters",
"time": 2553.013,
"legs": [
{
"steps": [
{
"name": "Boylston Street",
"road_class": "primary",
"speed_limit": 40,
"truck_limit": 40,
"lane_count": 2,
"surface": "paved_smooth",
"toll": false,
"tunnel": false,
"bridge": true,
"distance": 44,
"time": 14.557486939048895
}
]
}
]
}
]
}The full step list is useful for driver apps and audits: you can show where a route crosses bridges or tunnels and which road classes it uses. Keep in mind that route_details increases the API call cost, so request it only when you use the fields.
How Does Routing Change for Dangerous Goods?
Dangerous goods (hazmat, ADR) shipments face tunnel restrictions that do not apply to other trucks of the same size. The truck_dangerous_goods mode has the same 22 t / 4.1 m limits as truck, but routes around roads restricted for dangerous goods.
London's Limehouse Link is a good test. The UK government's ADR tunnel categories list places Limehouse in category E, the most restrictive category, which applies to nearly all dangerous goods. We routed from Wapping (51.5101,-0.0590) to Canary Wharf (51.5054,-0.0235):
| Mode | Distance | Time | Route |
|---|---|---|---|
truck | 2.93 km | 5 min | The Highway (A1203), then Limehouse Link (A1203) |
truck_dangerous_goods | 3.39 km | 7 min | The Highway, then Commercial Road (A13) and West India Dock Road (A1261) |
The detour costs about 460 meters and two minutes, and it keeps the vehicle out of the tunnel. The request is the same as any other truck route; only the mode changes:
curl "https://api.geoapify.com/v1/routing?waypoints=51.5101,-0.0590%7C51.5054,-0.0235&mode=truck_dangerous_goods&format=json&apiKey=YOUR_API_KEY"The mode helps you plan, but it does not replace compliance. The driver and operator remain responsible for the ADR rules of the specific load, tunnel codes and local signage.
truck route uses the Limehouse Link tunnel (dashed); truck_dangerous_goods avoids it and takes Commercial Road. Routes from the Geoapify Routing API. Map data © OpenStreetMap contributors, map © Geoapify.How Do You Plan a Multi-Stop Truck Route?
For one truck with several stops, send all stops as waypoints and add optimize_stops=true. The Routing API keeps the first and last waypoints fixed and reorders the intermediate ones; this becomes useful from four waypoints, when at least two stops can swap places.
Our test is a medium_truck leaving a depot in Newmarket, South Boston, visiting five stops and returning to the depot:
curl "https://api.geoapify.com/v1/routing?waypoints=42.3305,-71.0640%7C42.3647,-71.0542%7C42.3505,-71.1054%7C42.3467,-71.0972%7C42.3736,-71.1190%7C42.3770,-71.0600%7C42.3305,-71.0640&mode=medium_truck&optimize_stops=true&format=json&apiKey=YOUR_API_KEY"The waypoints are depot (0), North End (1), BU (2), Fenway (3), Harvard Square (4), Charlestown (5) and depot (6). Here is what reordering did:
optimize_stops | Distance | Time | Visit order |
|---|---|---|---|
false | 33.2 km | 57 min | 0, 1, 2, 3, 4, 5, 6 |
true | 24.5 km | 44 min | 0, 1, 5, 4, 2, 3, 6 |
The optimized route goes North End → Charlestown → Harvard Square → BU → Fenway instead of crossing the city twice: 8.7 km and 13 minutes less for the same five stops. Read the new order from results[0].waypoints[].original_index, not from properties.waypoints, which repeats the request input:
Simplified response:
{
"results": [
{
"distance": 24502,
"waypoints": [
{ "original_index": 0 },
{ "original_index": 1 },
{ "original_index": 5 },
{ "original_index": 4 },
{ "original_index": 2 },
{ "original_index": 3 },
{ "original_index": 6 }
]
}
]
}Stops also behave differently for a long vehicle. The intermediate_waypoint_mode parameter controls what happens at each intermediate waypoint:
| Mode | Behavior | When to use it for trucks |
|---|---|---|
stopover (default) | Each stop splits the route into legs; direction can reset at the stop | Standard deliveries; leg times align with the Route Matrix API |
through_stop | Still splits legs but avoids an immediate U-turn at the stop; may be longer | Trucks that cannot turn around at a delivery point |
pass_through | Treats the waypoint as a via point without splitting the route | Forcing the route along a preferred road |
The optimize route stop order how-to covers the request, the response and the limits in more detail.
How Do You Plan Routes for a Truck Fleet?
Planning for several trucks is a vehicle routing problem (VRP) where the vehicles are trucks: the optimizer decides which truck serves which stop, in what order and at what time. optimize_stops only reorders one route, so a fleet needs the Route Planner API.
| Your task | Use |
|---|---|
| Keep the stops in the given order | Routing API |
| Reorder stops in one truck route, fixed start and end | Routing API with optimize_stops=true |
| Several trucks, capacities, delivery windows, equipment, driver breaks | Route Planner API |
The request's mode, for example medium_truck, applies to all agents in the plan, and the planner calculates the routes with that truck profile.
Describe Trucks as Agents
In the Route Planner API, each truck is an agent. The agent fields map directly to fleet attributes:
start_location/end_location: the depot or the driver's home base, as[lon, lat].delivery_capacity/pickup_capacity: how much the truck can carry. Units are yours: kilograms, pallets or crates, as long as jobs use the same unit.capabilities: equipment or skills, for example"tail-lift"or"refrigerated". They are matched to jobrequirements.time_windows: the shift, in relative seconds.[[0, 28800]]is an 8-hour shift starting at time 0.breaks: driver rest, each with adurationand thetime_windowsin which it can happen. The planner picks the window that fits the route best.
For example, a truck with a 45-minute break somewhere between the fourth and fifth hour of its shift:
{
"id": "truck-1",
"start_location": [-71.0640, 42.3305],
"end_location": [-71.0640, 42.3305],
"delivery_capacity": 1200,
"capabilities": ["tail-lift"],
"time_windows": [[0, 28800]],
"breaks": [{ "duration": 2700, "time_windows": [[14400, 18000]] }]
}Describe Stops as Jobs or Shipments
Stops come in two shapes, and the choice depends on where the goods start. Jobs are single stops, typically deliveries from the depot the truck starts at. Shipments are pickup → delivery pairs, such as collecting pallets at a supplier and dropping them at a store.
Fields that matter for truck deliveries:
delivery_amount(orpickup_amount): the load the stop consumes from the truck's capacity.requirements: equipment the stop needs, matched against agentcapabilities.time_windows: when the truck must reach the stop, in the same relative seconds as the shift.duration: service time at the stop, in seconds.priority: 0 to 100, default 0. When trucks or time run out, lower-priority stops may be skipped.
The jobs or shipments how-to helps you pick the right model for your data.
Example: Two Trucks, Six Deliveries in Boston
This real request has two medium_truck agents at the Newmarket depot. Truck 1 carries 1,200 units and has a tail-lift; truck 2 carries 800 units. Two stops require a tail-lift, Fenway must be served in the first two hours, and the Back Bay hotel accepts deliveries from the second hour:
curl -X POST "https://api.geoapify.com/v1/routeplanner?apiKey=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mode": "medium_truck",
"agents": [
{ "id": "truck-1", "start_location": [-71.0640, 42.3305], "end_location": [-71.0640, 42.3305],
"delivery_capacity": 1200, "capabilities": ["tail-lift"], "time_windows": [[0, 28800]] },
{ "id": "truck-2", "start_location": [-71.0640, 42.3305], "end_location": [-71.0640, 42.3305],
"delivery_capacity": 800, "time_windows": [[0, 28800]] }
],
"jobs": [
{ "id": "north-end-cafe", "location": [-71.0542, 42.3647], "duration": 600, "delivery_amount": 300 },
{ "id": "bu-campus-store", "location": [-71.1054, 42.3505], "duration": 900, "delivery_amount": 400, "requirements": ["tail-lift"] },
{ "id": "fenway-restaurant", "location": [-71.0972, 42.3467], "duration": 600, "delivery_amount": 250, "time_windows": [[0, 7200]] },
{ "id": "harvard-sq-shop", "location": [-71.1190, 42.3736], "duration": 600, "delivery_amount": 350 },
{ "id": "charlestown-market", "location": [-71.0600, 42.3770], "duration": 900, "delivery_amount": 450, "requirements": ["tail-lift"] },
{ "id": "back-bay-hotel", "location": [-71.0810, 42.3480], "duration": 1200, "delivery_amount": 200, "time_windows": [[3600, 10800]] }
]
}'Note the coordinate order: the Route Planner API uses [lon, lat], while Routing API waypoints use lat,lon. Swapping them silently moves every stop to a different place, so convert explicitly when you pass data between the two APIs.
The response assigned all six jobs, with no issues. Times are seconds from the start of the shift:
| Truck | Distance | Stops (service start) | Load |
|---|---|---|---|
truck-1 | 23.7 km | Charlestown market (658 s) → Harvard Square shop (2,233 s) → BU campus store (3,452 s) → depot (4,906 s) | 1,200 of 1,200, both tail-lift jobs |
truck-2 | 14.7 km | starts 1,996 s → North End cafe (2,510 s) → Back Bay hotel (3,600 s) → Fenway restaurant (4,901 s) → depot (5,910 s) | 750 of 800 |
Two details show the constraints at work. Both tail-lift stops went to truck 1, the only truck with that capability, and filled it exactly. Truck 2 leaves at 1,996 seconds, about 33 minutes into the shift, so it reaches the Back Bay hotel exactly when its window opens at 3,600 seconds, and still reaches Fenway before the 7,200-second deadline.
Each truck is one feature in the response:
Simplified response:
{
"type": "FeatureCollection",
"properties": { "mode": "medium_truck" },
"features": [
{
"type": "Feature",
"properties": {
"agent_index": 1,
"agent_id": "truck-2",
"distance": 14701,
"time": 3914,
"start_time": 1996,
"end_time": 5910,
"actions": [
{ "type": "start", "start_time": 1996 },
{ "type": "job", "job_id": "north-end-cafe", "job_index": 0, "start_time": 2510, "duration": 600 },
{ "type": "job", "job_id": "back-bay-hotel", "job_index": 5, "start_time": 3600, "duration": 1200 },
{ "type": "job", "job_id": "fenway-restaurant", "job_index": 2, "start_time": 4901, "duration": 600 },
{ "type": "end", "start_time": 5910 }
]
}
}
]
}
truck-1 and fills it to capacity; truck-2 starts later to meet the Back Bay delivery window. Stop order from the Route Planner API, road geometry from Routing API calls with each truck's waypoints. Map data © OpenStreetMap contributors, map © Geoapify.What Happens When the Trucks Are Full?
The planner does not overload a truck to make a plan work. To test this, we added a seventh job, seaport-warehouse at [-71.0420, 42.3480] with 900 seconds of service and a delivery_amount of 500. Total demand became 2,450 units against 2,000 units of capacity.
The response left one job out and said so:
Simplified response:
{
"properties": {
"mode": "medium_truck",
"issues": {
"unassigned_jobs": [4]
}
}
}Job index 4 is charlestown-market, a 450-unit tail-lift delivery. Truck 1 took the Back Bay hotel, BU campus store, Fenway restaurant and Harvard Square shop (1,200 units, full); truck 2 took the North End cafe and the Seaport warehouse (800 units, full). Neither truck had room for another 450 units.
Check properties.issues before dispatching. An unassigned job is a customer who will not get a delivery unless someone acts. Use priority to tell the planner which stops can wait when capacity runs short, or add a truck. These how-tos cover the details:
Turn the Plan Into Driver Routes
A plan tells each driver where to go and when; the driver also needs turn-by-turn directions. Send each agent's waypoints, in order and as lat,lon, to the Routing API with the same mode=medium_truck and details=instruction_details:
# truck-1: depot → Charlestown → Harvard Square → BU → depot
curl "https://api.geoapify.com/v1/routing?waypoints=42.3305,-71.0641%7C42.3771,-71.0599%7C42.3737,-71.1192%7C42.3505,-71.1054%7C42.3305,-71.0641&mode=medium_truck&details=instruction_details&format=json&apiKey=YOUR_API_KEY"
# truck-2: depot → North End → Back Bay → Fenway → depot
curl "https://api.geoapify.com/v1/routing?waypoints=42.3305,-71.0641%7C42.3648,-71.0541%7C42.3478,-71.0810%7C42.3472,-71.0972%7C42.3305,-71.0641&mode=medium_truck&details=instruction_details&format=json&apiKey=YOUR_API_KEY"Using the same truck mode keeps the directions consistent with the plan. The Routing API recalculates each leg with full road detail, so a driver route's distance and time can differ from the plan's estimate; use the Routing API result for navigation and customer ETAs. Our route directions tutorial shows how to display the instructions and the route on a map.
What Should You Check Before Going Live?
A truck routing integration usually fails on details, not on the algorithm. Check these points before drivers depend on it:
- Avoids are soft. The Routing API applies
avoidrules only when alternatives exist and does not exclude a road if there is no other way. Avoids also increase calculation time and add cost. - Extra details cost more.
details=route_detailsand elevation data increase the API call cost; request them only where you use them. See pricing. - Coordinate order differs. Routing API waypoints are
lat,lon; Route Planner locations are[lon, lat]. - ETAs depend on the traffic model.
traffic=approximatedgives more conservative times for city deliveries; decide which model your customer-facing ETAs use and keep it consistent. - Restrictions are as good as the map data. Routes follow OpenStreetMap data, so a restriction counts only if it is tagged. Keep a driver or dispatcher check for new sites, construction and unusual loads.
- Distance tables come from the Matrix API. For your own scheduling logic, the Route Matrix API returns up to 1,000 travel time and distance values per call and supports truck modes.
- AI agents can use truck modes too. The
calculate_routetool of the Geoapify MCP Server supportslight_truck,medium_truck,truck,heavy_truck,truck_dangerous_goodsandlong_truck, so an assistant can answer a dispatcher's routing question with the same profiles.
For a wider view of delivery use cases, see logistics and delivery solutions. For more multi-agent examples, read Route Planner API for delivery route optimization.
Frequently Asked Questions
Can I set my truck's exact weight and height?
No. Each truck mode has fixed limits, for example medium_truck is 7.5 t and 4.1 m, and the Routing API has no parameters for custom weight, height, width or axle load. Choose the smallest mode whose limits cover your vehicle. For a custom vehicle profile, contact Geoapify. See the travel modes reference.
Which mode should I use for an 18-tonne truck?
Use truck, which covers vehicles up to 22 t and 4.1 m. medium_truck stops at 7.5 t. Above 22 t, use heavy_truck (40 t); for dangerous goods, use truck_dangerous_goods; for vehicles up to 34 m long, use long_truck.
Does the Routing API avoid low bridges and truck-restricted tunnels?
Truck modes apply their weight and height limits to road restrictions recorded in OpenStreetMap. In our tests, medium_truck avoided Boston's Storrow Drive and truck_dangerous_goods avoided London's Limehouse Link. Results depend on map tagging, so drivers and operators remain responsible for compliance. Try it in the Routing API playground.
Should I use optimize_stops or the Route Planner API?
Use optimize_stops=true in the Routing API to reorder stops in one truck route with a fixed start and end. Use the Route Planner API when several trucks share the stops or when you need capacities, time windows, equipment or breaks. See the stop order how-to.
How does the Route Planner API handle truck capacity?
Set delivery_capacity or pickup_capacity on each agent and delivery_amount or pickup_amount on each job, in any unit you choose. Jobs that do not fit the available capacity are left out and listed in properties.issues.unassigned_jobs. Read the capacity limits how-to.
Can an AI agent plan truck routes through MCP?
Yes, for single routes. The calculate_route tool of the Geoapify MCP Server supports all truck modes, including medium_truck, heavy_truck and truck_dangerous_goods. For distance tables, agents can use calculate_route_matrix; multi-truck planning with capacities is done with the REST Route Planner API. See the MCP tool catalog.

