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

# Migration from V2

> How to migrate from the V2 VRP API (OnRoute) to the V3 Routing API

## Overview

The V3 Routing API is a ground-up rewrite with a new, faster solver engine replacing Timefold. The V2 endpoint (`/v2/vrp/sync/solve`) remains available for backwards compatibility — internally it maps to V3 and back.

## Endpoint change

|                       | V2 (OnRoute)                             | V3 (Routing)                                          |
| --------------------- | ---------------------------------------- | ----------------------------------------------------- |
| **URL**               | `POST /v2/vrp/sync/solve`                | `POST /v3/routing/solve`                              |
| **Auth**              | `Authorization: API_KEY`                 | `Authorization: API_KEY`                              |
| **Coordinate format** | `{"latitude": 50.85, "longitude": 4.35}` | `{ "coordinate": [4.35, 50.85] }` (GeoJSON: lon, lat) |
| **Time format**       | ISO 8601 strings                         | ISO 8601 strings                                      |
| **Field naming**      | camelCase                                | snake\_case                                           |

## Request mapping

### Vehicles (Resources → Vehicles)

<CodeGroup>
  ```json V2 (Resource) theme={null}
  {
    "name": "truck-1",
    "shifts": [
      {
        "from": "2026-04-01T08:00:00+02:00",
        "to": "2026-04-01T17:00:00+02:00",
        "start": { "latitude": 50.8503, "longitude": 4.3517 },
        "end": { "latitude": 50.8503, "longitude": 4.3517 }
      }
    ],
    "capacity": [100],
    "tags": ["refrigerated"]
  }
  ```

  ```json V3 (Vehicle) theme={null}
  {
    "id": "truck-1",
    "capacity": { "weight": 100 },
    "skills": ["refrigerated"],
    "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] }
      }
    ]
  }
  ```
</CodeGroup>

**Key differences:**

* `name` → `id`
* `shifts[].start/end` move to inside `shifts[]` as a `Place` (`{ "coordinate": [lon, lat] }`) — this is still inside the shift in both V2 and V3, but the coordinate format changes
* Coordinates: `{ "latitude", "longitude" }` object → `{ "coordinate": [longitude, latitude] }` Place (GeoJSON order, wrapped in object)
* `capacity`: array `[100]` → named map `{ "weight": 100 }` (dimension names must match job `demand` keys)
* `tags` → `skills` (note: V2 tags are **not automatically mapped** when using the V2 compat endpoint)
* New: `limits.max_distance_m`, `limits.max_drive_time_s` for vehicle range constraints

### Jobs

<CodeGroup>
  ```json V2 (Job) theme={null}
  {
    "name": "delivery-1",
    "location": { "latitude": 50.8798, "longitude": 4.7005 },
    "duration": 300,
    "load": [10],
    "windows": [
      {
        "from": "2026-04-01T09:00:00+02:00",
        "to": "2026-04-01T12:00:00+02:00",
        "hard": true
      }
    ]
  }
  ```

  ```json V3 (Job) theme={null}
  {
    "id": "delivery-1",
    "location": { "coordinate": [4.7005, 50.8798] },
    "service_duration_s": 300,
    "demand": { "weight": 10 },
    "time_windows": [
      {
        "from": "2026-04-01T09:00:00+02:00",
        "to": "2026-04-01T12:00:00+02:00"
      }
    ]
  }
  ```
</CodeGroup>

**Key differences:**

* `name` → `id`
* `location`: `{ "latitude", "longitude" }` → Place object `{ "coordinate": [longitude, latitude] }`
* `duration` → `service_duration_s` (still in seconds)
* `load` array → `demand` named map (e.g. `[10]` → `{ "weight": 10 }`)
* `windows` → `time_windows` (no `hard` flag — all time windows are hard in V3 Phase 1)
* Skills and committed vehicle: `skills: [{ "name": "refrigerated" }]`, `eligible_vehicles: { "allowed": ["truck-1"] }` — Coming soon (Phase 2)

### Relations

V3 uses a tagged-union format with `job_ids` (not `jobs`). V2 relation types map as follows:

