> ## 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.

# Concepts

> Core concepts of the V3 Routing API — vehicles, jobs, constraints, and objectives

## Jobs

A job is something that needs to happen at one or more locations. For a simple visit (delivery, service call, inspection) place its visit fields directly on the job object. Pickup-then-delivery shipments use `pickup` + `delivery` instead — see [Shipments](#shipments).

```json theme={null}
{
  "id": "delivery-1",
  "location": { "coordinate": [4.7005, 50.8798] },
  "service_duration_s": 300,
  "time_windows": [
    {
      "from": "2026-04-01T09:00:00+02:00",
      "to":   "2026-04-01T12:00:00+02:00"
    }
  ],
  "demand": { "weight": 10 },
  "skills": [{ "name": "refrigerated" }]
}
```

* **location** — a `Place`: `{ "coordinate": [lon, lat] }`, or a reference to a named location or depot.
* **service\_duration\_s** — seconds spent at the location, excluding travel.
* **time\_windows** — when the job can be served (ISO 8601 `from`/`to` pairs). Hard by default — no `earliness_cost_per_hour` or `lateness_cost_per_hour`.
* **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.
* **mandatory** — set `true` to require the job be served (infeasible if it cannot be). Omit or use `unassigned_cost` for a droppable job.

### Shipments

<Info>**Coming soon.** Pickup-then-delivery jobs use `job.pickup` + `job.delivery` instead of flat visit fields. The solver guarantees pickup precedes delivery on the same route, and `demand` counts against capacity only between the two stops.</Info>

## Vehicles

A vehicle represents a driver or asset with capacity, skills, a cost model, and one or more working shifts.

```json theme={null}
{
  "id": "truck-1",
  "capacity": { "weight": 1000, "volume": 50 },
  "skills": ["refrigerated"],
  "limits": {
    "max_distance_m": 250000,
    "max_drive_time_s": 28800
  },
  "shifts": [
    {
      "from": "2026-04-01T08:00:00+02:00",
      "to":   "2026-04-01T17:00:00+02:00",
      "start": { "coordinate": [4.3517, 50.8503] },
      "end":   { "coordinate": [4.3517, 50.8503] }
    }
  ]
}
```

* **capacity** — named dimension limits matched against job `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 route caps: `max_distance_m`, `max_drive_time_s`, `max_duty_time_s`, `max_tasks`.
* **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.

Multiple shifts on one vehicle model multi-day availability.

## Distance matrices

V3 automatically fetches road-network distance and duration matrices from [Solvice Maps](https://maps.solvice.io). You don't need to provide a matrix unless you have custom distances.

To supply a custom matrix, include it in `options.runtime.matrix`:

```json theme={null}
{
  "options": {
    "runtime": {
      "matrix": {
        "distances": [
          [0, 1500, 3200],
          [1400, 0, 2100],
          [3100, 2000, 0]
        ],
        "durations": [
          [0, 600, 1200],
          [550, 0, 900],
          [1150, 850, 0]
        ]
      }
    }
  }
}
```

Both matrices must be square N×N. Values are distances in metres and durations in seconds. Road-network matrices are typically **asymmetric** (A→B ≠ B→A).

## Constraints

The solver enforces these constraints (hard — never violated unless explicitly softened):

| Constraint            | Description                                                                                        |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| **Capacity**          | Vehicle load never exceeds capacity on any named dimension                                         |
| **Time windows**      | Jobs served within their allowed time windows                                                      |
| **Skills**            | Vehicle must have all skills required by the job                                                   |
| **Vehicle range**     | Maximum distance or drive time per route                                                           |
| **Sequence**          | Job A served before job B on the same route (`ordered` relation)                                   |
| **Same resource**     | A set of jobs served by the same vehicle across shifts (`same_resource` relation)                  |
| **Eligible vehicles** | Job may only be served by vehicles in `eligible_vehicles.allowed`, never by vehicles in `excluded` |

See the full [Constraints guide](/guides/vrp/v3/constraints) for field-level details and coming-soon capabilities.

## Objective

The solver minimises a lexicographic objective:

1. **Serve as many jobs as possible** (highest priority — assign before optimising cost)
2. **Minimise vehicles used** (use as few vehicles as possible before optimising routes)
3. **Minimise cost** (weighted sum of travel time, distance, and any soft penalties)

The default objective is equivalent to `{ "priorities": ["serve_jobs", "minimize_vehicles", "minimize_cost"] }`. Omit the `objective` block entirely to use these defaults.

```json theme={null}
{
  "objective": {
    "priorities": ["serve_jobs", "minimize_vehicles", "minimize_cost"],
    "costs": {
      "per_travel_hour": 50
    }
  }
}
```

Every response includes an itemised `estimated_cost` breakdown (travel, waiting, overtime, unassigned, etc.) so you never need to recompute the objective yourself.

## Relations

Relations express ordering and grouping constraints between jobs using a single `relations` array. Each relation is a tagged object with a `type`.

```json theme={null}
{
  "relations": [
    {
      "type": "ordered",
      "job_ids": ["pickup-A", "delivery-A", "delivery-B"]
    },
    {
      "type": "same_resource",
      "job_ids": ["monday-visit", "tuesday-followup"]
    }
  ]
}
```

| Type            | Meaning                                                    | Status        |
| --------------- | ---------------------------------------------------------- | ------------- |
| `ordered`       | Jobs appear in listed order on one route                   | **Available** |
| `consecutive`   | Jobs appear consecutively (no stops between them)          | **Available** |
| `same_resource` | Jobs served by the same vehicle (across shifts / days)     | **Available** |
| `same_route`    | Jobs on the same route in the same shift                   | **Available** |
| `same_day`      | Jobs on the same calendar day                              | Coming soon   |
| `synchronized`  | Two vehicles meet at the same location within `max_wait_s` | Coming soon   |

<Tip>
  `job_ids` can reference a **job id** or a **tag** (jobs sharing a tag form a group). An `ordered` relation over tags orders the groups relative to each other while leaving order within each group free.
</Tip>
