Skip to main content
V3 is in beta. General availability (GA) is planned for January 2027.
A data export says where the stops are and how heavy the parcels are. It does not say whether “between 9 and 12” is a promise or a habit, whether a van may go back to the depot at noon, or what an hour of overtime costs. Those facts decide which V3 fields you set, and a wrong guess is hard to spot later: the solver obeys it and the plan looks fine. Ask the dispatcher, planner or operations manager these questions once, and keep the answers as a modelling report next to the request. Each question names the field its answer sets; where V3 has no field, the answer goes in the report as an open point. For how the fields fit together, see The V3 API model.

1. Context and scope

  • What is being planned: deliveries, collections, service visits, or goods moved between two addresses on one vehicle? Sets: jobs[] for work at one address, shipments[] for a pickup and delivery pair.
  • What is the planning horizon: one day, several days, a week? Sets: one shifts[] entry per vehicle per working day, with its own from and to.
  • How many tasks and vehicles on a normal day, and on the busiest? Sets: the endpoint. POST /v3/routing/solve takes up to 400 tasks and 60 seconds; POST /v3/routing/runs up to 10,000 tasks and 3,600 seconds. See Async runs.
  • Who waits for the plan, and how long: a dispatcher at a screen or a nightly batch? Sets: options.time_limit_s, and sync against async.
  • Is each plan built from scratch, or does it change a day already under way? Sets: plan.routes[] with locked_count for stops that must not move and pinned for stops that must stay on their vehicle.
A week written as one shift from Monday 08:00 to Friday 17:00 is accepted, and lets a vehicle work through four nights. Each working day is its own shifts[] entry.

2. Tasks

  • How long does a visit take, and is it the same for every worker? Is part of it paid once per address rather than per task? Sets: service_duration_s, setup_duration_s, vehicles[].service_factor and per-task service_factors[].
  • When a customer is told “between 9 and 12” and the driver arrives at 12:20, is the visit refused, or accepted with a complaint? Sets: a hard window with time_windows[].from and to; a priced late side with time_windows[].per_late_hour, or objective.per_late_hour fleet-wide.
  • Does a customer get several acceptable slots, with one preferred? Sets: several time_windows[] on the task, time_windows[].choice_cost on the less welcome ones.
  • Is there a promised time that is a goal rather than a cutoff (“we aim for 10:00”)? Sets: target.at, target.on and target.per_late_hour.
  • Must every task be served? If some may be left out, what does leaving one out cost in money? Sets: drop_cost on the optional tasks; a task without it is never dropped.
  • Among the must-serve tasks, which outrank which when the fleet is short? Sets: priority, a rank rather than a price; not combinable with drop_cost.
A business hour read as a hard cutoff is the most common silent error: tasks the customer would have taken at 12:20 come back unassigned on time_window. The reverse is as bad: a contractual window priced with per_late_hour is broken whenever that is cheaper than the detour.

3. Vehicles and shifts

  • Where does each vehicle start and end the day: a depot, the driver’s home, or wherever its last stop is? Sets: shifts[].start and shifts[].end, each a depot id or a location; omit one for an open route.
  • Does the drive to the first stop, or home from the last, count as working time? Sets: shifts[].free_start_travel, shifts[].free_end_travel or shifts[].start_at_first_task.
  • When may a route start, and by when must the vehicle be back with unloading done? Sets: shifts[].from and shifts[].to, plus depots[].service_duration_s for the handling at either end.
  • Is overtime allowed? How much, and what does an hour of it cost? Sets: shifts[].max_overtime_s and costs.per_overtime_hour on the shift, the vehicle or objective.
  • Which days does each vehicle work, and does anything change by day: another crew, a trailer, a shorter day? Sets: one shifts[] entry per day, with shifts[].skills, shifts[].capacity or shifts[].limits where the day differs.
shifts[].to is a hard end: the whole route, return leg and unload included, must finish by it. “They usually finish around 17:00” is not a cutoff. Ask what happens at 17:30, and set max_overtime_s with a rate when the answer is “they get paid for it”.

4. Breaks

  • Are breaks owed, and by which rule: a clock window (lunch between 12:00 and 14:00), driving time (45 minutes after 4 h 30, EU 561/2006), or working time? Sets: shifts[].breaks[] with type windowed, or triggered with after set to drive or duty.
  • How long is each break, and after how much driving or work is it due? Sets: duration_s and, for a triggered break, threshold_s.
  • Is the break taken wherever the driver is when it is due, or is it an interval in which nobody works? Sets: windowed or triggered for a floating break, fixed with from and to for an interval.
  • May a long job be interrupted by a break, or must the break fall between jobs? Sets: jobs[].break_interruptible.
  • Must the break be taken at a particular place, such as the depot? Sets: nothing: a location on a windowed break is a 400 not_supported. Note the place in the modelling report.
Breaks are hard and unpriced. A break left out because the export has no column for it makes every route 30 to 45 minutes shorter on paper than on the road. Ask for the rule even when nobody mentions breaks.

5. Capacity and load

  • What limits a vehicle’s load: weight, volume, pallets, parcels? Which of these ever binds? Sets: vehicles[].capacity and the matching jobs[].pickup_load, jobs[].delivery_load or shipments[].load, up to four named dimensions.
  • What is the real figure for each vehicle type, and in which unit? Values are integers, so pick a unit where rounding is harmless. Sets: the values in capacity and the load maps.
  • Do goods go out from the depot, come back in, or both at one visit? Sets: delivery_load for drop-offs, pickup_load for collections, both on one job for a swap.
  • Can a vehicle return to a depot mid-shift to reload or empty? Which depots, how long does it take, how many trips a day? Sets: depots[], shifts[].reloads, shifts[].max_trips, depots[].service_duration_s and depots[].per_reload.
  • Must the vehicle end the day empty, as a waste truck tips before the yard? Is anything on board at shift start? Sets: shifts[].unload_before_end and shifts[].initial_load.
