Overview
POST /v3/routing/suggest answers one question: given the plan I already have, where can this new task go, and what does each option cost? You send the problem, the plan you have committed to, and the ids of the tasks to place. For each task 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 option yourself.
The request
The body has three required parts: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.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. The tasks to place must not be in it. A route’s locked_count marks stops that are already dispatched: no option lands before them.array of strings
required
The ids of the jobs or shipments to place. At least one. Each must exist in
problem, appear once, and be absent from plan.integer
default:"5"
Maximum number of ranked options per task.
0 returns every feasible placement. Positive values above 100 are lowered to 100.integer
Search budget in seconds, at most
300. 0 is raised to 100 ms. Omit it and the search runs to completion, which is what you want for a single job. The clock starts when the search starts, so fetching travel times does not eat into it.problem that is in neither plan nor options.tasks is treated as unassigned context and gets no suggestions.
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 you named, 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 placements, cheapest first. Empty when there is none;
reason then says why.string
Present only when
options is empty. One of three fixed sentences: see When a task gets no options.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 option. A single job with no time_limit_s is never truncated.integer
Wall-clock time of the whole request, in milliseconds.
When a task gets no options
An emptyoptions list is a 200, not an error. The entry’s reason is one of these three sentences:
reason is written for people and logs. In code, branch on the empty options list and on truncated: when truncated is false, an empty list is final. truncated covers the whole response, so with several tasks in one request it does not say which task was cut short; send one task per request when you need that.
Reading an option
extra_cost and extra_duration_s measure different things. In the example the first option 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 options. To act on one, edit the plan yourself and send it back:1
Find the route
Take the option’s
vehicle and the shift at shift_index in that vehicle’s shifts[], and find the plan.routes[] entry with that vehicle and shift id. If the vehicle was unused, add a new route entry for it.2
Insert the stop
Insert
{ "type": "job", "id": "<job_id>" } so that it becomes task stop number position of the trip. On a route without reloads that is index position in stops. For the first option above, plan becomes:3
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. Name the shipment id in
options.tasks. Its pickup and delivery are placed together: the option’s top-level fields describe the pickup, andassignments[]lists both legs with atypeofpickupordelivery. Either both legs are inplanor neither is. ordered,same_resourceandsame_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 that takes part in one of these cannot be suggested; the request is rejected with a400.- Reloads. An option 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 and options 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 option.
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.