DEV Community

Roman Kotenko
Roman Kotenko

Posted on Originally published at road511.com

The Truck's Actual Toll Bill, Returned With the Route

The fastest route and the cheapest route are rarely the same line on the map. The difference is usually tolls — and a passenger car’s toll rate has almost nothing to do with what a 5-axle, 36-tonne, placarded tractor-trailer pays at the same plaza. If your dispatch math uses a car estimate and a fudge factor, the invoice is going to surprise you.

Road511’s routing endpoint returns the toll cost computed for the truck you’re actually moving. Opt in on a route request and you get back two things: a per-currency total for the whole trip, and a per-section breakdown naming each toll system and the fare that applies to your vehicle class.

Opt In With include

Toll pricing is opt-in, because computing it has an upstream cost — you only pay for it when you ask. Add "tolls" to the include array on POST /api/v1/routing/route:

curl -X POST "https://api.road511.com/api/v1/routing/route" \
  -H "X-API-Key: your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "origin":      { "lat": 40.7128, "lng": -74.0060 },
    "destination": { "lat": 39.9526, "lng": -75.1652 },
    "currency": "USD",
    "truck": {
      "profile":  "tractor",
      "weight_t": 36.0,
      "height_m": 4.2,
      "axle_count": 5,
      "hazardous": ["flammable"]
    },
    "include": ["tolls"]
  }'
Enter fullscreen mode Exit fullscreen mode

That’s New York City→Philadelphia for a 5-axle placarded tractor. The currency field (ISO 4217) controls what the fares are reported in; the truck profile you already send is what makes the price the truck’s price.

The Response

Two places carry toll data. The route summary gets a toll_costs array — one entry per distinct currency, because a single trip can cross systems billed in different currencies (think a US–Canada run mixing USD and CAD). Each route section gets a tolls array naming the systems charged on that stretch and the fares within them.

{
  "routes": [
    {
      "summary": {
        "distance_m": 153400,
        "duration_s": 7320,
        "toll_costs": [
          { "currency": "USD", "value": 38.75 }
        ]
      },
      "sections": [
        {
          "distance_m": 92100,
          "duration_s": 4080,
          "summary": "I-95 S via New Jersey Turnpike",
          "tolls": [
            {
              "system": "New Jersey Turnpike",
              "fares": [
                { "name": "Class 5 (5 axles)",
                  "price": { "currency": "USD", "value": 31.40 },
                  "payment_methods": ["transponder"],
                  "transponders": ["E-ZPass"],
                  "counted": true },
                { "name": "Class 5 (5 axles)",
                  "price": { "currency": "USD", "value": 39.25 },
                  "payment_methods": ["videoToll"] }
              ]
            }
          ]
        },
        {
          "distance_m": 61300,
          "duration_s": 3240,
          "summary": "Delaware River bridge crossing",
          "tolls": [
            {
              "system": "Delaware River Port Authority",
              "fares": [
                { "name": "5-axle truck",
                  "price": { "currency": "USD", "value": 7.35 },
                  "payment_methods": ["transponder"],
                  "transponders": ["E-ZPass"],
                  "counted": true }
              ]
            }
          ]
        }
      ],
      "geometry": { "type": "LineString", "coordinates": [ /* ... */ ] }
    }
  ],
  "route_id": "rt_a17f93c0"
}
Enter fullscreen mode Exit fullscreen mode

The fares under one toll system are alternatives, not line items — don’t add them up. Each is the same charge under a different payment method (payment_methods: transponder, videoToll, …) or time window (applicable_times), and the driver pays exactly one of them. summary.toll_costs has already picked one fare per system — the transponder tariff where one exists, otherwise the cheapest payment group — and marks it counted: true. That total is the number you’d quote a customer or drop into a lane-cost model; the sections[].tolls[] detail is where you see which authority charges what, and what the same stretch costs without a transponder.

Priced for the Vehicle, Not a Sedan

This is the whole point. The fare you get back is keyed to the truck profile on the request — axle count, gross weight, height, and the hazmat flag all factor into the classification the toll engine prices against. A 5-axle combination doesn’t get a 2-axle rate; a heavy load doesn’t get a light-vehicle rate. The fares[].name echoes the class that was applied (e.g. “Class 5 (5 axles)”) so you can confirm the truck was rated the way you expected.

Routing Around Tolls

Sometimes the answer is to skip the toll road entirely. That’s a different field: put "toll_road" in the avoid array and the engine routes around toll facilities where it can. The avoidance applies to every route in the response, so on its own it only shows you the detour.

To see the trade-off, ask for it instead: add "toll_alternative" to include (it implies "tolls"). You get the fast tolled route as usual, plus a second, toll-free route on toll_alternative with its extra distance and time set against the toll dollars it saves — the decision made explicit instead of a guess.

{ "origin": { /* ... */ }, "destination": { /* ... */ },
  "truck": { /* ... */ },
  "include": ["toll_alternative"] }
Enter fullscreen mode Exit fullscreen mode

It computes two routes, so it is billed as two routing calls. Full shape in the API docs.

What to Expect From the Data

A few honest notes so the numbers behave the way you expect:

  • Major corridors are well covered — Interstate turnpikes, major bridges and tunnels, express lanes, and Canadian facilities like the 407 ETR price reliably for trucks.
  • Coverage thins on the margins. Some secondary or rural toll facilities are known to the engine but may return a system name with no priced fare for a given vehicle class — treat a missing price as “not priced,” not “free.”
  • Send departure_time for an exact figure. Some tolls change by time of day. Without a departure time the engine can’t resolve which window applies, and the total is the worst case for the chosen payment method rather than an optimistic one.
  • It’s a planning estimate. Toll pricing is computed at request time for the route and vehicle class; it’s built for dispatch and quoting, not for reconciling a transponder statement to the cent.
  • No tolls, no array. A toll-free route, or a request that didn’t opt in, simply omits toll_costs and section tolls — the response shape stays stable.

One Call, the Whole Trip

Toll pricing rides the same POST /api/v1/routing/route as the corridor hazard warnings[] and the Hours-of-Service break planning. A single request can hand back a drivable truck route, the clearances and restrictions on it, where the driver must legally stop, and what the trip costs in tolls — the operational picture a dispatcher actually needs before the truck rolls. Routing is on every paid plan from Starter up, and the free 14-day trial includes it.

Try It


Originally published on road511.com.

Top comments (0)