V3 is in beta. General availability (GA) is planned for January 2027.
Overview
POST /v3/routing/suggest answers one question: given the plan I already have, where can this new task go, and what does each insertion cost? You send the same body as /v3/routing/evaluate: the problem and the plan you have committed to. Every task of the problem that is not in the plan is a task to place, and for each one you get back a ranked list of feasible insertion positions, best first.
Use it when a new order arrives during the day and a dispatcher (or your own code) should pick a slot, rather than letting the solver rearrange routes that are already on the road. The committed plan is never changed: the API holds no state, so nothing happens until you apply an insertion yourself.
The request
The body has two required parts,problem and plan, plus optional options:
object
required
The same
problem object as on /v3/routing/solve: jobs, shipments, vehicles, depots, relations, objective, travel. It must contain the tasks already in the plan and the tasks you want to place: every task not in plan is placed.object
required
The committed plan, in the shape every solve and evaluate response returns as
plan: one routes[] entry per vehicle shift, each with vehicle, shift and an ordered stops[] list. Leave the tasks to place out of it; at least one task of problem must be missing from it. A route’s locked_count marks stops that are already dispatched: no insertion lands before them.integer
default:"5"
Maximum number of ranked insertions per task.
0 returns every feasible placement. Positive values above 100 are lowered to 100.number
default:"1"
Search budget in seconds, at most
300; fractions are allowed (2.5). Defaults to 1, as on solve. A value below 0.1 is raised to 100 ms. The budget is split across the tasks to place in problem order, each getting an equal share of the time left. The clock starts when the search starts, so fetching travel times does not eat into it.plan or be left out of problem. An old options.tasks field is rejected as unknown_field.
Example
One truck already servesdelivery-1 and delivery-2. A third order, delivery-3, comes in and must be served between 08:00 and 11:00 local time.
The response
delivery-3 after delivery-2 would reach it after its window closes, so that position is not feasible and is not listed.
suggestions[] has one entry per task outside plan, in the order the tasks appear in problem (jobs first, then shipments). Tasks tied together by a relation share one entry: see Shipments and related tasks.
string
The task this entry is about.
array
Feasible insertions, lowest
delta.cost first. Empty when none was found; reason_code then says why.string
Present only when
insertions is empty: time_limit, candidates_exhausted or infeasible. See When a task gets no insertions. New codes may be added; handle a code you do not know generically.string
Present exactly when
reason_code is: the same fact as an English sentence, for people and logs.boolean
One flag for the whole response.
true when options.time_limit_s cut the search short for any task, or when an empty list for a multi-task unit is inconclusive. The lists may then be incomplete or miss the best insertion.integer
Wall-clock time of the whole request, in milliseconds.
When a task gets no insertions
An emptyinsertions list is a 200, not an error. The entry’s reason_code says why, and reason says the same in a sentence:
In code, branch on
reason_code, never on reason. Only infeasible is final; the other two can change with a larger budget or search. New codes may be added: treat one you do not know as not final and show reason. truncated covers the whole response: a task whose list is not empty can also have been cut short, and carries no reason_code. Send one task per request when you need to know which task was cut short.
Reading an insertion
An insertion says what it changes (delta), which stops it adds (placements) and how every changed route reads with it in (routes).
Insertions are ordered by
delta.cost, lowest first.
Each placement says who serves the new stop and when, which is what a booking screen shows:
delta.cost and delta.duration_s measure different things. In the example the first insertion adds more driving than the second, yet costs less: the truck used to wait at delivery-1 for the window to open, and the detour fits inside that wait, so the route does not end any later. See Objective function for what the cost is made of.Applying a suggestion
Suggest only reports insertions. To act on one, swap its routes into your plan:1
Swap in the routes
For each entry of the insertion’s
routes, replace the plan.routes[] entry with the same vehicle and shift, or add it when plan has none. To use one of interchangeable_vehicles instead, first put its vehicle and shift in the insertion’s route. For the first insertion above, plan becomes:2
Confirm or re-optimise
Send the edited plan to
/v3/routing/evaluate to get the full timeline and cost of the new plan, or to /v3/routing/solve as a warm start if the solver may also rearrange the other stops.Shipments and related tasks
- Shipments. Leave both legs of the shipment out of
plan. Its pickup and delivery are placed together, on one route: the insertion’splacements[]lists both legs in route order, each with itstypeofpickupordeliveryand its leg’s stop id. A shipment with only one leg inplanis rejected by the plan import, as on evaluate. sequence,same_vehicleandsame_dayrelations. Tasks tied together by one of these relations are placed as one unit and get one entry, named after the first new task of the unit.synchronizedandtime_lagrelations. A task outsideplanthat takes part in one of these cannot be suggested, and one such task makes the whole request a400, not just its own entry. Put the task inplan, or leave the relation out, to get suggestions for the other tasks.- Reloads. An insertion can land in any existing trip of a multi-trip route, but suggest never adds a new reload trip.
Errors
Suggest returns the same error body as the other endpoints. The cases specific to it:?validate_only=true checks problem, options, and that plan leaves at least one task out, without fetching travel times or searching. It does not check that plan fits the problem; only the real call does.
Evaluate
Score the plan after you apply an insertion.
Errors
The error body, every code, and what to do about each.
The V3 API model
The
problem and plan objects in full.API reference
Request and response schema for every endpoint.