The V3 model is rolling out in phases. The request schema and the core
optimisation (named capacity, hard time windows, skills, vehicle eligibility,
sequencing, pickup & delivery shipments, the priorities objective) are available now.
Advanced capabilities — driver breaks, depot reloads, soft time windows, cross-vehicle
synchronisation — are reserved in the schema and currently return a clear
400
naming the field. See Availability below.Design principles
Few orthogonal primitives
One concept, one mechanism. Vehicle eligibility, skills, and sequencing are
each a single field — not five overlapping ones.
Everything soft is money
No abstract weight vector. Lateness costs a rate per hour; a non-preferred
vehicle costs an amount. One unit you trade against, and an itemised cost
breakdown in every response.
Penalties live on the thing
A preference is a property of a job, so its violation cost sits on the job —
read one job and you see exactly what it costs to bend each rule.
Pit of success
Every advanced field is optional with a no-op default. You never see
eligible_vehicles or objective until you need them.A request at a glance
The smallest valid request — minimise total time, serve everything:jobs, vehicles, depots,
locations, relations, objective, and options. Only jobs and
vehicles are required.
Jobs
A job is a unit of work — a delivery, pickup, service call, or inspection. A single-visit job has its visit fields (location, service_duration_s,
time_windows) directly on the object. Shipments use pickup + delivery
instead (Coming soon).
Where the job is performed. A
Place is one of:{ "coordinate": [lon, lat] }— inline GeoJSON coordinate (Available){ "location_id": "..." }— reference intolocations[](Coming soon){ "depot": "..." }— reference intodepots[](Coming soon)
One or more time windows. Each window is
{ "from": "...", "to": "..." } (ISO 8601).
Hard by default — arriving outside the window makes the job unassignable.Soft windows with earliness_cost_per_hour / lateness_cost_per_hour are Coming soon.Named multi-dimensional load, e.g.
{ "weight": 30, "volume": 2 }. Vehicle
capacity uses the same dimension names — matched by name, so order never
matters and errors name the overflowing dimension exactly.
Available.true = the job must be served; the solve is infeasible if it cannot be.
false (default) = droppable. Use unassigned_cost to price the drop.
Available.Cost of leaving this job unassigned. The solver drops the job only when the
saving exceeds this price. Ignored when
mandatory: true.
Available.Capability requirements:
[{ "name": "fridge" }]. The serving vehicle must
have all named skills. Hard (no violation_cost) is Available.
Soft skills with violation_cost are Coming soon.Hard vehicle filter.
allowed is a whitelist (omit = all vehicles eligible);
excluded is a blacklist. Available.Soft vehicle preferences (preferences: [{ "vehicle": "v2", "violation_cost": 800 }])
are Coming soon.Vehicles & shifts
A vehicle carries capacity, skills, a cost model, and one or more shifts. The shift is where the working window and depot locations live.Clone this vehicle definition N times. Response carries
{ "type": "truck-1", "instance": 1 }
… { "instance": N } so results stay traceable. Available.Named dimensions, matched against job
demand by name.
Available.Per-vehicle route caps.
max_distance_m, max_drive_time_s, max_duty_time_s
are hard bounds. max_tasks caps the number of stops on the route.
Available.Per-vehicle cost rates.
fixed is charged when the vehicle is used;
per_travel_hour is the travel rate. per_km, per_stop, per_service_hour,
per_wait_hour, and per_overtime_hour are Coming soon for the
multi-term cost model.Per-shift depot location.
start is where the vehicle departs; end is
where it must return. Omit end for an open route (no return leg).
Depot references by ID are Coming soon — use inline coordinate for now.
Available (inline coordinate).How many seconds past
to the vehicle may run, priced via cost.per_overtime_hour.
Available.Scheduled breaks inserted into the route timeline. Coming soon.
Mid-route depot visits to reload capacity. Coming soon.
Relations
A singlerelations array expresses every inter-job constraint. Each relation
is a tagged-union object identified by type. violation_cost absent (or
omitted) = hard; a positive value = soft (Coming soon for soft relations).
| Type | Meaning | Status |
|---|---|---|
ordered | Jobs appear in this order on one route | Available |
consecutive | Jobs are adjacent (no stops between them) | Available |
same_resource | Jobs served by the same resource across days | Available |
same_route | Jobs on the same route in one shift | Available |
same_day | Jobs served on the same calendar day | Coming soon |
synchronized | Two vehicles meet at a location within max_wait_s | Coming soon |
Objective
The optimisation goal is one coherent, money-denominated model. The whole block is optional — omit it for “minimise total time, serve everything”.priorities— an ordered list of lexicographic tiers.minimize_vehiclesmakes the solver use as few vehicles as possible before optimising cost; drop it and vehicle count becomes free.costs— fleet-default rates.per_travel_houris available now.per_travel_km,per_late_hour,per_wait_hour, andper_overtime_hourare Coming soon for the multi-term cost model.
skills[].violation_cost, preferences[].violation_cost) — not in a global
table.
Response
A solve returns asummary, per-stop routes, and unassigned jobs with
structured reasons.
summary.status—solved,partial, orinfeasiblesummary.estimated_cost— always present, itemised by componentroutes[].vehicle—{ "type": "...", "instance": N }for multi-count vehiclesroutes[].stops[].type—start,task,pickup,delivery,break,reload,endroutes[].stops[].load_after— named load map after serving this stopunassigned[].job_id— the id of the unassigned jobunassigned[].reasons— structured{ code, message }objects (no legacyreasonstring)
Availability
The V3 schema is stable. Capabilities land in phases — anything not yet wired returns a400 that names the unsupported field, so you never get a
silently-wrong plan.
| Capability | Status |
|---|---|
Single-visit jobs (flat location, service_duration_s, time_windows), named capacity/demand, hard time windows | Available |
Hard skills (name only), eligible_vehicles (allowed/excluded) | Available |
mandatory: true, unassigned_cost (droppable at a price) | Available |
Inline shift depots (start/end coordinate), open routes, count | Available |
max_overtime_s, vehicle limits (max_distance_m, max_drive_time_s, max_tasks) | Available |
Single-term vehicle cost (fixed, per_travel_hour) | Available |
ordered (job ids & tag groups), consecutive, same_resource, same_route relations | Available |
objective.priorities, objective.costs.per_travel_hour | Available |
Itemised estimated_cost + structured unassigned[].reasons in response | Available |
Soft time windows (earliness_cost_per_hour / lateness_cost_per_hour) | Coming soon |
Soft skills (violation_cost on skills[]) | Coming soon |
Vehicle preferences (soft affinity, priced) | Coming soon |
setup_duration_s on jobs | Coming soon |
Multi-term vehicle cost (per_km, per_overtime_hour, per_wait_hour, etc.) | Coming soon |
Shipments — job.pickup + job.delivery (mandatory, coordinate legs, hard skills) | Available |
| Droppable / soft-skill / multi-vehicle shipments | Coming soon |
Driver breaks (shift.breaks) | Coming soon |
Depot reloads (shift.reloads) | Coming soon |
Named locations / depot references (location_id, depot in Place) | Coming soon |
same_day / synchronized relations | Coming soon |
objective.balance (fairness / workload balancing) | Coming soon |
Traffic-aware matrices (options.runtime.traffic) | Coming soon |
API Reference
Full request and response schema for
POST /v3/routing/solve.