> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solvice.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Requirements briefing

> The questions to ask the people who run the operation before you model it as a V3 request: the business facts a data export cannot show.

> [!NOTE]
>
> **V3 is in beta.** General availability (GA) is planned for January 2027.

A data export says where the stops are and how heavy the parcels are. It does
not say whether "between 9 and 12" is a promise or a habit, whether a van may
go back to the depot at noon, or what an hour of overtime costs. Those facts
decide which V3 fields you set, and a wrong guess is hard to spot later: the
solver obeys it and the plan looks fine.

Ask the dispatcher, planner or operations manager these questions once, and
keep the answers as a **modelling report** next to the request. Each question
names the field its answer sets; where V3 has no field, the answer goes in the
report as an open point. For how the fields fit together, see
[The V3 API model](https://docs.solvice.io/guides/vrp/v3/api-design.md).

## 1. Context and scope

* What is being planned: deliveries, collections, service visits, or goods
  moved between two addresses on one vehicle? Sets: `jobs[]` for work at one
  address, `shipments[]` for a pickup and delivery pair.
* What is the planning horizon: one day, several days, a week? Sets: one
  `shifts[]` entry per vehicle per working day, with its own `from` and `to`.
* How many tasks and vehicles on a normal day, and on the busiest? Sets: the
  endpoint. `POST /v3/routing/solve` takes up to 400 tasks and 60 seconds;
  `POST /v3/routing/runs` up to 10,000 tasks and 3,600 seconds. See
  [Async runs](https://docs.solvice.io/guides/vrp/v3/runs.md).
* Who waits for the plan, and how long: a dispatcher at a screen or a nightly
  batch? Sets: `options.time_limit_s`, and sync against async.
* Is each plan built from scratch, or does it change a day already under way?
  Sets: `plan.routes[]` with `locked_count` for stops that must not move and
  `pinned` for stops that must stay on their vehicle.

> [!WARNING]
>
> A week written as one shift from Monday 08:00 to Friday 17:00 is accepted, and
> lets a vehicle work through four nights. Each working day is its own `shifts[]`
> entry.

## 2. Tasks

* How long does a visit take, and is it the same for every worker? Is part of
  it paid once per address rather than per task? Sets:
  `service_duration_s`, `setup_duration_s`, `vehicles[].service_factor` and
  per-task `service_factors[]`.
* When a customer is told "between 9 and 12" and the driver arrives at 12:20,
  is the visit refused, or accepted with a complaint? Sets: a hard window with
  `time_windows[].from` and `to`; a priced late side with
  `time_windows[].per_late_hour`, or `objective.per_late_hour` fleet-wide.
* Does a customer get several acceptable slots, with one preferred? Sets:
  several `time_windows[]` on the task, `time_windows[].choice_cost` on the
  less welcome ones.
* Is there a promised time that is a goal rather than a cutoff ("we aim for
  10:00")? Sets: `target.at`, `target.on` and `target.per_late_hour`.
* Must every task be served? If some may be left out, what does leaving one
  out cost in money? Sets: `drop_cost` on the optional tasks; a task without
  it is never dropped.
* Among the must-serve tasks, which outrank which when the fleet is short?
  Sets: `priority`, a rank rather than a price; not combinable with `drop_cost`.

> [!WARNING]
>
> A business hour read as a hard cutoff is the most common silent error: tasks
> the customer would have taken at 12:20 come back unassigned on `time_window`.
> The reverse is as bad: a contractual window priced with `per_late_hour` is
> broken whenever that is cheaper than the detour.

## 3. Vehicles and shifts

* Where does each vehicle start and end the day: a depot, the driver's home,
  or wherever its last stop is? Sets: `shifts[].start` and `shifts[].end`, each
  a `depot` id or a `location`; omit one for an open route.
* Does the drive to the first stop, or home from the last, count as working
  time? Sets: `shifts[].free_start_travel`, `shifts[].free_end_travel` or
  `shifts[].start_at_first_task`.
* When may a route start, and by when must the vehicle be back with unloading
  done? Sets: `shifts[].from` and `shifts[].to`, plus `depots[].service_duration_s`
  for the handling at either end.
* Is overtime allowed? How much, and what does an hour of it cost? Sets:
  `shifts[].max_overtime_s` and `costs.per_overtime_hour` on the shift, the
  vehicle or `objective`.
* Which days does each vehicle work, and does anything change by day: another
  crew, a trailer, a shorter day? Sets: one `shifts[]` entry per day, with
  `shifts[].skills`, `shifts[].capacity` or `shifts[].limits` where the day
  differs.

> [!TIP]
>
> `shifts[].to` is a hard end: the whole route, return leg and unload included,
> must finish by it. "They usually finish around 17:00" is not a cutoff. Ask what
> happens at 17:30, and set `max_overtime_s` with a rate when the answer is
> "they get paid for it".

## 4. Breaks

* Are breaks owed, and by which rule: a clock window (lunch between 12:00 and
  14:00), driving time (45 minutes after 4 h 30, EU 561/2006), or working
  time? Sets: `shifts[].breaks[]` with `type` `windowed`, or
  `triggered` with `after` set to `drive` or `duty`.
* How long is each break, and after how much driving or work is it due? Sets:
  `duration_s` and, for a triggered break, `threshold_s`.
* Is the break taken wherever the driver is when it is due, or is it an
  interval in which nobody works? Sets: `windowed` or `triggered` for a
  floating break, `fixed` with `from` and `to` for an interval.
* May a long job be interrupted by a break, or must the break fall between
  jobs? Sets: `jobs[].break_interruptible`.
* Must the break be taken at a particular place, such as the depot? Sets:
  nothing: a `location` on a windowed break is a `400 not_supported`. Note the place in the modelling report.

> [!WARNING]
>
> Breaks are hard and unpriced. A break left out because the export has no
> column for it makes every route 30 to 45 minutes shorter on paper than on the
> road. Ask for the rule even when nobody mentions breaks.

## 5. Capacity and load

* What limits a vehicle's load: weight, volume, pallets, parcels? Which of
  these ever binds? Sets: `vehicles[].capacity` and the matching
  `jobs[].pickup_load`, `jobs[].delivery_load` or `shipments[].load`, up to four
  named dimensions.
* What is the real figure for each vehicle type, and in which unit? Values
  are integers, so pick a unit where rounding is harmless. Sets: the values in
  `capacity` and the load maps.
* Do goods go out from the depot, come back in, or both at one visit? Sets:
  `delivery_load` for drop-offs, `pickup_load` for collections, both on one
  job for a swap.
* Can a vehicle return to a depot mid-shift to reload or empty? Which depots,
  how long does it take, how many trips a day? Sets: `depots[]`,
  `shifts[].reloads`, `shifts[].max_trips`, `depots[].service_duration_s` and
  `depots[].per_reload`.
* Must the vehicle end the day empty, as a waste truck tips before the yard?
  Is anything on board at shift start? Sets: `shifts[].unload_before_end` and
  `shifts[].initial_load`.

> [!TIP]
>
> Agree the dimension names in the briefing. A vehicle whose `capacity` omits a
> dimension has `0` of it, and one with no `capacity` carries anything, so a name
> that differs between vehicles and jobs is not an error: it leaves every job
> that needs it unassigned on `capacity`, or removes the limit.

## 6. Skills, tags and eligibility

* Which tasks need a qualification, tool or licence that only some vehicles
  carry? Is it yes-or-no, or graded? Sets: `jobs[].required_skills` with
  `name` and `min_level`; `vehicles[].skills` with `name` and `level`.
* Is that requirement absolute, or a preference ("this customer likes Ann")?
  What happens when the preferred vehicle is full? Sets: hard,
  `eligible_vehicles.allowed`; soft, `preferences[].vehicle` with
  `violation_cost`.
* Are there vehicles that must never visit certain customers? Sets:
  `eligible_vehicles.excluded`.
* Are there territories? Must a vehicle stay in its zone, or does it just
  prefer it? Sets: `jobs[].tags` with `shifts[].serves_tags` for a hard zone,
  or `vehicles[].preferred_tags[].violation_cost` for a soft one.
* Does it cost more to send one vehicle than another, as with a subcontractor
  rate? Sets: `assignment_costs[].vehicle` and `cost`.

> [!WARNING]
>
> "Preferred" written as `eligible_vehicles.allowed` with one id turns a wish
> into a wall: when that vehicle is full the task is unassigned instead of going
> to the second choice. Only a rule the operation would refuse to break belongs
> in `eligible_vehicles` or `required_skills`.

## 7. Relations and crews

* Must some tasks be done in a fixed order, such as a survey before an
  install? On the same route, or on any? Sets: `relations[]` of type
  `sequence`, or `consecutive` for back-to-back, plus `same_route` to keep
  them on one route.
* Must a set of tasks go to one vehicle, or happen on the same day? Sets:
  `same_vehicle` or `same_day`, by `stops` or by `tag`.
* Do two vehicles have to be at one job at the same time, as in a two-person
  lift? Which pairs may work together? Sets: `synchronized` with
  `max_spread_s`; `compatible_vehicles` with `vehicles[].compatible_with`.
* Is there a required gap between two tasks: deliver a machine and collect it
  two hours later, or a cure time? Sets: `time_lag` with `min_s`, `max_s` and
  `on`.
* If one task of a group cannot be done, should the others be left out too?
  Sets: `all_or_none`.

> [!TIP]
>
> Every relation is hard and has no price. A `sequence` alone does not put its
> members on one route, and a `synchronized` pair on a day with one eligible
> vehicle leaves both tasks unassigned. Ask how often the crew rule holds today
> before you make it hard.

## 8. Limits and fairness

* Is there a maximum per route in distance, hours or stops? A rule the
  operation enforces, or a habit? Sets: `vehicles[].limits` with
  `max_distance_m`, `max_route_duration_s` and `max_stops`; `shifts[].limits`
  for one day.
* Are there caps across days: a weekly driving limit, a blocked date? Sets:
  `limits.periods[]` with `every` set to `day` or `week`, or an explicit
  `from` and `to`.
* Does a pool of vehicles share one quota, such as contractors who together
  install at most twenty units a day? Sets: `quotas[]` with `vehicles`,
  `tasks` and `max_stops`.
* Should work be spread evenly across drivers, and how much imbalance is
  acceptable? Sets: `objective.workload_share` with `per_imbalance_hour` and
  `tolerance`, and `vehicles[].workload_weight`.
* Over several days, should work be done as early as possible? Sets:
  `objective.per_delay_workday`.

> [!WARNING]
>
> Route limits are hard, and `max_route_duration_s` counts waiting as well as
> driving and service. A "max 8 hours" that is really a habit comes back as tasks
> unassigned on `max_route_duration`. Fairness is soft: a plan stays uneven when
> evenness costs more than the rate you set.

## 9. Costs, objective and data quality

* What currency, and what does an hour of a route and a kilometre cost? Do
  vehicles differ? Sets: `objective.currency`, `objective.costs.per_route_hour`
  and `per_travel_km` (defaults 35 and 0.20), with `vehicles[].costs` or
  `shifts[].costs` where one differs. See
  [Objective function](https://docs.solvice.io/guides/vrp/v3/concepts/scoring-explanation.md).
* Is using fewer vehicles a goal, and what does one vehicle cost for a day?
  Sets: `costs.per_route` per used shift, or `costs.per_used_vehicle` once per
  vehicle. Both default to `0`: until you set one, the vehicle count is free.
* Is waiting paid, and is driving paid differently from time on the route?
  Sets: `costs.per_wait_hour` and `costs.per_drive_hour`.
* Where do the coordinates come from, and which addresses are known to be
  unreliable: farms, industrial estates, PO boxes, site codes? Sets: every
  `location`, as `[longitude, latitude]`. The API does not geocode; list the
  doubtful addresses in the modelling report.
* Which time zone does the operation run in, and does the horizon cross a
  clock change? Sets: the UTC offset on every timestamp, `shifts[].from` and
  `time_windows[].from` included. A timestamp without one is a `400`, and the
  offset of a shift's `from` decides its calendar day; see
  [How days are counted](https://docs.solvice.io/guides/vrp/v3/constraints.md#how-days-are-counted).
* Should travel times reflect typical traffic at the departure hour, or
  free-flow? Any truck restrictions? Sets: `travel.engine`,
  `travel.departure_time` and `vehicles[].profile`.

> [!TIP]
>
> A coordinate pair written latitude first lands in the wrong country: a `400`
> for spanning more than one region, or tasks unassigned on `unreachable`. Check
> one coordinate from the export on a map before the first request.

## After the briefing

The answers and open points are the modelling report: what you check the
request against as you build it, and the first thing to reread when a plan
looks wrong. An AI agent building the request needs the same answers;
[AI agents](https://docs.solvice.io/guides/vrp/v3/ai-agents.md) says how it uses them.

> [card] [Constraints](https://docs.solvice.io/guides/vrp/v3/constraints.md)
>
> Which rules are hard, which are priced, and how a broken rule shows up.

> [card] [AI agents](https://docs.solvice.io/guides/vrp/v3/ai-agents.md)
>
> Turning these answers and a data export into a request.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.