Truck Route Planning API: From One Truck Route to a Multi-Stop Fleet Plan

Choose a truck mode, request a truck-safe route, reorder stops and assign deliveries to a fleet with real Boston and London examples

Truck Route Planning API banner: two truck routes split from one depot, with medium_truck and other truck mode limits
Truck Route Planning API banner: two truck routes split from one depot, with medium_truck and other truck mode limits

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=true reordered five Boston stops and cut a medium_truck route from 33.2 km to 24.5 km.
  • A fleet: the Route Planner API assigns jobs to trucks by delivery_capacity, capabilities and time_windows, and reports what did not fit in issues.unassigned_jobs.
  • Data: routes follow OpenStreetMap restrictions, so a driver or dispatcher check stays part of the process.

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:

ModeDistanceTimeMain roads
drive6.38 km10 minStorrow Drive (3.1 km), Cambridge Street, Hanover Street
medium_truck, truck, heavy_truck, truck_dangerous_goods, long_truck6.46 km12 minBoylston 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.

Map of Boston comparing a car route along Storrow Drive with a medium truck route via Boylston Street and Atlantic Avenue
Same start and end, two travel modes: 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:

ModeMax weightMax heightDescription
drive3.5 t1.6 mPassenger car
light_truck3.5 t3.2 mLight truck, for example a small delivery truck or camping car
medium_truck7.5 t4.1 mMedium-size truck
truck22 t4.1 mTruck
heavy_truck40 t4.1 mHeavy truck
truck_dangerous_goods22 t4.1 mTruck carrying dangerous goods
long_truck22 t4.1 mLong 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:

ParameterValueEffect
waypointslat,lon|lat,lonStops in latitude, longitude order, separated by | (encoded as %7C)
modemedium_truckTruck profile with 7.5 t / 4.1 m limits
typeless_maneuversBalanced route with extra penalties for maneuvers; default is balanced; supported for drive, truck modes and bus
avoidtolls:0.8Avoid toll roads with importance 0.8 on a 0 to 1 scale; ferries, highways and location:lat,lon are also available
trafficapproximatedLowers speeds on potentially heavy-loaded roads; default free_flow assumes no traffic
max_speed80Caps vehicle speed in km/h; range 10 to 252, default for trucks is 90
detailsroute_detailsAdds 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):

ModeDistanceTimeRoute
truck2.93 km5 minThe Highway (A1203), then Limehouse Link (A1203)
truck_dangerous_goods3.39 km7 minThe 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.

Map of East London comparing a truck route through the Limehouse Link tunnel with a dangerous goods route via Commercial Road
The 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_stopsDistanceTimeVisit order
false33.2 km57 min0, 1, 2, 3, 4, 5, 6
true24.5 km44 min0, 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:

ModeBehaviorWhen to use it for trucks
stopover (default)Each stop splits the route into legs; direction can reset at the stopStandard deliveries; leg times align with the Route Matrix API
through_stopStill splits legs but avoids an immediate U-turn at the stop; may be longerTrucks that cannot turn around at a delivery point
pass_throughTreats the waypoint as a via point without splitting the routeForcing 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 taskUse
Keep the stops in the given orderRouting API
Reorder stops in one truck route, fixed start and endRouting API with optimize_stops=true
Several trucks, capacities, delivery windows, equipment, driver breaksRoute 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 job requirements.
  • time_windows: the shift, in relative seconds. [[0, 28800]] is an 8-hour shift starting at time 0.
  • breaks: driver rest, each with a duration and the time_windows in 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 (or pickup_amount): the load the stop consumes from the truck's capacity.
  • requirements: equipment the stop needs, matched against agent capabilities.
  • 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:

TruckDistanceStops (service start)Load
truck-123.7 kmCharlestown 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-214.7 kmstarts 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 }
        ]
      }
    }
  ]
}
Map of Boston showing two optimized truck routes from one depot, with stops assigned by capacity, tail-lift equipment and delivery windows
The Route Planner gives both tail-lift jobs to 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:

  1. Avoids are soft. The Routing API applies avoid rules only when alternatives exist and does not exclude a road if there is no other way. Avoids also increase calculation time and add cost.
  2. Extra details cost more. details=route_details and elevation data increase the API call cost; request them only where you use them. See pricing.
  3. Coordinate order differs. Routing API waypoints are lat,lon; Route Planner locations are [lon, lat].
  4. ETAs depend on the traffic model. traffic=approximated gives more conservative times for city deliveries; decide which model your customer-facing ETAs use and keep it consistent.
  5. 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.
  6. 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.
  7. AI agents can use truck modes too. The calculate_route tool of the Geoapify MCP Server supports light_truck, medium_truck, truck, heavy_truck, truck_dangerous_goods and long_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.

World map

Plan Your First Truck Route

Test truck modes in the playground, then get a free API key and start building.