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).
Place
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)
array
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.object
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.boolean
default:"false"
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.number
Cost of leaving this job unassigned. The solver drops the job only when the
saving exceeds this price. Ignored when
mandatory: true.
Available.array
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.object
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.number
default:"1"
Clone this vehicle definition N times. Response carries
{ "type": "truck-1", "instance": 1 }
… { "instance": N } so results stay traceable. Available.object
Named dimensions, matched against job
demand by name.
Available.object
Per-vehicle route caps.
max_distance_m, max_drive_time_s, max_duty_time_s,
and max_leg_drive_time_s are hard bounds.
Available.object
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.Place
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).integer
How many seconds past
to the vehicle may run, priced via cost.per_overtime_hour.
Available.integer
Maximum number of job stops for this shift. Lives on the shift, not on
vehicle.limits. Available.array
Scheduled breaks inserted into the route timeline. Coming soon.
array
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).
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.
API Reference
Full request and response schema for
POST /v3/routing/solve.