Agree the dimension names in the briefing. A vehicle whose capacity omits a dimension has 0 of it, and one with no capacity carries anything, so a name that differs between vehicles and jobs is not an error: it leaves every job that needs it unassigned on capacity, or removes the limit.

6. Skills, tags and eligibility

  • Which tasks need a qualification, tool or licence that only some vehicles carry? Is it yes-or-no, or graded? Sets: jobs[].required_skills with name and min_level; vehicles[].skills with name and level.
  • Is that requirement absolute, or a preference (“this customer likes Ann”)? What happens when the preferred vehicle is full? Sets: hard, eligible_vehicles.allowed; soft, preferences[].vehicle with violation_cost.
  • Are there vehicles that must never visit certain customers? Sets: eligible_vehicles.excluded.
  • Are there territories? Must a vehicle stay in its zone, or does it just prefer it? Sets: jobs[].tags with shifts[].serves_tags for a hard zone, or vehicles[].preferred_tags[].violation_cost for a soft one.
  • Does it cost more to send one vehicle than another, as with a subcontractor rate? Sets: assignment_costs[].vehicle and cost.
“Preferred” written as eligible_vehicles.allowed with one id turns a wish into a wall: when that vehicle is full the task is unassigned instead of going to the second choice. Only a rule the operation would refuse to break belongs in eligible_vehicles or required_skills.

7. Relations and crews

  • Must some tasks be done in a fixed order, such as a survey before an install? On the same route, or on any? Sets: relations[] of type sequence, or consecutive for back-to-back, plus same_route to keep them on one route.
  • Must a set of tasks go to one vehicle, or happen on the same day? Sets: same_vehicle or same_day, by stops or by tag.
  • Do two vehicles have to be at one job at the same time, as in a two-person lift? Which pairs may work together? Sets: synchronized with max_spread_s; compatible_vehicles with vehicles[].compatible_with.
  • Is there a required gap between two tasks: deliver a machine and collect it two hours later, or a cure time? Sets: time_lag with min_s, max_s and on.
  • If one task of a group cannot be done, should the others be left out too? Sets: all_or_none.
Every relation is hard and has no price. A sequence alone does not put its members on one route, and a synchronized pair on a day with one eligible vehicle leaves both tasks unassigned. Ask how often the crew rule holds today before you make it hard.

8. Limits and fairness

  • Is there a maximum per route in distance, hours or stops? A rule the operation enforces, or a habit? Sets: vehicles[].limits with max_distance_m, max_route_duration_s and max_stops; shifts[].limits for one day.
  • Are there caps across days: a weekly driving limit, a blocked date? Sets: limits.periods[] with every set to day or week, or an explicit from and to.
  • Does a pool of vehicles share one quota, such as contractors who together install at most twenty units a day? Sets: quotas[] with vehicles, tasks and max_stops.
  • Should work be spread evenly across drivers, and how much imbalance is acceptable? Sets: objective.workload_share with per_imbalance_hour and tolerance, and vehicles[].workload_weight.
  • Over several days, should work be done as early as possible? Sets: objective.per_delay_workday.
Route limits are hard, and max_route_duration_s counts waiting as well as driving and service. A “max 8 hours” that is really a habit comes back as tasks unassigned on max_route_duration. Fairness is soft: a plan stays uneven when evenness costs more than the rate you set.

9. Costs, objective and data quality

  • What currency, and what does an hour of a route and a kilometre cost? Do vehicles differ? Sets: objective.currency, objective.costs.per_route_hour and per_travel_km (defaults 35 and 0.20), with vehicles[].costs or shifts[].costs where one differs. See Objective function.
  • Is using fewer vehicles a goal, and what does one vehicle cost for a day? Sets: costs.per_route per used shift, or costs.per_used_vehicle once per vehicle. Both default to 0: until you set one, the vehicle count is free.
  • Is waiting paid, and is driving paid differently from time on the route? Sets: costs.per_wait_hour and costs.per_drive_hour.
  • Where do the coordinates come from, and which addresses are known to be unreliable: farms, industrial estates, PO boxes, site codes? Sets: every location, as [longitude, latitude]. The API does not geocode; list the doubtful addresses in the modelling report.
  • Which time zone does the operation run in, and does the horizon cross a clock change? Sets: the UTC offset on every timestamp, shifts[].from and time_windows[].from included. A timestamp without one is a 400, and the offset of a shift’s from decides its calendar day; see How days are counted.
  • Should travel times reflect typical traffic at the departure hour, or free-flow? Any truck restrictions? Sets: travel.engine, travel.departure_time and vehicles[].profile.
A coordinate pair written latitude first lands in the wrong country: a 400 for spanning more than one region, or tasks unassigned on unreachable. Check one coordinate from the export on a map before the first request.

After the briefing

The answers and open points are the modelling report: what you check the request against as you build it, and the first thing to reread when a plan looks wrong. An AI agent building the request needs the same answers; AI agents says how it uses them.

Constraints

Which rules are hard, which are priced, and how a broken rule shows up.

AI agents

Turning these answers and a data export into a request.