| V2 `type`   | V3 `type`                                  | Notes                                                         |
| ----------- | ------------------------------------------ | ------------------------------------------------------------- |
| `SEQUENCE`  | `ordered`                                  | `job_ids` instead of `jobs`; `resource` pin not yet supported |
| `FIRST_JOB` | `ordered` with a single entry in `job_ids` | Pin job to position 1 in route                                |

<CodeGroup>
  ```json V2 (SEQUENCE) theme={null}
  {
    "type": "SEQUENCE",
    "jobs": ["job-A", "job-B", "job-C"],
    "resource": "truck-1"
  }
  ```

  ```json V3 (ordered) theme={null}
  {
    "type": "ordered",
    "job_ids": ["job-A", "job-B", "job-C"]
  }
  ```
</CodeGroup>

**Note:** V2's `resource` field (pin relation to a specific vehicle) is not yet supported in V3. Use `eligible_vehicles` on individual jobs as a workaround — Coming soon.

### Options

<CodeGroup>
  ```json V2 theme={null}
  {
    "solvingTime": 30
  }
  ```

  ```json V3 theme={null}
  {
    "options": {
      "runtime": {
        "time_limit_ms": 5000,
        "seed": 42
      }
    }
  }
  ```
</CodeGroup>

**Key differences:**

* `solvingTime` (seconds) → `options.runtime.time_limit_ms` (milliseconds)
* New: `options.runtime.seed` for reproducible results
* New: `options.runtime.matrix` — supply custom distance/duration matrices (bypasses Solvice Maps)
* Objective tuning (minimize time vs. distance) is configured via the `objective` field — Coming soon

## Response mapping

<CodeGroup>
  ```json V2 Response theme={null}
  {
    "trips": [
      {
        "resource": "truck-1",
        "visits": [
          {
            "job": "delivery-1",
            "arrival": "2026-04-01T09:30:00+02:00",
            "location": { "latitude": 50.8798, "longitude": 4.7005 }
          }
        ],
        "travelTime": 3600,
        "distance": 30000
      }
    ],
    "unserved": ["delivery-3"],
    "unservedReasons": {
      "delivery-3": ["Time window violated"]
    },
    "totalTravelTimeInSeconds": 3600,
    "totalTravelDistanceInMeters": 30000
  }
  ```

  ```json V3 Response theme={null}
  {
    "summary": {
      "status": "solved",
      "total_distance_m": 142000,
      "total_duration_s": 7200,
      "vehicles_used": 1,
      "jobs_assigned": 2,
      "jobs_unassigned": 0,
      "estimated_cost": {
        "total": 7200,
        "components": {
          "travel": 7200,
          "waiting": 0,
          "overtime": 0,
          "lateness": 0,
          "vehicles_fixed": 0,
          "unassigned": 0,
          "preferences": 0,
          "imbalance": 0
        }
      },
      "elapsed_ms": 850,
      "iterations": 1200
    },
    "routes": [
      {
        "vehicle": { "type": "truck-1", "instance": 1 },
        "distance_m": 142000,
        "duration_s": 7200,
        "overtime_s": 0,
        "stops": [
          {
            "type": "start",
            "location": [4.3517, 50.8503],
            "departure": "2026-04-01T08:00:00+02:00"
          },
          {
            "type": "job",
            "id": "delivery-2",
            "location": [3.7303, 51.0500],
            "arrival": "2026-04-01T08:40:00+02:00",
            "departure": "2026-04-01T08:50:00+02:00",
            "wait_s": 0,
            "service_s": 600,
            "travel_time_s": 2400,
            "load_after": { "weight": 20 }
          },
          {
            "type": "job",
            "id": "delivery-1",
            "location": [4.7005, 50.8798],
            "arrival": "2026-04-01T09:50:00+02:00",
            "departure": "2026-04-01T09:55:00+02:00",
            "wait_s": 0,
            "service_s": 300,
            "travel_time_s": 3600,
            "load_after": { "weight": 30 }
          },
          {
            "type": "end",
            "location": [4.3517, 50.8503],
            "arrival": "2026-04-01T10:30:00+02:00"
          }
        ]
      }
    ],
    "unassigned": []
  }
  ```
