Skip to main content

Jobs

A job is something that needs to happen at one location. For a simple visit (delivery, service call, inspection) place its visit fields directly on the job object. Pickup-then-delivery work uses a distinct shipments[] entry type instead — see Shipments.
  • location — a Place: { "coordinate": [lon, lat] } (GeoJSON order), inline only — there is no reference into a separate locations/depot list. Omit it entirely for a virtual (location-less) job.
  • service_duration_s — nominal seconds spent at the location, excluding travel; scaled by the serving vehicle’s service_factor.
  • time_windows — when the job can be served (ISO 8601 from/to pairs). Hard by default. Lateness is softened fleet-wide via objective.costs.per_late_hour, per-task via target_arrival, or graded between a task’s own alternative windows via time_windows[].cost — see Constraints for how the three compose.
  • demand — named capacity consumed, e.g. { "weight": 10 }. Matched against vehicle.capacity by name.
  • skills — capability requirements, e.g. [{ "name": "refrigerated" }]. A job can only be served by a vehicle that has all required skills; there is no soft-skill form.
  • mandatory — omit or set true to require the job be served (infeasible if it cannot be). false makes it droppable, and only means something together with drop_fee (below) — a droppable task with no price is rejected.
  • drop_fee — what leaving the job unserved costs, in the objective’s currency. Replaces the removed unassigned_cost field.

Shipments

A shipment is a bound pickup→delivery pair, expressed as its own shipments[] entry (not a flag on a job):
The solver guarantees the pickup precedes the delivery on the same route — same-vehicle and ordering are implicit, never a separate relations[] entry. demand counts against capacity only between the two legs. mandatory/drop_fee/skills/eligible_vehicles apply to the pair as a whole (one decision, one fee).

Vehicles

A vehicle represents a driver or asset with capacity, skills, a cost model, and one or more working shifts. There is no vehicle-level count — fleet size is one entry per physical vehicle.
  • capacity — named dimension limits matched against job/shipment demand by name. { "weight": 1000, "volume": 50 } is two independent caps.
  • skills — capability tags the vehicle provides. A vehicle can serve a job only when its skills are a superset of the job’s required skills.
  • limits — optional hard route caps: max_distance_m and max_route_duration_s. The latter caps the whole-route span from shift departure to final arrival — travel, service, and wait all count, not pure driving time; there is no separate pure-drive-time cap.
  • shifts — working time windows (ISO 8601 from/to). At least one shift is required. start and end are the depot Place for this shift — set inside shifts, not at vehicle top-level; absent means an open start/end on that side. shifts[].max_tasks caps the number of stops in that shift; shifts[].breaks/shifts[].reloads add driver breaks and multi-trip depot reloads (see Constraints).
Multiple shifts on one vehicle model multi-day availability.

Distance matrices

V3 always fetches road-network distance and duration matrices from Solvice Maps — traffic-aware by default (historical-typical traffic for the shift’s departure time; options.runtime.traffic.departure_time overrides the lookup instant). There is no request field to supply a custom matrix; the API always routes through Solvice Maps. Road-network matrices are typically asymmetric (A→B time or distance ≠ B→A).

Constraints

The solver enforces a fixed, closed set of constraint types — each one hard (infeasible if violated) unless noted otherwise: See the full Constraints guide for field-level detail on every one of these, including which are soft and how each soft mechanism is priced.

Objective

The solver ranks feasible solutions in two lexicographic tiers, not a Hard/Medium/Soft point score:
  1. Drop penalty (tier 1) — the summed penalty of unassigned tasks. A must-serve task (the default) carries a large uniform internal penalty, so on a request with no drop_fee set this tier is exactly “number of unassigned tasks” and always outranks cost.
  2. Cost (tier 2) — the weighted currency sum of travel, waiting, overtime, soft lateness, preference violations, and the drop_fee of every priced task the plan chose not to serve.
objective.minimize_vehicles (a bool, default true) is the one real degree of freedom on top of that: whether using fewer vehicles outranks minimising cost. It replaced an objective.priorities token list that could never actually be reordered. Omit the objective block entirely for “minimise travel cost, serve everything, use as few vehicles as it takes” — V3 seeds a realistic default travel baseline (€0.20/km, €35/travel-hour) in that case.
Every response includes an itemised estimated_cost breakdown — travel and waiting are always reported; drop_fees/overtime appear only when priced — so you never need to recompute the objective yourself. See Objective Function for the full ranking and defaulting behaviour.

Relations

Relations express ordering, grouping, and synchronisation between jobs using a single relations array. Each relation is a tagged object with a type, and every relation is hard — there is no per-relation violation_cost.
A relation references jobs either explicitly via job_ids, or by tag via the separate group field — never both. An ordered relation with groups set orders all jobs carrying those tags relative to each other, leaving order within a group free.
relations[] has exactly these four variants. consecutive and same_route were considered and removed from the schema entirely — an unknown relation type is an unknown-field rejection, not a coming-soon 400.
See the full Constraints guide and The V3 API Model for field-level detail.