</CodeGroup>

**Key differences:**

* `trips` → `routes`; `resource` → `vehicle` object `{ "type": "truck-1", "instance": 1 }`
* `visits` → `stops` (typed: `start`, `job`, `end`, etc.)
* V3 stops carry `type`, `id`, `arrival`, `departure`, `wait_s`, `service_s`, `travel_time_s`, `load_after` (named map)
* V3 routes use `distance_m` / `duration_s` (not bare `distance` / `duration`)
* `unserved` (string list) → `unassigned` (objects with `job_id` and `reasons[]`)
* New `summary` block with `jobs_assigned`/`jobs_unassigned`, `total_distance_m`, `total_duration_s`, `estimated_cost`, `elapsed_ms`, `iterations`
* Coordinates in response are bare `[longitude, latitude]` arrays

## V2 features not mapped via compat endpoint

When using the V2 endpoint (`/v2/vrp/sync/solve`), the following V2 fields are **silently dropped** during conversion:

* `resources[].tags` — V2 skill tags are not forwarded to the V3 solver
* `relations[].resource` — pinning a relation to a specific vehicle is ignored
* `windows[].hard` — soft time window flag has no V3 equivalent yet
* Per-visit `serviceTime`, `travelTime`, `distance` — not populated in the V2 response

## Feature parity

V3 currently implements a subset of V2's features. The rest are on the roadmap.

| Feature                               |  V2 |  V3 | Notes                                              |
| ------------------------------------- | :-: | :-: | -------------------------------------------------- |
| Capacity (single dimension)           |  ✅  |  ✅  | Named map e.g. `{ "weight": 100 }`                 |
| Time windows (hard, single)           |  ✅  |  ✅  |                                                    |
| Skills / tags                         |  ✅  |  ✅  |                                                    |
| Sequence / precedence                 |  ✅  |  ✅  | V3 type: `ordered` with `job_ids`                  |
| First-job constraint                  |  ✅  |  ✅  | V3: `ordered` with a single `job_ids` entry        |
| Vehicle range (max distance/duration) |  ✅  |  ✅  | `limits.max_distance_m`, `limits.max_drive_time_s` |
| Committed vehicle                     |  ✅  |  ✅  | `eligible_vehicles.allowed`                        |
| Custom distance matrix                |  ✅  |  ✅  | `options.runtime.matrix`                           |
| Auto distance matrix (Solvice Maps)   |  ✅  |  ✅  |                                                    |
| Multi-dimensional capacity            |  ✅  |  🔜 | Coming soon                                        |
| Multiple time windows per job         |  ✅  |  🔜 | Coming soon                                        |
| Driver breaks                         |  ✅  |  🔜 | Coming soon                                        |
| Job priority                          |  ✅  |  🔜 | Coming soon                                        |
| Soft time windows                     |  ✅  |  🔜 | Coming soon                                        |
| Skill levels / proficiency            |  ✅  |  🔜 | Coming soon                                        |
| Job relations (same route, etc.)      |  ✅  |  🔜 | Coming soon                                        |
| Break management                      |  ✅  |  🔜 | Coming soon                                        |
| Tag ranking                           |  ✅  |  🔜 | Coming soon                                        |
| Inherited location                    |  ✅  |  🔜 | Coming soon                                        |
| Pickup & delivery (shipments)         |  ✅  |  🔜 | Coming soon                                        |
| Workload balancing / fairness         |  ✅  |  🔜 | Coming soon                                        |
| Rules engine                          |  ✅  |  🔜 | Coming soon                                        |
| Multi-day planning                    |  ✅  |  🔜 | Coming soon                                        |
| Real-time re-optimization             |  —  |  🔜 | Coming soon                                        |
| SSE streaming progress                |  —  |  ✅  | New in V3                                          |
| Job proximity constraint              |  —  |  ✅  | New in V3                                          |

<Note>
  V3 is under active development. The V2 endpoint (`/v2/vrp/sync/solve`) remains available and internally maps to the V3 solver — you get V3's performance with the V2 API contract.
</Note>
