@solvice/routing 0.1.0-beta.1 → 0.16.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/v3.d.ts CHANGED
@@ -14,7 +14,7 @@ export interface paths {
14
14
  put?: never;
15
15
  /**
16
16
  * Evaluate an imported solution
17
- * @description Scores the `plan` you send against `problem` without searching for a better one. Returns the plan's cost, timing and loads, and lists each constraint violation on the stop or route where it occurs; `summary.score.violations` is 0 when there are none. Tasks that appear in no route are reported in `unassigned[]`. `problem` has the same shape as on `POST /v3/routing/solve`, and a solve response's `plan` can be sent as it stands.
17
+ * @description Scores the `plan` you send against `problem` without searching for a better one. Returns the plan's cost, timing and loads, and lists each constraint violation on the stop or route where it occurs; `summary.score.violation_count` is 0 when there are none. Tasks that appear in no route are reported in `unassigned[]`. `problem` has the same shape as on `POST /v3/routing/solve`, and a solve response's `plan` can be sent as it stands.
18
18
  */
19
19
  post: operations["evaluate"];
20
20
  delete?: never;
@@ -54,7 +54,7 @@ export interface paths {
54
54
  put?: never;
55
55
  /**
56
56
  * Suggest best insertions for the tasks outside the plan
57
- * @description Takes the same body as `POST /v3/routing/evaluate` (`problem` + committed `plan`), plus optional `options`. Every task of `problem` that is not in `plan` is a task to place: finds its feasible insertion positions and returns them as `insertions`, ranked by `delta.cost`, the change in the plan's cost in money. Each insertion lists the stops it adds (`placements`) and every plan route it changes, whole (`routes`): swap those routes into `plan` to apply it. An empty `insertions` carries a `reason_code` (`time_limit`, `candidates_exhausted` or `infeasible`; an open set). The committed plan is never modified. Limitation: suggest never opens a new reload trip on a multi-trip vehicle.
57
+ * @description Takes the same body as `POST /v3/routing/evaluate` (`problem` + committed `plan`), plus optional `options`. Every task of `problem` that is not in `plan` is a task to place: finds its feasible insertion positions and returns them as `insertions`, ranked by `delta.cost`, the change in the plan's cost in money. Each insertion lists the stops it adds (`placements`) and every plan route it changes, whole (`routes`): swap those routes into `plan` to apply it. An empty `insertions` carries a `reason` whose `code` is `time_limit`, `candidates_exhausted` or `infeasible` (an open set) and whose `message` says the same in English. The committed plan is never modified. Limitation: suggest never opens a new reload trip on a multi-trip vehicle.
58
58
  */
59
59
  post: operations["suggest"];
60
60
  delete?: never;
@@ -63,6 +63,66 @@ export interface paths {
63
63
  patch?: never;
64
64
  trace?: never;
65
65
  };
66
+ "/v3/routing/validate/evaluate": {
67
+ parameters: {
68
+ query?: never;
69
+ header?: never;
70
+ path?: never;
71
+ cookie?: never;
72
+ };
73
+ get?: never;
74
+ put?: never;
75
+ /**
76
+ * Check an evaluate request without running it
77
+ * @description Checks a `POST /v3/routing/evaluate` request without scoring it. It runs the checks `POST /v3/routing/evaluate` runs before it fetches travel times, and stops there: no travel times are fetched, nothing is searched, no solver slot is taken, and the call is not billed. The body is the body of `POST /v3/routing/evaluate`. A valid request returns `{"valid": true, "warnings": []}`; an invalid one returns the 400 (or 403) the real call would. Not covered, because the real call makes these checks only after it fetches travel times: coordinates that span more than one Maps region (a 400 on the real call), and the `plan` (that its routes and stops name vehicles, shifts, tasks and depots of `problem`, and that it imports; see the plan errors in the errors guide).
78
+ */
79
+ post: operations["validate_evaluate"];
80
+ delete?: never;
81
+ options?: never;
82
+ head?: never;
83
+ patch?: never;
84
+ trace?: never;
85
+ };
86
+ "/v3/routing/validate/solve": {
87
+ parameters: {
88
+ query?: never;
89
+ header?: never;
90
+ path?: never;
91
+ cookie?: never;
92
+ };
93
+ get?: never;
94
+ put?: never;
95
+ /**
96
+ * Check a solve request without running it
97
+ * @description Checks a `POST /v3/routing/solve` request without solving it. It runs the checks `POST /v3/routing/solve` runs before it fetches travel times, and stops there: no travel times are fetched, nothing is searched, no solver slot is taken, and the call is not billed. The body is the body of `POST /v3/routing/solve`. A valid request returns `{"valid": true, "warnings": []}`; an invalid one returns the 400 (or 403) the real call would. Not covered, because the real call makes these checks only after it fetches travel times: coordinates that span more than one Maps region (a 400 on the real call), and the warm-start `plan` (that its routes and stops name vehicles, shifts, tasks and depots of `problem`, and that it imports, its locked stops included; see the plan errors in the errors guide).
98
+ */
99
+ post: operations["validate_solve"];
100
+ delete?: never;
101
+ options?: never;
102
+ head?: never;
103
+ patch?: never;
104
+ trace?: never;
105
+ };
106
+ "/v3/routing/validate/suggest": {
107
+ parameters: {
108
+ query?: never;
109
+ header?: never;
110
+ path?: never;
111
+ cookie?: never;
112
+ };
113
+ get?: never;
114
+ put?: never;
115
+ /**
116
+ * Check a suggest request without running it
117
+ * @description Checks a `POST /v3/routing/suggest` request without searching. It runs the checks `POST /v3/routing/suggest` runs before it fetches travel times, and stops there: no travel times are fetched, nothing is searched, no solver slot is taken, and the call is not billed. The body is the body of `POST /v3/routing/suggest`. A valid request returns `{"valid": true, "warnings": []}`; an invalid one returns the 400 (or 403) the real call would. Not covered, because the real call makes these checks only after it fetches travel times: coordinates that span more than one Maps region (a 400 on the real call), and the `plan` beyond suggest's own rule that it leaves a task to place, which does run here (that its routes and stops name vehicles, shifts, tasks and depots of `problem`, and that it imports; see the plan errors in the errors guide).
118
+ */
119
+ post: operations["validate_suggest"];
120
+ delete?: never;
121
+ options?: never;
122
+ head?: never;
123
+ patch?: never;
124
+ trace?: never;
125
+ };
66
126
  }
67
127
  export type webhooks = Record<string, never>;
68
128
  export interface components {
@@ -90,16 +150,6 @@ export interface components {
90
150
  */
91
151
  vehicle: string;
92
152
  };
93
- /**
94
- * @description Named capacity/demand/load dimensions, e.g. `{"weight": 30, "volume": 2}`. Keys are user-chosen dimension names; values are integer quantities. Order-independent and self-documenting. In a request every value must be `>= 0` (a negative one is rejected with HTTP 400 `out_of_range`), and a request may use at most 4 distinct dimension names across jobs, shipments and vehicles (HTTP 400 `limit_exceeded` beyond that).
95
- * @example {
96
- * "volume": 2,
97
- * "weight": 20
98
- * }
99
- */
100
- BTreeMap: {
101
- [key: string]: number;
102
- };
103
153
  /**
104
154
  * @description A scheduled break within a shift. Tagged by `type`:
105
155
  *
@@ -109,11 +159,13 @@ export interface components {
109
159
  * - `fixed`: a hard off-duty interval from `from` to `to`.
110
160
  *
111
161
  * Breaks are injected between stops and appear in the response as `break`
112
- * stops.
162
+ * stops, carrying the break's `id` when it has one.
113
163
  *
114
- * **Not yet supported** — rejected with HTTP 400 `not_supported`: more than
115
- * one `windows` entry, a `location` on a `triggered` break, and
116
- * `resets_accumulator: false`.
164
+ * A `triggered` break always resets its accumulator after a qualifying break
165
+ * and is taken wherever the vehicle is: `resets_accumulator` and `location`
166
+ * do not exist on it. A `windowed` break takes exactly one `time_window` and
167
+ * is also taken wherever the vehicle is: a `location` on it is HTTP 400
168
+ * `not_supported`.
117
169
  *
118
170
  * There is no paid/unpaid cost accounting: a break's duration is never
119
171
  * separately priced, and no `paid` field exists on this schema — sending one
@@ -125,27 +177,60 @@ export interface components {
125
177
  * "type": "triggered"
126
178
  * }
127
179
  */
128
- Break: {
180
+ Break: components["schemas"]["BreakWindowed"] | components["schemas"]["BreakTriggered"] | components["schemas"]["BreakFixed"];
181
+ /**
182
+ * Fixed
183
+ * @description Mandatory off-duty interval at a fixed time. No service is scheduled
184
+ * inside it, but a drive already under way at `from` continues through
185
+ * it and counts in both `travel_s` and `break_s`.
186
+ */
187
+ BreakFixed: {
129
188
  /**
130
- * Format: int32
131
- * @description Break duration in seconds. Must be `> 0`.
189
+ * Format: date-time
190
+ * @description Start of the break (RFC 3339 instant, UTC offset required).
132
191
  */
133
- duration_s: number;
192
+ from: string;
134
193
  /**
135
- * @description Accepted and range-checked like any place, but it has no effect:
136
- * the break is scheduled wherever the vehicle is when it starts, and
137
- * the response's `break` stop carries no `location`. The coordinate
138
- * is still sent to the travel-time lookup.
194
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
195
+ * Echoed as `id` on the `break` stop that realises this break.
196
+ * @example lunch
139
197
  */
140
- location?: null | components["schemas"]["Place"];
141
- /** @enum {string} */
142
- type: "windowed";
198
+ id?: string | null;
199
+ /**
200
+ * Format: date-time
201
+ * @description End of the break (RFC 3339 instant, UTC offset required).
202
+ */
203
+ to: string;
204
+ /**
205
+ * @description Discriminator: always `fixed`. (enum property replaced by openapi-typescript)
206
+ * @enum {string}
207
+ */
208
+ type: "fixed";
209
+ };
210
+ /**
211
+ * @description The window a `windowed` break must start in. Always hard.
212
+ * @example {
213
+ * "from": "2026-07-01T12:00:00+02:00",
214
+ * "to": "2026-07-01T13:30:00+02:00"
215
+ * }
216
+ */
217
+ BreakTimeWindow: {
218
+ /**
219
+ * Format: date-time
220
+ * @description Earliest break start (RFC 3339 instant, UTC offset required).
221
+ */
222
+ from: string;
143
223
  /**
144
- * @description The window bounding the break's **start**. Exactly one entry; a
145
- * second one is rejected with HTTP 400 (`not_supported`).
224
+ * Format: date-time
225
+ * @description Latest break start (RFC 3339 instant, UTC offset required).
146
226
  */
147
- windows: components["schemas"]["BreakWindow"][];
148
- } | {
227
+ to: string;
228
+ };
229
+ /**
230
+ * Triggered
231
+ * @description A break taken once drive or duty time passes a threshold.
232
+ */
233
+ BreakTriggered: {
149
234
  /** @description What to accumulate: drive time or duty time. */
150
235
  after: components["schemas"]["TriggerAfter"];
151
236
  /**
@@ -153,15 +238,12 @@ export interface components {
153
238
  * @description Break duration in seconds. Must be `> 0`.
154
239
  */
155
240
  duration_s: number;
156
- /** @description Not supported yet: any value is rejected with HTTP 400. */
157
- location?: null | components["schemas"]["Place"];
158
241
  /**
159
- * @description Whether the accumulator resets after the break. Default `true` (the
160
- * EU-561 semantics; the accumulation window restarts after a qualifying
161
- * break). `false` is not supported yet and is rejected with HTTP 400.
162
- * @example true
242
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
243
+ * Echoed as `id` on the `break` stop that realises this break.
244
+ * @example lunch
163
245
  */
164
- resets_accumulator?: boolean | null;
246
+ id?: string | null;
165
247
  /**
166
248
  * Format: int64
167
249
  * @description Trigger threshold in seconds (strict `>` — the break fires when the
@@ -170,41 +252,54 @@ export interface components {
170
252
  * @example 14400
171
253
  */
172
254
  threshold_s: number;
173
- /** @enum {string} */
174
- type: "triggered";
175
- } | {
176
- /**
177
- * Format: date-time
178
- * @description Start of the break (RFC 3339 instant, UTC offset required).
179
- */
180
- from: string;
181
255
  /**
182
- * Format: date-time
183
- * @description End of the break (RFC 3339 instant, UTC offset required).
256
+ * @description Discriminator: always `triggered`. (enum property replaced by openapi-typescript)
257
+ * @enum {string}
184
258
  */
185
- to: string;
186
- /** @enum {string} */
187
- type: "fixed";
259
+ type: "triggered";
188
260
  };
189
261
  /**
190
- * @description The window a `windowed` break must start in. Always hard.
191
- * @example {
192
- * "from": "2026-07-01T12:00:00+02:00",
193
- * "to": "2026-07-01T13:30:00+02:00"
194
- * }
262
+ * Windowed
263
+ * @description A break that must start inside a time window.
195
264
  */
196
- BreakWindow: {
265
+ BreakWindowed: {
197
266
  /**
198
- * Format: date-time
199
- * @description Earliest break start (RFC 3339 instant, UTC offset required).
267
+ * Format: int32
268
+ * @description Break duration in seconds. Must be `> 0`.
200
269
  */
201
- from: string;
270
+ duration_s: number;
202
271
  /**
203
- * Format: date-time
204
- * @description Latest break start (RFC 3339 instant, UTC offset required).
272
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
273
+ * Echoed as `id` on the `break` stop that realises this break.
274
+ * @example lunch
205
275
  */
206
- to: string;
276
+ id?: string | null;
277
+ /**
278
+ * @description Not supported on V3: a windowed break is taken wherever the
279
+ * vehicle is when it starts, so a `location` here is rejected with
280
+ * HTTP 400 `not_supported`. Set only by the V2 compatibility mapper.
281
+ */
282
+ location?: null | components["schemas"]["Place"];
283
+ /** @description The window bounding the break's **start**. */
284
+ time_window: components["schemas"]["BreakTimeWindow"];
285
+ /**
286
+ * @description Discriminator: always `windowed`. (enum property replaced by openapi-typescript)
287
+ * @enum {string}
288
+ */
289
+ type: "windowed";
207
290
  };
291
+ /**
292
+ * @description The constraint a violation breaks or a reason names: one vocabulary for
293
+ * `routes[].violations[].code`, `routes[].stops[].violations[].code` and
294
+ * `unassigned[].reasons[].constraint`.
295
+ *
296
+ * New values may be added; clients must accept unknown values and handle
297
+ * them generically, for example by showing `message`.
298
+ *
299
+ * Known values: `unreachable`, `max_leg_travel`, `required_skills`, `serves_tags`, `capacity`, `time_window`, `eligible_vehicles`, `shift_end`, `max_distance`, `max_route_duration`, `max_stops`, `sequence`, `tag_order`, `shipment`, `break`, `multi_trip`, `same_vehicle`, `same_day`, `same_route`, `compatible_vehicles`, `synchronized`, `time_lag`, `all_or_none`, `period_limit`, `quota`, `unknown`. An open set: a later release may add values, so accept any string and handle the ones you know.
300
+ * @example capacity
301
+ */
302
+ ConstraintCode: string;
208
303
  /**
209
304
  * @description What running a vehicle costs, in the request's currency
210
305
  * (`objective.currency` is only a label). The same type at three levels:
@@ -218,22 +313,17 @@ export interface components {
218
313
  * Rates are rounded to the internal grid (1/100 000 of a currency unit per
219
314
  * second or per metre); a nonzero rate too small to represent is rejected.
220
315
  * Every value must be finite and `>= 0`.
316
+ *
317
+ * Lateness is not priced here: `objective.per_late_hour` (or a window's own
318
+ * `per_late_hour`) is the rate, because it softens a constraint rather than
319
+ * pricing a resource.
221
320
  * @example {
222
- * "fixed": 50,
321
+ * "per_route": 50,
223
322
  * "per_route_hour": 35,
224
323
  * "per_travel_km": 0.2
225
324
  * }
226
325
  */
227
326
  Costs: {
228
- /**
229
- * Format: double
230
- * @description Flat charge for each used shift (a route with at least one task),
231
- * reported in `score.components.fixed`. Default `0`. Pricing vehicles is
232
- * how the solver is made to use fewer of them: the higher it is, the
233
- * more travel it accepts to avoid opening another route.
234
- * @example 50
235
- */
236
- fixed?: number | null;
237
327
  /**
238
328
  * Format: double
239
329
  * @description Per hour a route finishes past its shift's `to` (possible only with
@@ -242,17 +332,28 @@ export interface components {
242
332
  * @example 0
243
333
  */
244
334
  per_overtime_hour?: number | null;
335
+ /**
336
+ * Format: double
337
+ * @description Flat charge for each used shift (a route with at least one task),
338
+ * reported in `score.components.routes`. Default `0`. Pricing vehicles is
339
+ * how the solver is made to use fewer of them: the higher it is, the
340
+ * more travel it accepts to avoid opening another route.
341
+ * @example 50
342
+ */
343
+ per_route?: number | null;
245
344
  /**
246
345
  * Format: double
247
346
  * @description Per hour of each route's wall-clock span (travel, service, waiting
248
- * and breaks), reported in `score.components.time`. Default **35**.
347
+ * and breaks), reported in `score.components.time`. Default **35** at objective
348
+ * level; a vehicle or shift value inherits the fleet value.
249
349
  * @example 35
250
350
  */
251
351
  per_route_hour?: number | null;
252
352
  /**
253
353
  * Format: double
254
354
  * @description Per kilometre driven, reported in `score.components.distance`.
255
- * Default **0.20**.
355
+ * Default **0.20** at objective level; a vehicle or shift value inherits the
356
+ * fleet value.
256
357
  * @example 0.2
257
358
  */
258
359
  per_travel_km?: number | null;
@@ -260,7 +361,8 @@ export interface components {
260
361
  * Format: double
261
362
  * @description Per hour spent waiting for a time window to open, reported in
262
363
  * `score.components.waiting`, on top of `per_route_hour` (the span
263
- * includes the wait). Default `0`.
364
+ * includes the wait). Idle before a windowed break's window opens is
365
+ * reported in `wait_s` but not charged here. Default `0`.
264
366
  * @example 0
265
367
  */
266
368
  per_wait_hour?: number | null;
@@ -268,7 +370,7 @@ export interface components {
268
370
  /**
269
371
  * @description A depot: a place a shift starts from, ends at, or reloads at mid-shift,
270
372
  * referenced by `id` from `shifts[].start`, `shifts[].end` and
271
- * `shifts[].reloads`. Each depot keeps its own handling time and visit cost.
373
+ * `shifts[].reloads`. Each depot keeps its own handling time and reload cost.
272
374
  * @example {
273
375
  * "id": "gent",
274
376
  * "location": [
@@ -279,13 +381,20 @@ export interface components {
279
381
  * }
280
382
  */
281
383
  Depot: {
384
+ /**
385
+ * @description Depot id: 1 to 128 characters, unique across `depots[]`.
386
+ * @example gent
387
+ */
388
+ id: string;
389
+ /** @description Where the depot is. */
390
+ location: components["schemas"]["Place"];
282
391
  /**
283
392
  * Format: double
284
393
  * @description Money charged once per reload visit, in the objective's currency.
285
394
  * Default 0; at most `1e9`. A shift that only starts or ends here is not
286
395
  * charged.
287
396
  *
288
- * Set this when a reload has a real per-visit price the travel terms
397
+ * Set this when a reload has a real per-reload price the travel terms
289
398
  * cannot see — typically the driver labour for the unload itself
290
399
  * (`service_duration_s` × the hourly rate). Without it, a reload that
291
400
  * consumes only *slack* is free in the objective: it adds no route
@@ -294,14 +403,7 @@ export interface components {
294
403
  * the vehicle at a depot for no capacity benefit.
295
404
  * @example 38.66
296
405
  */
297
- cost_per_visit?: number | null;
298
- /**
299
- * @description Depot id: 1 to 128 characters, unique across `depots[]`.
300
- * @example gent
301
- */
302
- id: string;
303
- /** @description Where the depot is. */
304
- location: components["schemas"]["Place"];
406
+ per_reload?: number | null;
305
407
  /**
306
408
  * Format: int32
307
409
  * @description Handling time in seconds per visit: the load before a shift that starts
@@ -314,27 +416,6 @@ export interface components {
314
416
  */
315
417
  service_duration_s?: number | null;
316
418
  };
317
- /**
318
- * @description Hard vehicle eligibility: whitelist or blacklist (mutually exclusive).
319
- * @example {
320
- * "allowed": [
321
- * "v1",
322
- * "v2"
323
- * ]
324
- * }
325
- */
326
- Eligibility: {
327
- /**
328
- * @description Hard whitelist of vehicle ids. Omit = all vehicles allowed. An empty
329
- * list, or an id that names no vehicle, is rejected with HTTP 400.
330
- */
331
- allowed?: string[] | null;
332
- /**
333
- * @description Hard blacklist of vehicle ids. Mutually exclusive with `allowed`. An
334
- * id that names no vehicle is rejected with HTTP 400.
335
- */
336
- excluded?: string[] | null;
337
- };
338
419
  /**
339
420
  * @description Error body of every `/v3/routing/*` endpoint.
340
421
  *
@@ -360,7 +441,7 @@ export interface components {
360
441
  /** @description What kind of failure this is. One value per HTTP status class. */
361
442
  code: components["schemas"]["ErrorCode"];
362
443
  /** @description One entry per problem found in the request. Empty for non-input errors. */
363
- errors?: components["schemas"]["ErrorItem"][];
444
+ errors?: components["schemas"]["RequestIssue"][];
364
445
  /**
365
446
  * @description Human-readable summary. With exactly one item it is that item's
366
447
  * message; with several, `"{n} problems in request"` (at most 100 items
@@ -378,39 +459,17 @@ export interface components {
378
459
  };
379
460
  /**
380
461
  * @description The top-level `code` of an error body.
381
- * @enum {string}
462
+ *
463
+ * Known values: `invalid_request`, `feature_not_enabled`, `payload_too_large`, `unsupported_media_type`, `internal`, `travel_provider_error`, `overloaded`. An open set: a later release may add values, so accept any string and handle the ones you know.
382
464
  */
383
- ErrorCode: "invalid_request" | "feature_not_enabled" | "payload_too_large" | "unsupported_media_type" | "internal" | "matrix_provider_error" | "overloaded";
384
- /** @description One problem in a request. */
385
- ErrorItem: {
386
- /**
387
- * Format: int64
388
- * @description `limit_exceeded` only: the count this request has.
389
- */
390
- actual?: number | null;
391
- /** @description What is wrong. */
392
- code: components["schemas"]["ErrorItemCode"];
393
- /**
394
- * Format: int64
395
- * @description `limit_exceeded` only: the published cap.
396
- */
397
- limit?: number | null;
398
- /** @description Human-readable description. */
399
- message: string;
400
- /**
401
- * @description RFC 6901 JSON Pointer into the request body, when the problem has a
402
- * location. It is relative to the root of the body, so a field of the
403
- * problem reads `/problem/...` (e.g.
404
- * `"/problem/vehicles/0/shifts/0/from"`).
405
- */
406
- pointer?: string | null;
407
- };
465
+ ErrorCode: string;
408
466
  /**
409
467
  * @description The `code` of one `errors[]` item. Clients should accept values they do
410
468
  * not know yet.
411
- * @enum {string}
469
+ *
470
+ * Known values: `invalid_json`, `invalid_type`, `unknown_field`, `missing_field`, `invalid_value`, `not_supported`, `out_of_range`, `duplicate_id`, `unknown_reference`, `conflicting_fields`, `limit_exceeded`. An open set: a later release may add values, so accept any string and handle the ones you know.
412
471
  */
413
- ErrorItemCode: "invalid_json" | "invalid_type" | "unknown_field" | "missing_field" | "invalid_value" | "not_supported" | "out_of_range" | "duplicate_id" | "unknown_reference" | "conflicting_fields" | "limit_exceeded";
472
+ ErrorItemCode: string;
414
473
  /**
415
474
  * @description Request body for `POST /v3/routing/evaluate`.
416
475
  *
@@ -441,7 +500,7 @@ export interface components {
441
500
  * 3.725,
442
501
  * 51.05
443
502
  * ],
444
- * "pickup": {
503
+ * "pickup_load": {
445
504
  * "weight": 10
446
505
  * },
447
506
  * "service_duration_s": 300
@@ -481,37 +540,45 @@ export interface components {
481
540
  /** @description The plan to score. */
482
541
  plan: components["schemas"]["Plan"];
483
542
  /** @description Problem definition — identical to `POST /v3/routing/solve`. */
484
- problem: components["schemas"]["ProblemInput"];
543
+ problem: components["schemas"]["Problem"];
485
544
  };
486
545
  /**
487
546
  * @description Keep geographically clustered tasks consecutive in a route.
488
547
  *
489
548
  * Two tasks are in the same **group** when they lie within `radius_m` of
490
- * each other. The solver adds `cost_per_reentry` to the objective each time
491
- * a route leaves a group and comes back — minimising the "passing-waypoint"
492
- * / area re-entry count last-mile fleets track. Presence of this object
493
- * enables the feature; omit it to disable.
549
+ * each other. The solver adds `per_entry` to the objective each time a
550
+ * route enters a group from a job outside it, the first entry included;
551
+ * entering from the shift's start or from a reload is free. Keeping each
552
+ * group in one visit minimises the "passing-waypoint" / area re-entry count
553
+ * last-mile fleets track. Presence of this object enables the feature; omit
554
+ * it to disable.
494
555
  * @example {
495
- * "cost_per_reentry": 0.5,
496
- * "distance": "straight_line",
556
+ * "distance_metric": "straight_line",
557
+ * "per_entry": 0.5,
497
558
  * "radius_m": 180
498
559
  * }
499
560
  */
500
561
  Grouping: {
562
+ /**
563
+ * @description How neighbour distance is measured. Default `"straight_line"`.
564
+ * @default straight_line
565
+ */
566
+ distance_metric?: null | components["schemas"]["GroupingDistance"];
501
567
  /**
502
568
  * Format: double
503
- * @description Cost added to the objective per group re-entry, in the objective's
504
- * currency. At most 1000 currency units: a larger value is rejected with
505
- * HTTP 400. Higher keeps clusters together more aggressively at the
506
- * expense of total travel.
569
+ * @description Cost added to the objective on every entry into a group from a job
570
+ * outside it (a job that is not within `radius_m` of the entered one),
571
+ * the first entry included, in the objective's currency. Entry from the
572
+ * shift's start or from a reload is free. At most 1000 currency units: a
573
+ * larger value is rejected with HTTP 400. Higher keeps clusters together
574
+ * more aggressively at the expense of total travel.
507
575
  * @example 0.5
508
576
  */
509
- cost_per_reentry: number;
510
- /** @description How neighbour distance is measured. Default `"straight_line"`. */
511
- distance?: null | components["schemas"]["GroupingDistance"];
577
+ per_entry: number;
512
578
  /**
513
579
  * Format: int32
514
580
  * @description Radius defining a group, in metres. Default `180`. Must be `> 0`.
581
+ * @default 180
515
582
  * @example 180
516
583
  */
517
584
  radius_m?: number | null;
@@ -530,14 +597,14 @@ export interface components {
530
597
  * @example {
531
598
  * "cost": 12.4,
532
599
  * "distance_m": 2400,
533
- * "duration_s": 240
600
+ * "travel_s": 240
534
601
  * }
535
602
  */
536
603
  InsertionDelta: {
537
604
  /**
538
605
  * Format: double
539
606
  * @description Change in the score's `cost`, in the request's currency. Negative when
540
- * serving a task saves more `drop_fee` than it costs to route.
607
+ * serving a task saves more `drop_cost` than it costs to route.
541
608
  * @example 12.4
542
609
  */
543
610
  cost: number;
@@ -553,7 +620,7 @@ export interface components {
553
620
  * seconds.
554
621
  * @example 240
555
622
  */
556
- duration_s: number;
623
+ travel_s: number;
557
624
  };
558
625
  /**
559
626
  * @description One feasible way to place the whole unit.
@@ -561,7 +628,7 @@ export interface components {
561
628
  * "delta": {
562
629
  * "cost": 12.4,
563
630
  * "distance_m": 2400,
564
- * "duration_s": 240
631
+ * "travel_s": 240
565
632
  * },
566
633
  * "placements": [
567
634
  * {
@@ -612,69 +679,180 @@ export interface components {
612
679
  routes: components["schemas"]["PlanRoute"][];
613
680
  };
614
681
  /**
615
- * @description Ranked insertion suggestions for a single unit.
682
+ * @description A single-stop visit: one location served once (the `jobs[]` entry type).
683
+ * For a pickup bound to a delivery on the same vehicle, use `shipments[]`.
616
684
  * @example {
617
- * "insertions": [
685
+ * "id": "job-1",
686
+ * "location": [
687
+ * 3.725,
688
+ * 51.05
689
+ * ],
690
+ * "pickup_load": {
691
+ * "weight": 20
692
+ * },
693
+ * "required_skills": [
618
694
  * {
619
- * "delta": {
620
- * "cost": 12.4,
621
- * "distance_m": 2400,
622
- * "duration_s": 240
623
- * },
624
- * "placements": [
625
- * {
626
- * "arrival": "2026-07-01T09:30:00+02:00",
627
- * "id": "job-2",
628
- * "latest_arrival": "2026-07-01T10:15:00+02:00",
629
- * "shift": "mon",
630
- * "type": "job",
631
- * "vehicle": "v1"
632
- * }
633
- * ],
634
- * "routes": [
635
- * {
636
- * "shift": "mon",
637
- * "stops": [
638
- * {
639
- * "id": "job-1",
640
- * "type": "job"
641
- * },
642
- * {
643
- * "id": "job-2",
644
- * "type": "job"
645
- * }
646
- * ],
647
- * "vehicle": "v1"
648
- * }
649
- * ]
695
+ * "name": "fridge"
650
696
  * }
651
697
  * ],
652
- * "job_id": "job-2"
653
- * }
698
+ * "service_duration_s": 300,
699
+ * "time_windows": [
700
+ * {
701
+ * "from": "2026-07-01T09:00:00+02:00",
702
+ * "to": "2026-07-01T12:00:00+02:00"
703
+ * }
704
+ * ]
705
+ * }
654
706
  */
655
- JobSuggestions: {
707
+ Job: {
656
708
  /**
657
- * @description Ranked feasible insertions, lowest `delta.cost` first. Empty if none
658
- * was found; `reason_code` then says why. Known limitation: suggest
659
- * never opens a **new reload trip** on a multi-trip vehicle.
709
+ * @description Absolute price of serving this task on a given vehicle, in the
710
+ * objective's currency. Charged once, when that vehicle (on any of its
711
+ * shifts) serves the task; unlisted vehicles cost nothing. Unlike
712
+ * `preferences`, which charges the vehicles that did NOT get the task,
713
+ * this prices the vehicle that did, so a task rated badly everywhere is
714
+ * the first one dropped when capacity runs out. It lives in the cost tier,
715
+ * below `priority`, and adds to `preferences`, `drop_cost` and travel.
716
+ * Not applied by decomposition: a problem that sets it solves monolithically.
660
717
  */
661
- insertions: components["schemas"]["InsertionOption"][];
718
+ assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
662
719
  /**
663
- * @description The unit's lead: its first member in placement order. That is the
664
- * visit, the shipment, the first stop of a `sequence` chain in the
665
- * unit, or else the member that comes first in problem order (`jobs`,
666
- * then `shipments`).
667
- * @example job-2
720
+ * @description Quantity delivered at this visit: comes off the vehicle here, having
721
+ * been loaded at a depot. Direction is carried by the field itself, never
722
+ * by sign — `delivery_load` values are non-negative magnitudes, like `pickup_load`.
723
+ *
724
+ * Unlike a shipment, nothing is picked up for it at another stop: the
725
+ * goods are assumed already aboard from a depot, so the vehicle departs
726
+ * its trip carrying the sum of the trip's `delivery_load` quantities.
727
+ *
728
+ * Absent or empty means no delivery at this visit.
668
729
  */
669
- job_id: string;
730
+ delivery_load?: null | components["schemas"]["Quantities"];
670
731
  /**
671
- * @description `reason_code` as an English sentence, for people and logs; present
672
- * exactly when `reason_code` is. Do not parse the text.
673
- * @example No feasible insertion position found
732
+ * Format: double
733
+ * @description Drop **price** — what leaving this task unserved costs you, in the same
734
+ * currency as `objective.costs`, and the only way to make a task
735
+ * droppable. Tasks without a `drop_cost` must be served.
736
+ *
737
+ * This is money, not a priority: it enters the same cost the solver
738
+ * minimises, so the task is served only while serving it costs less than
739
+ * dropping it. Drop costs the plan chose to pay are reported in
740
+ * `score.components.drop_costs` and summed into `score.cost`.
741
+ *
742
+ * On a shipment the drop cost applies to the pair, charged once.
743
+ *
744
+ * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
745
+ * is rejected with HTTP 400 (`conflicting_fields`).
746
+ * @example 25
747
+ */
748
+ drop_cost?: number | null;
749
+ /**
750
+ * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
751
+ * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
752
+ * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
753
+ */
754
+ eligible_vehicles?: null | components["schemas"]["VehicleEligibility"];
755
+ /**
756
+ * @description Job id: 1 to 128 characters, unique across `jobs` + `shipments`.
757
+ * @example job-1
758
+ */
759
+ id: string;
760
+ /**
761
+ * @description Where this visit happens. Omit for a "virtual" (location-less) job:
762
+ * it still has service duration, time windows, load, and skills, but
763
+ * requires no travel — the vehicle's position doesn't change when it
764
+ * serves one. Virtual and located jobs may be mixed freely in the same
765
+ * request and route. A virtual job's stop in the solution response
766
+ * reports the resolved location of its nearest real (located)
767
+ * neighbor in the route — the predecessor when there is one, otherwise
768
+ * the successor — so it is `null` only on a route that has no located
769
+ * stop at all (an all-virtual route on an open-start/open-end shift).
770
+ * A shipment's legs still require a `location`.
771
+ */
772
+ location?: null | components["schemas"]["Place"];
773
+ /**
774
+ * @description Quantity picked up at this visit: goes onto the vehicle here and stays
775
+ * aboard until the route ends or reloads. Non-negative magnitudes per
776
+ * named dimension. A swap that collects one quantity and drops off
777
+ * another at the same address is one job with both `pickup_load` and
778
+ * `delivery_load`.
779
+ */
780
+ pickup_load?: null | components["schemas"]["Quantities"];
781
+ /**
782
+ * @description Soft vehicle affinity preferences, priced. Each entry is independent:
783
+ * a job listing several preferred vehicles it doesn't get pays each
784
+ * one's `violation_cost` (compounding, the same rule as a vehicle's
785
+ * `preferred_tags`).
786
+ */
787
+ preferences?: components["schemas"]["VehiclePreference"][] | null;
788
+ /**
789
+ * Format: int32
790
+ * @description Importance of a must-serve task when not all of them fit: the solver
791
+ * maximises the summed `priority` of served tasks before any cost. `>= 1`,
792
+ * default `1` (maximise the count). A rank, not money — it never makes a
793
+ * task droppable; use `drop_cost` for that. Both set is a 400.
794
+ * @example 3
795
+ */
796
+ priority?: number | null;
797
+ /**
798
+ * @description Hard skill requirements — the assigned vehicle must provide every one,
799
+ * at or above each requirement's `min_level`. A request may use at most
800
+ * 256 distinct `(name, min_level)` pairs across all jobs and shipments
801
+ * (HTTP 400 `limit_exceeded` beyond that).
802
+ */
803
+ required_skills?: components["schemas"]["SkillRequirement"][] | null;
804
+ /**
805
+ * Format: int32
806
+ * @description On-site service time paid per job (seconds).
807
+ *
808
+ * This is the nominal figure. The serving vehicle's `service_factor`
809
+ * scales it — the time actually scheduled is
810
+ * `service_duration_s / service_factor` — so the solution's
811
+ * `stops[].service_s` may differ from what you sent here. Default `0`;
812
+ * a negative value is rejected with HTTP 400.
813
+ * @example 300
674
814
  */
675
- reason?: string | null;
676
- /** @description Why `insertions` is empty; absent otherwise. Branch on this. */
677
- reason_code?: null | components["schemas"]["SuggestReasonCode"];
815
+ service_duration_s?: number | null;
816
+ /**
817
+ * @description Per-vehicle work-rate factors for this task's `service_duration_s`,
818
+ * which is DIVIDED by the factor (above `1` = faster). Each multiplies
819
+ * the serving vehicle's rate (the shift's `service_factor` if set, else
820
+ * the vehicle's): effective service time = `service_duration_s /
821
+ * (shift_or_vehicle_factor * factor)`. On a shipment the factor scales
822
+ * both legs. A vehicle not listed works at its own rate.
823
+ */
824
+ service_factors?: components["schemas"]["ServiceFactor"][] | null;
825
+ /**
826
+ * Format: int32
827
+ * @description Setup time paid once on arrival at a new location (seconds),
828
+ * distinct from `service_duration_s`. Skipped when the immediate real
829
+ * predecessor in the route already sits at this location — co-located
830
+ * stops share one setup.
831
+ *
832
+ * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
833
+ * overhead (parking, walking to the door), not the work itself.
834
+ * Default `0`; a negative value is rejected with HTTP 400.
835
+ * @example 60
836
+ */
837
+ setup_duration_s?: number | null;
838
+ /**
839
+ * @description Free-form task labels (zones/territories, relation labels).
840
+ * Used for `tag`/relation resolution and, when a shift scopes itself via
841
+ * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
842
+ * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
843
+ * `required_skills`, which requires ALL. Not capability matching on its own.
844
+ * A request may carry at most 256 distinct tags across all jobs and
845
+ * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
846
+ * lists do not count.
847
+ */
848
+ tags?: string[] | null;
849
+ /**
850
+ * @description Soft target for this task, measured at its arrival (default) or
851
+ * departure. On a shipment it is measured on the **delivery** leg.
852
+ */
853
+ target?: null | components["schemas"]["Target"];
854
+ /** @description Time windows for this visit. */
855
+ time_windows?: components["schemas"]["TimeWindow"][] | null;
678
856
  };
679
857
  /**
680
858
  * @description Which road-network data prices travel times and distances.
@@ -699,8 +877,8 @@ export interface components {
699
877
  * (the summed `priority` of the required tasks left unassigned is
700
878
  * minimised), then **minimise cost** — the `costs` rates plus every priced
701
879
  * preference, reported as `score.cost`. There is no separate vehicle-count
702
- * step: to use fewer vehicles, price them with `costs.fixed` or
703
- * `vehicles[].costs.fixed`.
880
+ * step: to use fewer vehicles, price them with `costs.per_route` or
881
+ * `vehicles[].costs.per_route`.
704
882
  * @example {
705
883
  * "costs": {
706
884
  * "per_route_hour": 35,
@@ -724,21 +902,6 @@ export interface components {
724
902
  currency?: string | null;
725
903
  /** @description Job-proximity cluster cohesion. See the `Grouping` schema. */
726
904
  grouping?: null | components["schemas"]["Grouping"];
727
- /**
728
- * Format: double
729
- * @description Flat charge, in the objective's currency, for serving a task on a day
730
- * other than its `preferred_date`.
731
- *
732
- * Applied once per task whose `preferred_date` resolves to a different
733
- * calendar day (in its own offset) than the shift serving it; tasks without a `preferred_date`
734
- * are never charged. Unset or `0.0` disables the preference entirely,
735
- * which also makes every `preferred_date` in the request inert.
736
- *
737
- * Part of `score.cost`, so it trades off against travel and vehicle
738
- * cost but never against serving a required task.
739
- * @example 50
740
- */
741
- non_preferred_date_cost?: number | null;
742
905
  /**
743
906
  * Format: double
744
907
  * @description Cost per hour of lateness: the default rate for every task window
@@ -747,7 +910,7 @@ export interface components {
747
910
  * lateness and hard windows read opposite ways, and lateness is never
748
911
  * free). There is no earliness rate. It prices task windows only: a
749
912
  * shift's `to` (plus `max_overtime_s` when set) stays a hard limit.
750
- * Setting it `> 0` alongside a nonzero `time_windows[].cost` anywhere in
913
+ * Setting it `> 0` alongside a nonzero `time_windows[].choice_cost` anywhere in
751
914
  * the request is rejected with HTTP 400.
752
915
  * @example 60
753
916
  */
@@ -755,50 +918,6 @@ export interface components {
755
918
  /** @description Spreads work across vehicles. See the `WorkloadShare` schema. */
756
919
  workload_share?: null | components["schemas"]["WorkloadShare"];
757
920
  };
758
- /**
759
- * @description The 200 body of solve, evaluate and suggest: the call's result, or with
760
- * `?validate_only=true` the validation verdict (`ValidateOnlyResponse`).
761
- */
762
- OrValidateOnly_SolveResponse: {
763
- /**
764
- * @description The plan these routes follow, in the request's vocabulary: valid input
765
- * to evaluate, suggest or a warm-started solve as it stands.
766
- */
767
- plan: components["schemas"]["Plan"];
768
- /** @description One entry per non-empty route. */
769
- routes: components["schemas"]["Route"][];
770
- /** @description Aggregate statistics for the solve run. */
771
- summary: components["schemas"]["Summary"];
772
- /** @description Tasks that could not be feasibly assigned. */
773
- unassigned: components["schemas"]["Unassigned"][];
774
- } | components["schemas"]["ValidateOnlyResponse"];
775
- /**
776
- * @description The 200 body of solve, evaluate and suggest: the call's result, or with
777
- * `?validate_only=true` the validation verdict (`ValidateOnlyResponse`).
778
- */
779
- OrValidateOnly_SuggestResponse: {
780
- /**
781
- * Format: int64
782
- * @description Wall-clock time taken by the request, in milliseconds.
783
- * @example 8
784
- */
785
- elapsed_ms: number;
786
- /**
787
- * @description One entry per unit of tasks outside `plan`, in problem order (jobs,
788
- * then shipments; a relation group sorts at its first-listed member).
789
- */
790
- suggestions: components["schemas"]["JobSuggestions"][];
791
- /**
792
- * @description `true` when `options.time_limit_s` cut the search short, or a
793
- * multi-member unit came back empty after the search had discarded
794
- * candidates (an inconclusive "not found"; its `reason_code` is
795
- * `candidates_exhausted`). Lists may then be incomplete or missing the
796
- * best insertion. A single visit's only level is never pruned, so its
797
- * empty list is proof of infeasibility unless the budget cut it, and its
798
- * `reason_code` is then `time_limit`.
799
- */
800
- truncated?: boolean;
801
- } | components["schemas"]["ValidateOnlyResponse"];
802
921
  /**
803
922
  * @description The recurrence of a period limit (`limits.periods[].every`).
804
923
  * @enum {string}
@@ -809,8 +928,8 @@ export interface components {
809
928
  * Set exactly one of `every`, or `from` and `to`; and at least one maximum.
810
929
  * @example {
811
930
  * "every": "week",
812
- * "max_duration_s": 144000,
813
- * "max_tasks": 40
931
+ * "max_route_duration_s": 144000,
932
+ * "max_stops": 40
814
933
  * }
815
934
  */
816
935
  PeriodLimit: {
@@ -832,26 +951,27 @@ export interface components {
832
951
  max_distance_m?: number | null;
833
952
  /**
834
953
  * Format: int64
835
- * @description Hard cap on the summed route span of the period's shifts, measured as
836
- * for `max_route_duration_s`, in seconds. An unused shift adds nothing.
837
- * Must be `>= 0`.
954
+ * @description Hard cap on the summed route span of the period's shifts, measured as a
955
+ * shift's `max_route_duration_s` is, in seconds. An unused shift adds
956
+ * nothing. Must be `>= 0`.
838
957
  * @example 144000
839
958
  */
840
- max_duration_s?: number | null;
959
+ max_route_duration_s?: number | null;
841
960
  /**
842
961
  * Format: int32
843
- * @description Hard cap on served stops, counted as a shift's `max_tasks` counts
844
- * them: a job is one stop, a shipment two (pickup and delivery).
962
+ * @description Hard cap on served stops across the period's shifts; a job counts as
963
+ * one stop. Start, end, break and reload stops in `routes[].stops` do not
964
+ * count; a shipment counts as two stops.
845
965
  * @example 40
846
966
  */
847
- max_tasks?: number | null;
967
+ max_stops?: number | null;
848
968
  /**
849
969
  * Format: date-time
850
970
  * @description End of one explicit period (RFC 3339, UTC offset required, exclusive), with `from`.
851
971
  * @example 2026-10-12T00:00:00+02:00
852
972
  */
853
973
  to?: string | null;
854
- };
974
+ } & (unknown | unknown);
855
975
  /**
856
976
  * @description A place: a coordinate `[longitude, latitude]` in GeoJSON order — exactly two numbers. Tasks at the same coordinate are treated as one location. Longitude must lie in `[-180, 180]` and latitude in `[-90, 90]` (HTTP 400 `out_of_range` otherwise), and `[0, 0]` is rejected with HTTP 400 `invalid_value` as a missing-GPS placeholder.
857
977
  * @example [
@@ -949,44 +1069,77 @@ export interface components {
949
1069
  * "type": "pickup"
950
1070
  * }
951
1071
  */
952
- PlanStop: {
1072
+ PlanStop: components["schemas"]["PlanStopJob"] | components["schemas"]["PlanStopPickup"] | components["schemas"]["PlanStopDelivery"] | components["schemas"]["PlanStopReload"];
1073
+ /**
1074
+ * PlanStopDelivery
1075
+ * @description A shipment's delivery leg.
1076
+ */
1077
+ PlanStopDelivery: {
1078
+ /**
1079
+ * @description The leg's stop id: its own `id`, else `{shipment}:delivery`.
1080
+ * @example parts-9:delivery
1081
+ */
1082
+ id: string;
1083
+ /**
1084
+ * @description Discriminator: always `delivery`. (enum property replaced by openapi-typescript)
1085
+ * @enum {string}
1086
+ */
1087
+ type: "delivery";
1088
+ };
1089
+ /**
1090
+ * PlanStopJob
1091
+ * @description A job, by its id.
1092
+ */
1093
+ PlanStopJob: {
953
1094
  /**
954
1095
  * @description Job id.
955
1096
  * @example boiler-17
956
1097
  */
957
1098
  id: string;
958
- /** @enum {string} */
1099
+ /**
1100
+ * @description Discriminator: always `job`. (enum property replaced by openapi-typescript)
1101
+ * @enum {string}
1102
+ */
959
1103
  type: "job";
960
- } | {
1104
+ };
1105
+ /**
1106
+ * PlanStopPickup
1107
+ * @description A shipment's pickup leg.
1108
+ */
1109
+ PlanStopPickup: {
961
1110
  /**
962
1111
  * @description The leg's stop id: its own `id`, else `{shipment}:pickup`.
963
1112
  * @example parts-9:pickup
964
1113
  */
965
1114
  id: string;
966
- /** @enum {string} */
967
- type: "pickup";
968
- } | {
969
1115
  /**
970
- * @description The leg's stop id: its own `id`, else `{shipment}:delivery`.
971
- * @example parts-9:delivery
1116
+ * @description Discriminator: always `pickup`. (enum property replaced by openapi-typescript)
1117
+ * @enum {string}
972
1118
  */
973
- id: string;
974
- /** @enum {string} */
975
- type: "delivery";
976
- } | {
1119
+ type: "pickup";
1120
+ };
1121
+ /**
1122
+ * PlanStopReload
1123
+ * @description A reload at a depot: the next trip starts there.
1124
+ */
1125
+ PlanStopReload: {
977
1126
  /**
978
1127
  * @description A depot id from the shift's `reloads`.
979
1128
  * @example gent
980
1129
  */
981
1130
  depot: string;
982
- /** @enum {string} */
1131
+ /**
1132
+ * @description Discriminator: always `reload`. (enum property replaced by openapi-typescript)
1133
+ * @enum {string}
1134
+ */
983
1135
  type: "reload";
984
1136
  };
985
1137
  /**
986
1138
  * @description The `type` of a plan stop.
987
- * @enum {string}
1139
+ *
1140
+ * Known values: `job`, `pickup`, `delivery`, `reload`. An open set: a later release may add values, so accept any string and handle the ones you know.
988
1141
  */
989
- PlanStopType: "job" | "pickup" | "delivery" | "reload";
1142
+ PlanStopType: string;
990
1143
  /**
991
1144
  * @description How much road detail `routes[].polyline` carries.
992
1145
  *
@@ -1006,28 +1159,6 @@ export interface components {
1006
1159
  * @enum {string}
1007
1160
  */
1008
1161
  PolylineDetail: "simplified" | "full";
1009
- /**
1010
- * @description A soft vehicle affinity preference, priced.
1011
- * @example {
1012
- * "vehicle": "v1",
1013
- * "violation_cost": 50
1014
- * }
1015
- */
1016
- Preference: {
1017
- /**
1018
- * @description Preferred vehicle id. An id that names no vehicle, or a vehicle listed
1019
- * twice in one task's `preferences`, is rejected with HTTP 400.
1020
- * @example v1
1021
- */
1022
- vehicle: string;
1023
- /**
1024
- * Format: double
1025
- * @description Cost, in the objective's currency, incurred when a different vehicle
1026
- * serves the job. Must be finite and `>= 0`.
1027
- * @example 50
1028
- */
1029
- violation_cost: number;
1030
- };
1031
1162
  /**
1032
1163
  * @description The problem part of every V3 request body.
1033
1164
  * @example {
@@ -1047,7 +1178,7 @@ export interface components {
1047
1178
  * 3.725,
1048
1179
  * 51.05
1049
1180
  * ],
1050
- * "pickup": {
1181
+ * "pickup_load": {
1051
1182
  * "weight": 20
1052
1183
  * },
1053
1184
  * "service_duration_s": 300
@@ -1076,19 +1207,19 @@ export interface components {
1076
1207
  * ]
1077
1208
  * }
1078
1209
  */
1079
- ProblemInput: {
1210
+ Problem: {
1080
1211
  /** @description Depots that shifts start from, end at, or reload at, by id. */
1081
1212
  depots?: components["schemas"]["Depot"][];
1082
1213
  /**
1083
1214
  * @description Single-stop visits to serve. At most 10,000 tasks per request, `jobs`
1084
1215
  * and `shipments` combined (HTTP 400 `limit_exceeded` beyond that).
1085
1216
  */
1086
- jobs?: components["schemas"]["Visit"][];
1217
+ jobs?: components["schemas"]["Job"][];
1087
1218
  /** @description Objective configuration. */
1088
1219
  objective?: null | components["schemas"]["Objective"];
1089
1220
  /** @description Stop caps shared by a set of vehicles. At most 65,535. */
1090
1221
  quotas?: components["schemas"]["Quota"][];
1091
- /** @description Ordering, grouping, and synchronization constraints. */
1222
+ /** @description Ordering, co-assignment and synchronization constraints. */
1092
1223
  relations?: components["schemas"]["Relation"][] | null;
1093
1224
  /**
1094
1225
  * @description Bound pickup→delivery shipments to serve. Counts toward the same
@@ -1107,21 +1238,39 @@ export interface components {
1107
1238
  */
1108
1239
  Profile: "car" | "truck" | "bike";
1109
1240
  /**
1110
- * @description A hard cap on how many stops of `job_ids` the `vehicles` serve together
1241
+ * @description Named capacity/demand/load dimensions, e.g. `{"weight": 30, "volume": 2}`. Keys are user-chosen dimension names; values are integer quantities. Order-independent and self-documenting. In a request every value must be `>= 0` (a negative one is rejected with HTTP 400 `out_of_range`), and a request may use at most 4 distinct dimension names across jobs, shipments and vehicles (HTTP 400 `limit_exceeded` beyond that).
1242
+ * @example {
1243
+ * "volume": 2,
1244
+ * "weight": 20
1245
+ * }
1246
+ */
1247
+ Quantities: {
1248
+ [key: string]: number;
1249
+ };
1250
+ /**
1251
+ * @description The unit of a violation's `excess` or a relaxation's `amount`.
1252
+ *
1253
+ * Known values: `s`, `m`, `load`, `stops`. An open set: a later release may add values, so accept any string and handle the ones you know.
1254
+ * @example s
1255
+ */
1256
+ QuantityUnit: string;
1257
+ /**
1258
+ * @description A hard cap on how many stops of `tasks` the `vehicles` serve together
1111
1259
  * in a window. A stop counts when its service starts in `[from, to)`
1112
- * (`arrival + wait_s` in the response); without a window every stop counts.
1113
- * Stops count as `max_tasks` counts them: a job one, a shipment two. An
1260
+ * (`arrival + wait_s` in the response when no windowed break is taken on
1261
+ * arrival there); without a window every stop counts.
1262
+ * Stops count as `max_stops` counts them: a job one, a shipment two. An
1114
1263
  * over-cap job is left unassigned. Unlike `limits.periods[]`, which counts a
1115
1264
  * shift by its start, a quota has no `every` recurrence and caps only stop
1116
1265
  * counts.
1117
1266
  * @example {
1118
1267
  * "id": "pool-install",
1119
- * "job_ids": [
1268
+ * "max_stops": 2,
1269
+ * "tasks": [
1120
1270
  * "j1",
1121
1271
  * "j2",
1122
1272
  * "j3"
1123
1273
  * ],
1124
- * "max_tasks": 2,
1125
1274
  * "vehicles": [
1126
1275
  * "c0",
1127
1276
  * "c1"
@@ -1143,15 +1292,17 @@ export interface components {
1143
1292
  */
1144
1293
  id: string;
1145
1294
  /**
1146
- * @description Job or shipment ids whose stops count, each at most once. At least
1147
- * one; an id that names no job or shipment is rejected with HTTP 400.
1295
+ * Format: int32
1296
+ * @description The cap on counted stops; a job counts as one stop.
1297
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
1298
+ * shipment counts as two stops.
1148
1299
  */
1149
- job_ids: string[];
1300
+ max_stops: number;
1150
1301
  /**
1151
- * Format: int32
1152
- * @description The cap on counted stops.
1302
+ * @description Job or shipment ids whose stops count, each at most once. At least
1303
+ * one; an id that names no job or shipment is rejected with HTTP 400.
1153
1304
  */
1154
- max_tasks: number;
1305
+ tasks: string[];
1155
1306
  /**
1156
1307
  * Format: date-time
1157
1308
  * @description Window end (RFC 3339, UTC offset required, exclusive), with `from`.
@@ -1182,13 +1333,11 @@ export interface components {
1182
1333
  * that leg like a job. A leg coupled to other tasks by a `synchronized` or
1183
1334
  * `time_lag` relation (directly, or through a `sequence` with a member that
1184
1335
  * is) is rejected with HTTP 400, as is a `sequence` putting a delivery before
1185
- * its pickup. A shipment's own id in the `stops` of a `sequence`,
1186
- * `same_vehicle`, `same_day` or `synchronized` relation, and a shipment
1187
- * carrying the `tag` of a `same_vehicle` or `same_day` relation, passes
1188
- * validation but is skipped: the request returns HTTP 200 and the relation
1189
- * does not constrain that shipment. `same_route`, `time_lag`,
1190
- * `compatible_vehicles`, `all_or_none` and `tag_order` reject a shipment
1191
- * with HTTP 400.
1336
+ * its pickup. A shipment's own id in `stops`, or a shipment carrying the
1337
+ * `tag` of a `same_vehicle` or `same_day` relation, is rejected with HTTP 400
1338
+ * `not_supported`: relations never silently skip a member. `same_route`,
1339
+ * `time_lag`, `compatible_vehicles`, `all_or_none` and `tag_order` reject a
1340
+ * shipment with HTTP 400 as well.
1192
1341
  * @example {
1193
1342
  * "stops": [
1194
1343
  * "job-1",
@@ -1197,41 +1346,102 @@ export interface components {
1197
1346
  * "type": "sequence"
1198
1347
  * }
1199
1348
  */
1200
- Relation: {
1349
+ Relation: components["schemas"]["RelationSequence"] | components["schemas"]["RelationTagOrder"] | components["schemas"]["RelationSameVehicle"] | components["schemas"]["RelationSameDay"] | components["schemas"]["RelationSameRoute"] | components["schemas"]["RelationSynchronized"] | components["schemas"]["RelationTimeLag"] | components["schemas"]["RelationCompatibleVehicles"] | components["schemas"]["RelationAllOrNone"];
1350
+ /**
1351
+ * All or none
1352
+ * @description All or none: either every member in `stops` is served, or none is.
1353
+ * Sets no timing; combine with `synchronized` or `time_lag` for when.
1354
+ * Hard. Overlapping `all_or_none` relations chain: one on A and B plus
1355
+ * one on B and C serve all three together or none of them. A group with
1356
+ * a task in a vehicle's locked prefix (`plan.routes[].locked_count`) is
1357
+ * exempt.
1358
+ *
1359
+ * Every task must also be named by a `synchronized` or `time_lag`
1360
+ * relation; a task named by neither is rejected with HTTP 400.
1361
+ */
1362
+ RelationAllOrNone: {
1201
1363
  /**
1202
- * @description Job ids or shipment-leg stop ids (`pickup.id` / `delivery.id`, by
1203
- * default `"{shipment}:pickup"` / `"{shipment}:delivery"`), in the
1204
- * order they must be served. A shipment's own id is not resolved.
1364
+ * @description Job ids, at least two. A shipment's own id or a shipment-leg stop id
1365
+ * is rejected with HTTP 400.
1366
+ * @example [
1367
+ * "job-1",
1368
+ * "job-2"
1369
+ * ]
1205
1370
  */
1206
1371
  stops: string[];
1207
- /** @enum {string} */
1208
- type: "sequence";
1209
- } | {
1210
- /** @description Tag labels in precedence order. Requires at least 2 entries. */
1211
- tags: string[];
1212
- /** @enum {string} */
1213
- type: "tag_order";
1214
- } | {
1215
1372
  /**
1216
- * @description Job ids or shipment-leg stop ids in the relation (mutually
1217
- * exclusive with `tag`). A shipment's own id is not resolved.
1373
+ * @description Discriminator: always `all_or_none`. (enum property replaced by openapi-typescript)
1374
+ * @enum {string}
1218
1375
  */
1219
- stops?: string[] | null;
1220
- /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1221
- tag?: string | null;
1222
- /** @enum {string} */
1223
- type: "same_vehicle";
1224
- } | {
1225
- /**
1376
+ type: "all_or_none";
1377
+ };
1378
+ /**
1379
+ * Compatible vehicles
1380
+ * @description Which vehicles may serve a set of tasks together. Every two distinct
1381
+ * vehicles serving `stops` must be compatible under
1382
+ * `vehicles[].compatible_with`; with no lists it restricts nothing.
1383
+ * Tasks left unassigned impose nothing, so a group may be served
1384
+ * partially. Hard.
1385
+ *
1386
+ * Every task must also be named by a `synchronized` or `time_lag`
1387
+ * relation; a task named by neither is rejected with HTTP 400. At most
1388
+ * 16 tasks per relation.
1389
+ */
1390
+ RelationCompatibleVehicles: {
1391
+ /**
1392
+ * @description Job ids, 2 to 16. A shipment's own id or a shipment-leg stop id
1393
+ * is rejected with HTTP 400.
1394
+ * @example [
1395
+ * "job-1",
1396
+ * "job-2"
1397
+ * ]
1398
+ */
1399
+ stops: string[];
1400
+ /**
1401
+ * @description Discriminator: always `compatible_vehicles`. (enum property replaced by openapi-typescript)
1402
+ * @enum {string}
1403
+ */
1404
+ type: "compatible_vehicles";
1405
+ };
1406
+ /**
1407
+ * @description Which instant of a member a `synchronized` or `time_lag` relation is
1408
+ * measured at, named after the response stop field that reports it. There is
1409
+ * no `arrival`: a relation bounds when service happens, not when the vehicle
1410
+ * gets there.
1411
+ * @enum {string}
1412
+ */
1413
+ RelationInstant: "service_start" | "departure";
1414
+ /**
1415
+ * Same day
1416
+ * @description Same calendar day: every member that is served is served on the same
1417
+ * day. The day is the calendar date of the serving shift's `from`, read
1418
+ * in that value's own UTC offset, not the time of the stop. Like
1419
+ * `same_vehicle`, it constrains only the members that end up assigned.
1420
+ */
1421
+ RelationSameDay: {
1422
+ /**
1226
1423
  * @description Job ids or shipment-leg stop ids in the relation (mutually
1227
- * exclusive with `tag`). A shipment's own id is not resolved.
1424
+ * exclusive with `tag`). A shipment's own id is rejected with
1425
+ * HTTP 400 `not_supported`.
1228
1426
  */
1229
1427
  stops?: string[] | null;
1230
1428
  /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1231
1429
  tag?: string | null;
1232
- /** @enum {string} */
1430
+ /**
1431
+ * @description Discriminator: always `same_day`. (enum property replaced by openapi-typescript)
1432
+ * @enum {string}
1433
+ */
1233
1434
  type: "same_day";
1234
- } | {
1435
+ } & (unknown | unknown);
1436
+ /**
1437
+ * Same route
1438
+ * @description Same route: every member that ends up assigned is served by one
1439
+ * vehicle shift (one entry of `shifts`), stricter than
1440
+ * `same_vehicle` for vehicles with several `shifts`. Reloads within
1441
+ * the shift do not split a route. Hard-only, with `same_vehicle`'s
1442
+ * partial-service semantics.
1443
+ */
1444
+ RelationSameRoute: {
1235
1445
  /**
1236
1446
  * @description Job ids or shipment-leg stop ids in the relation (mutually
1237
1447
  * exclusive with `tag`). A shipment's own id is rejected with HTTP
@@ -1240,32 +1450,126 @@ export interface components {
1240
1450
  stops?: string[] | null;
1241
1451
  /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1242
1452
  tag?: string | null;
1243
- /** @enum {string} */
1453
+ /**
1454
+ * @description Discriminator: always `same_route`. (enum property replaced by openapi-typescript)
1455
+ * @enum {string}
1456
+ */
1244
1457
  type: "same_route";
1245
- } | {
1458
+ } & (unknown | unknown);
1459
+ /**
1460
+ * Same vehicle
1461
+ * @description Same vehicle: every member that is served is served by the same
1462
+ * vehicle, on any of its shifts.
1463
+ */
1464
+ RelationSameVehicle: {
1465
+ /**
1466
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1467
+ * exclusive with `tag`). A shipment's own id is rejected with
1468
+ * HTTP 400 `not_supported`.
1469
+ */
1470
+ stops?: string[] | null;
1471
+ /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1472
+ tag?: string | null;
1473
+ /**
1474
+ * @description Discriminator: always `same_vehicle`. (enum property replaced by openapi-typescript)
1475
+ * @enum {string}
1476
+ */
1477
+ type: "same_vehicle";
1478
+ } & (unknown | unknown);
1479
+ /**
1480
+ * Sequence
1481
+ * @description Ordering (gaps allowed). Constrains members that end up on the **same
1482
+ * route** only: members on different vehicles are unordered relative to
1483
+ * each other.
1484
+ */
1485
+ RelationSequence: {
1486
+ /**
1487
+ * @description Job ids or shipment-leg stop ids (`pickup.id` / `delivery.id`, by
1488
+ * default `"{shipment}:pickup"` / `"{shipment}:delivery"`), in the
1489
+ * order they must be served. A shipment's own id is
1490
+ * rejected with HTTP 400 `not_supported`.
1491
+ */
1492
+ stops: string[];
1493
+ /**
1494
+ * @description Discriminator: always `sequence`. (enum property replaced by openapi-typescript)
1495
+ * @enum {string}
1496
+ */
1497
+ type: "sequence";
1498
+ };
1499
+ /**
1500
+ * Synchronized
1501
+ * @description Synchronized starts (or ends) across vehicles: every member's
1502
+ * service start — or with `on: departure`, its service end — lies within
1503
+ * `max_spread_s` seconds of every other member's. Hard, checked across
1504
+ * routes; the returned schedule holds a member back where needed so
1505
+ * the bound is met (see `hold_s` on the stop). A hold waits inside the
1506
+ * regular shift only: a member is never held past its shift's `to`
1507
+ * into overtime (`max_overtime_s`); a group that could only meet the
1508
+ * bound that way is left unassigned instead.
1509
+ */
1510
+ RelationSynchronized: {
1246
1511
  /**
1247
1512
  * Format: int64
1248
1513
  * @description Maximum spread between the synchronized instants in seconds
1249
1514
  * (`0` = exact simultaneity). Required. A negative value, or one that
1250
1515
  * does not fit in 32 bits, is rejected with HTTP 400 `out_of_range`.
1251
1516
  */
1252
- max_wait_s: number;
1517
+ max_spread_s: number;
1253
1518
  /**
1254
- * @description Which instant is synchronized: the service `start` (default) or
1255
- * the service `end`. `arrival` is rejected with HTTP 400.
1519
+ * @description Which instant is synchronized: `service_start` (default) or
1520
+ * `departure` (the service end), the stop fields of the same names.
1521
+ * @default service_start
1256
1522
  */
1257
- on?: null | components["schemas"]["StopInstant"];
1523
+ on?: null | components["schemas"]["RelationInstant"];
1258
1524
  /**
1259
1525
  * @description Participating job ids, at most 8 (HTTP 400 `limit_exceeded`
1260
1526
  * beyond that). A shipment-leg stop id is rejected with HTTP 400;
1261
- * a shipment's own id is not resolved.
1527
+ * a shipment's own id with HTTP 400 `not_supported`.
1262
1528
  */
1263
1529
  stops: string[];
1264
- /** @enum {string} */
1530
+ /**
1531
+ * @description Discriminator: always `synchronized`. (enum property replaced by openapi-typescript)
1532
+ * @enum {string}
1533
+ */
1265
1534
  type: "synchronized";
1266
- } | {
1535
+ };
1536
+ /**
1537
+ * Tag order
1538
+ * @description Ordering between tags: on every route, every task carrying `tags[0]`
1539
+ * precedes every task carrying `tags[1]`, and so on. Tasks carry
1540
+ * membership via their own `tags`. At most one `tag_order` per request.
1541
+ *
1542
+ * Jobs only: if a tag named here selects a **shipment**, the request is
1543
+ * rejected with HTTP 400 (a shipment's two legs already carry their own
1544
+ * hard precedence, which tag ordering cannot compose with yet). Drop the
1545
+ * tag from the shipment.
1546
+ */
1547
+ RelationTagOrder: {
1548
+ /** @description Tag labels in precedence order. Requires at least 2 entries. */
1549
+ tags: string[];
1550
+ /**
1551
+ * @description Discriminator: always `tag_order`. (enum property replaced by openapi-typescript)
1552
+ * @enum {string}
1553
+ */
1554
+ type: "tag_order";
1555
+ };
1556
+ /**
1557
+ * Time lag
1558
+ * @description A directional time bound between two jobs on any vehicles:
1559
+ * `t(to) − t(from)` must lie in `[min_s, max_s]` seconds, each end
1560
+ * measured at the job's service start or end (`on`). "B starts at
1561
+ * least an hour after A ends" is `from: {stop: A, on: departure}, to: {stop: B},
1562
+ * min_s: 3600`; "A and B finish together" is both ends `on: departure` with
1563
+ * `min_s: 0, max_s: 0`. `min_s` defaults to `0`; an absent `max_s` is
1564
+ * unbounded; both may be negative. Hard, checked across routes like
1565
+ * `synchronized` (an unassigned end imposes nothing). A job may take
1566
+ * part in any number of `time_lag` relations; a chain is written as
1567
+ * one relation per consecutive pair. As with `synchronized`, a hold
1568
+ * never waits past the shift's regular end (`to`).
1569
+ */
1570
+ RelationTimeLag: {
1267
1571
  /** @description The reference end. */
1268
- from: components["schemas"]["TimeLagEnd"];
1572
+ from: components["schemas"]["TimeLagMember"];
1269
1573
  /**
1270
1574
  * Format: int64
1271
1575
  * @description Upper bound on `t(to) − t(from)` in seconds. Absent = unbounded.
@@ -1276,45 +1580,25 @@ export interface components {
1276
1580
  * Format: int64
1277
1581
  * @description Lower bound on `t(to) − t(from)` in seconds. Default `0`. Must fit
1278
1582
  * in 32 bits.
1583
+ * @default 0
1279
1584
  */
1280
1585
  min_s?: number | null;
1281
1586
  /** @description The bounded end. */
1282
- to: components["schemas"]["TimeLagEnd"];
1283
- /** @enum {string} */
1284
- type: "time_lag";
1285
- } | {
1286
- /**
1287
- * @description Job ids, 2 to 16. A shipment's own id or a shipment-leg stop id
1288
- * is rejected with HTTP 400.
1289
- * @example [
1290
- * "job-1",
1291
- * "job-2"
1292
- * ]
1293
- */
1294
- stops: string[];
1295
- /** @enum {string} */
1296
- type: "compatible_vehicles";
1297
- } | {
1587
+ to: components["schemas"]["TimeLagMember"];
1298
1588
  /**
1299
- * @description Job ids, at least two. A shipment's own id or a shipment-leg stop id
1300
- * is rejected with HTTP 400.
1301
- * @example [
1302
- * "job-1",
1303
- * "job-2"
1304
- * ]
1589
+ * @description Discriminator: always `time_lag`. (enum property replaced by openapi-typescript)
1590
+ * @enum {string}
1305
1591
  */
1306
- stops: string[];
1307
- /** @enum {string} */
1308
- type: "all_or_none";
1592
+ type: "time_lag";
1309
1593
  };
1310
1594
  /**
1311
1595
  * @description A best-effort, actionable suggestion for relaxing the problem so a task can be
1312
1596
  * assigned — derived from the smallest constraint relaxation the solver found.
1313
1597
  * @example {
1314
1598
  * "amount": 900,
1315
- * "field": "/jobs/job-2/time_windows",
1599
+ * "message": "Extend a time window by 900s (~15 min).",
1316
1600
  * "op": "extend_time_window",
1317
- * "suggestion": "Extend a time window by 900s (~15 min).",
1601
+ * "pointer": "/problem/jobs/1/time_windows",
1318
1602
  * "unit": "s"
1319
1603
  * }
1320
1604
  */
@@ -1325,37 +1609,60 @@ export interface components {
1325
1609
  * @example 900
1326
1610
  */
1327
1611
  amount: number;
1328
- /**
1329
- * @description Names the task and the field to change. For a job: `/jobs/{id}/pickup`
1330
- * (`/jobs/{id}/delivery` for a job with only a `delivery`) or
1331
- * `/jobs/{id}/time_windows`. For a shipment: `/shipments/{id}/load` or
1332
- * `/shipments/{id}/pickup/time_windows` (either leg's window may be the
1333
- * one to extend). `{id}` is the task id, the same value as `job_id`. It is
1334
- * a label, not a JSON Pointer into the request body: it uses the id, not
1335
- * the array index, and has no `/problem` prefix.
1336
- * @example /jobs/job-2/time_windows
1337
- */
1338
- field: string;
1339
- /** @description The kind of change suggested. */
1340
- op: components["schemas"]["RelaxationOp"];
1341
1612
  /**
1342
1613
  * @description Human-readable suggestion.
1343
1614
  * @example Extend a time window by 900s (~15 min).
1344
1615
  */
1345
- suggestion: string;
1616
+ message: string;
1617
+ /** @description The kind of change suggested. */
1618
+ op: components["schemas"]["RelaxationOp"];
1346
1619
  /**
1347
- * @description Unit of `amount`: `"s"` (seconds, for `extend_time_window`) or
1348
- * `"load"` (demand units, for `reduce_demand`).
1349
- * @example s
1620
+ * @description [RFC 6901] JSON Pointer to the request field to change, like
1621
+ * `warnings[].pointer`. For a job: `/problem/jobs/{i}/pickup_load`
1622
+ * (`/problem/jobs/{i}/delivery_load` for a job with only a
1623
+ * `delivery_load`) or `/problem/jobs/{i}/time_windows`. For a shipment:
1624
+ * `/problem/shipments/{i}/load` or `/problem/shipments/{i}/pickup/time_windows`
1625
+ * (either leg's window may be the one to extend). It may name a field the
1626
+ * request omits (a JSON Patch `add` target); its task prefix always resolves.
1627
+ *
1628
+ * [RFC 6901]: https://www.rfc-editor.org/rfc/rfc6901
1629
+ * @example /problem/jobs/1/time_windows
1350
1630
  */
1351
- unit: string;
1631
+ pointer: string;
1632
+ /** @description Unit of `amount`: `s` for `extend_time_window`, `load` for `reduce_load`. */
1633
+ unit: components["schemas"]["QuantityUnit"];
1352
1634
  };
1353
1635
  /**
1354
1636
  * @description The kind of change a relaxation suggests.
1637
+ *
1638
+ * Known values: `reduce_load`, `extend_time_window`. An open set: a later release may add values, so accept any string and handle the ones you know.
1355
1639
  * @example extend_time_window
1356
- * @enum {string}
1357
1640
  */
1358
- RelaxationOp: "reduce_demand" | "extend_time_window";
1641
+ RelaxationOp: string;
1642
+ /** @description One problem in a request. */
1643
+ RequestIssue: {
1644
+ /**
1645
+ * Format: int64
1646
+ * @description `limit_exceeded` only: the count this request has.
1647
+ */
1648
+ actual?: number | null;
1649
+ /** @description What is wrong. */
1650
+ code: components["schemas"]["ErrorItemCode"];
1651
+ /**
1652
+ * Format: int64
1653
+ * @description `limit_exceeded` only: the published cap.
1654
+ */
1655
+ limit?: number | null;
1656
+ /** @description Human-readable description. */
1657
+ message: string;
1658
+ /**
1659
+ * @description RFC 6901 JSON Pointer into the request body, when the problem has a
1660
+ * location. It is relative to the root of the body, so a field of the
1661
+ * problem reads `/problem/...` (e.g.
1662
+ * `"/problem/vehicles/0/shifts/0/from"`).
1663
+ */
1664
+ pointer?: string | null;
1665
+ };
1359
1666
  /**
1360
1667
  * @description A single vehicle's route.
1361
1668
  * @example {
@@ -1393,6 +1700,7 @@ export interface components {
1393
1700
  * 51.05
1394
1701
  * ],
1395
1702
  * "service_s": 300,
1703
+ * "service_start": "2026-07-01T09:00:00+02:00",
1396
1704
  * "travel_s": 600,
1397
1705
  * "type": "job",
1398
1706
  * "wait_s": 3000
@@ -1411,6 +1719,7 @@ export interface components {
1411
1719
  * 51.06
1412
1720
  * ],
1413
1721
  * "service_s": 600,
1722
+ * "service_start": "2026-07-01T09:13:00+02:00",
1414
1723
  * "travel_s": 480,
1415
1724
  * "type": "job",
1416
1725
  * "wait_s": 0
@@ -1429,7 +1738,8 @@ export interface components {
1429
1738
  * ],
1430
1739
  * "service_s": 0,
1431
1740
  * "travel_s": 900,
1432
- * "type": "end"
1741
+ * "type": "end",
1742
+ * "wait_s": 0
1433
1743
  * }
1434
1744
  * ],
1435
1745
  * "time": {
@@ -1452,11 +1762,11 @@ export interface components {
1452
1762
  */
1453
1763
  distance_m: number;
1454
1764
  /** @description Peak load reached on the route, by named dimension. */
1455
- load_peak?: null | components["schemas"]["BTreeMap"];
1765
+ load_peak?: null | components["schemas"]["Quantities"];
1456
1766
  /**
1457
1767
  * @description Road geometry for this route as an [encoded polyline] at precision 5
1458
1768
  * (~1.1 m), ready to hand to a map library. Present only when
1459
- * `options.polylines` was set, and absent for a route whose geometry the
1769
+ * `options.polyline` was set, and absent for a route whose geometry the
1460
1770
  * routing engine could not produce.
1461
1771
  *
1462
1772
  * Traced with this vehicle's `profile` at the solve's departure time, so
@@ -1473,8 +1783,14 @@ export interface components {
1473
1783
  * @example mon
1474
1784
  */
1475
1785
  shift: string;
1476
- /** @description Ordered stops, including depot bookends. */
1477
- stops: components["schemas"]["StopOutput"][];
1786
+ /**
1787
+ * @description Stops in time order (by `departure`), including depot bookends. A
1788
+ * windowed break taken while the vehicle is at a stop is listed just
1789
+ * before that stop and lies within that stop's `arrival` to `departure`
1790
+ * (the end stop included); drive, duty and unavailability breaks end
1791
+ * before the next stop's `arrival`.
1792
+ */
1793
+ stops: components["schemas"]["RouteStop"][];
1478
1794
  /**
1479
1795
  * @description Where this route's time goes. `time.span_s` is what the route's
1480
1796
  * `costs.per_route_hour` is charged on: the shift's rate, else its
@@ -1484,7 +1800,7 @@ export interface components {
1484
1800
  /** @description The vehicle id (`vehicle.id` from the request) serving this route. */
1485
1801
  vehicle: string;
1486
1802
  /**
1487
- * @description Route-level constraint violations (e.g. `max_distance`, `max_duration`,
1803
+ * @description Route-level constraint violations (e.g. `max_distance`, `max_route_duration`,
1488
1804
  * or `unreachable` for a leg whose destination is not a job stop — the
1489
1805
  * return to the end depot, or a leg into a reload).
1490
1806
  * Only populated by `POST /v3/routing/evaluate`; absent on solve responses.
@@ -1492,18 +1808,212 @@ export interface components {
1492
1808
  violations?: components["schemas"]["Violation"][];
1493
1809
  };
1494
1810
  /**
1495
- * @description How good a plan is. Plans compare in order: fewer `violations` first,
1496
- * then less `unserved_priority`, then less `cost`.
1811
+ * @description A single stop within a route.
1812
+ *
1813
+ * One flat object for every stop `type`. `type`, `arrival` and `departure`
1814
+ * are present on every stop; every other field is present only on the stop
1815
+ * types its description names, and absent (not `null`) elsewhere:
1816
+ *
1817
+ * | `type` | fields beyond `type`, `arrival`, `departure` |
1818
+ * | --- | --- |
1819
+ * | `job`, `pickup`, `delivery` | `id`, `location`, `service_start`, `wait_s`, `service_s`, `travel_s`, `distance_m`, `lateness_s`; `hold_s`, `target_lateness_s`, `violations` when they apply |
1820
+ * | `start` | `depot`, `location`, `service_s` (absent on an open start) |
1821
+ * | `end` | `depot`, `location`, `wait_s`, `service_s` (absent on an open end), `travel_s`, `distance_m` |
1822
+ * | `reload` | `depot`, `location`, `service_start`, `wait_s`, `service_s`, `travel_s`, `distance_m` |
1823
+ * | `break` | `id` (when the request break names one), `service_s` |
1824
+ *
1825
+ * `load_after` is on every stop when the problem declares a capacity
1826
+ * dimension, and `snapped_location` wherever there is a `location` and the
1827
+ * routing graph snapped it.
1828
+ *
1829
+ * Every stop time is RFC 3339, rendered in the UTC offset of the route's
1830
+ * shift `from` (`Z` when that `from` is UTC or has no offset): a `+02:00`
1831
+ * shift reports `2026-07-01T08:10:00+02:00`, the same instant as
1832
+ * `2026-07-01T06:10:00Z`.
1833
+ * @example {
1834
+ * "arrival": "2026-07-01T08:10:00+02:00",
1835
+ * "departure": "2026-07-01T09:05:00+02:00",
1836
+ * "distance_m": 2600,
1837
+ * "id": "job-1",
1838
+ * "lateness_s": 0,
1839
+ * "load_after": {
1840
+ * "weight": 20
1841
+ * },
1842
+ * "location": [
1843
+ * 3.725,
1844
+ * 51.05
1845
+ * ],
1846
+ * "service_s": 300,
1847
+ * "service_start": "2026-07-01T09:00:00+02:00",
1848
+ * "travel_s": 600,
1849
+ * "type": "job",
1850
+ * "wait_s": 3000
1851
+ * }
1852
+ */
1853
+ RouteStop: {
1854
+ /**
1855
+ * Format: date-time
1856
+ * @description Physical arrival, before any waiting. On `start` when the route
1857
+ * begins; on `break` when the break starts.
1858
+ * @example 2026-07-01T08:10:00+02:00
1859
+ */
1860
+ arrival: string;
1861
+ /**
1862
+ * Format: date-time
1863
+ * @description Departure. On `end` when the route finishes, after any depot
1864
+ * handling time; on `break` when the break ends (`arrival + service_s`).
1865
+ * @example 2026-07-01T09:05:00+02:00
1866
+ */
1867
+ departure: string;
1868
+ /**
1869
+ * @description The `depots[].id` of this stop: on every `reload` stop, and on a
1870
+ * `start`/`end` stop whose shift end names a depot. Absent on a
1871
+ * `location` or open end and on task and break stops.
1872
+ * @example gent
1873
+ */
1874
+ depot?: string | null;
1875
+ /**
1876
+ * Format: int32
1877
+ * @description Travel distance from the previous stop, in metres. On task, `reload`
1878
+ * and `end` stops.
1879
+ * @example 2600
1880
+ */
1881
+ distance_m?: number | null;
1882
+ /**
1883
+ * Format: int32
1884
+ * @description The part of `wait_s` spent holding for a `synchronized` or
1885
+ * `time_lag` partner on another vehicle, beyond any wait the time
1886
+ * window already imposed. On task stops, only when non-zero.
1887
+ * @example 0
1888
+ */
1889
+ hold_s?: number | null;
1890
+ /**
1891
+ * @description On a `job` stop the job id; on `pickup`/`delivery` the leg's stop id
1892
+ * (its own `id`, else `{shipment}:pickup` / `{shipment}:delivery`); on a
1893
+ * `break` stop the `id` of the request break (`shifts[].breaks[].id`)
1894
+ * it realises, absent when that break named none. Absent on `start`,
1895
+ * `end` and `reload`.
1896
+ * @example job-1
1897
+ */
1898
+ id?: string | null;
1899
+ /**
1900
+ * Format: int32
1901
+ * @description Seconds late beyond the latest allowed arrival (`0` when on time), on
1902
+ * task stops, measured from the arrival plus any `windowed` break taken
1903
+ * on arrival at this stop (idle until that break's window opens
1904
+ * included). Measures the hard time window only; a soft target is
1905
+ * reported in `target_lateness_s`.
1906
+ * @example 0
1907
+ */
1908
+ lateness_s?: number | null;
1909
+ /**
1910
+ * @description Load on board after this stop, by named dimension: on `start` when
1911
+ * the vehicle leaves, on `reload` the next trip's departure stock, on
1912
+ * `break` the load after the previous stop. Absent when the problem
1913
+ * declares no capacity dimension.
1914
+ */
1915
+ load_after?: null | components["schemas"]["Quantities"];
1916
+ /**
1917
+ * @description Stop location `[longitude, latitude]` (GeoJSON order). Absent on
1918
+ * every `break` stop, including a break with a pinned location, and on
1919
+ * `start`/`end` stops for a genuinely open end (no configured
1920
+ * coordinate for that end of the shift). A virtual (location-less) job
1921
+ * has no coordinate of its own and reports its nearest located
1922
+ * neighbor's instead, so it is absent only when the whole route is
1923
+ * virtual with open depot ends.
1924
+ * @example [
1925
+ * 3.725,
1926
+ * 51.05
1927
+ * ]
1928
+ */
1929
+ location?: number[] | null;
1930
+ /**
1931
+ * Format: int32
1932
+ * @description Time spent at this stop, in seconds.
1933
+ *
1934
+ * On task stops, the **effective** on-site service time, not the
1935
+ * nominal `service_duration_s` from the request: it already has the
1936
+ * serving vehicle's `service_factor` applied. `departure -
1937
+ * service_start - service_s` is the stop's setup time: the request's
1938
+ * `setup_duration_s` (unscaled) for the first stop of a run at the same
1939
+ * location (setup is charged when the previous stop is elsewhere), and 0
1940
+ * for a co-located successor.
1941
+ *
1942
+ * On `reload`, the depot's handling time (`departure - service_start
1943
+ * == service_s`). On `start`/`end`, the depot handling time applied
1944
+ * there (0 on a free-travel end), so `departure - arrival == service_s`
1945
+ * on a start and `departure - arrival - wait_s - Σ windowed break
1946
+ * service_s == service_s` on an end; absent on an open start or end. On `break`, the
1947
+ * break length (`departure - arrival`). `service_factor` never scales
1948
+ * depot, reload or break time.
1949
+ * @example 300
1950
+ */
1951
+ service_s?: number | null;
1952
+ /**
1953
+ * Format: date-time
1954
+ * @description When service starts: `arrival + wait_s` plus the duration of any
1955
+ * windowed break taken on arrival here. On task and `reload` stops only.
1956
+ * @example 2026-07-01T09:00:00+02:00
1957
+ */
1958
+ service_start?: string | null;
1959
+ /** @description The same point snapped to the routable graph, when available. */
1960
+ snapped_location?: number[] | null;
1961
+ /**
1962
+ * Format: int32
1963
+ * @description Seconds past this task's `target.at`, measured at the stop's arrival
1964
+ * (plus any `windowed` break taken on arrival there, idle before it
1965
+ * included) or departure per `target.on`; `0` when met. Present only on a task
1966
+ * stop carrying a target. A shipment's target is measured on its
1967
+ * delivery leg, so it appears on the `:delivery` stop and never on the
1968
+ * `:pickup` stop.
1969
+ * @example 0
1970
+ */
1971
+ target_lateness_s?: number | null;
1972
+ /**
1973
+ * Format: int32
1974
+ * @description Travel time from the previous stop, in seconds. On task, `reload`
1975
+ * and `end` stops.
1976
+ * @example 600
1977
+ */
1978
+ travel_s?: number | null;
1979
+ /** @description What kind of stop this is. */
1980
+ type: components["schemas"]["StopType"];
1981
+ /**
1982
+ * @description Constraint violations detected at this task stop. Only populated by
1983
+ * `POST /v3/routing/evaluate` (imported solutions may be infeasible); a
1984
+ * solve response never emits violations, so this is absent there.
1985
+ */
1986
+ violations?: components["schemas"]["Violation"][];
1987
+ /**
1988
+ * Format: int32
1989
+ * @description Seconds spent waiting here, counted in `time.wait_s`. On task stops:
1990
+ * before service, for the time window to open and for any cross-route
1991
+ * hold (`hold_s`, included in this figure). On `reload`: before the
1992
+ * reload. On both, also the idle before a windowed break taken on
1993
+ * arrival here whose window had not opened yet, so `service_start ==
1994
+ * arrival + wait_s + Σ` those breaks' `service_s`. On `end`: idle time
1995
+ * at the end, `departure - arrival - service_s` less the `service_s` of
1996
+ * break stops taken there, clamped to be never negative. Idle before a
1997
+ * break is not charged by `per_wait_hour`. Absent on `start` (a start
1998
+ * never waits) and `break`.
1999
+ * @example 3000
2000
+ */
2001
+ wait_s?: number | null;
2002
+ };
2003
+ /**
2004
+ * @description How good a plan is. Plans compare in order: fewer `violation_count`
2005
+ * first, then less `unassigned_priority`, then less `cost`.
1497
2006
  * @example {
1498
2007
  * "components": {
1499
- * "depot_visits": 0,
2008
+ * "assignment": 0,
1500
2009
  * "distance": 1.69,
1501
- * "drop_fees": 0,
1502
- * "fixed": 0,
2010
+ * "drop_costs": 0,
1503
2011
  * "grouping": 0,
1504
2012
  * "lateness": 0,
1505
- * "other": 0,
1506
2013
  * "overtime": 0,
2014
+ * "preferences": 0,
2015
+ * "reloads": 0,
2016
+ * "routes": 0,
1507
2017
  * "tag_preference": 0,
1508
2018
  * "target": 0,
1509
2019
  * "time": 57.1536,
@@ -1513,8 +2023,8 @@ export interface components {
1513
2023
  * },
1514
2024
  * "cost": 58.8436,
1515
2025
  * "currency": "EUR",
1516
- * "unserved_priority": 0,
1517
- * "violations": 0
2026
+ * "unassigned_priority": 0,
2027
+ * "violation_count": 0
1518
2028
  * }
1519
2029
  */
1520
2030
  Score: {
@@ -1534,43 +2044,47 @@ export interface components {
1534
2044
  /**
1535
2045
  * Format: int64
1536
2046
  * @description Summed `priority` of the required tasks left unassigned (a task that
1537
- * priced a `drop_fee` counts in `components.drop_fees` instead).
2047
+ * priced a `drop_cost` counts in `components.drop_costs` instead).
1538
2048
  * @example 0
1539
2049
  */
1540
- unserved_priority: number;
2050
+ unassigned_priority: number;
1541
2051
  /**
1542
2052
  * Format: int32
1543
- * @description Hard-constraint violations. Always `0` on a solve result.
2053
+ * @description How many hard-constraint violations the plan has (the `violations`
2054
+ * arrays on routes and stops list them). Always `0` on a solve result.
1544
2055
  * @example 0
1545
2056
  */
1546
- violations: number;
2057
+ violation_count: number;
1547
2058
  };
1548
2059
  /**
1549
2060
  * @description The money of each objective term, in the objective's currency. The
1550
2061
  * components always sum to `score.cost` exactly: every term the solver
1551
2062
  * charges lands in exactly one of them.
1552
2063
  * @example {
1553
- * "depot_visits": 0,
2064
+ * "assignment": 0,
1554
2065
  * "distance": 1.69,
1555
- * "drop_fees": 0,
1556
- * "fixed": 0,
2066
+ * "drop_costs": 0,
1557
2067
  * "grouping": 0,
1558
2068
  * "lateness": 0,
1559
- * "other": 0,
1560
2069
  * "overtime": 0,
2070
+ * "preferences": 0,
2071
+ * "reloads": 0,
2072
+ * "routes": 0,
1561
2073
  * "tag_preference": 0,
1562
2074
  * "target": 0,
1563
2075
  * "time": 57.1536,
1564
2076
  * "waiting": 0,
1565
- * "window_choice": 0
2077
+ * "window_choice": 0,
2078
+ * "workload_share": 0
1566
2079
  * }
1567
2080
  */
1568
2081
  ScoreComponents: {
1569
2082
  /**
1570
2083
  * Format: double
1571
- * @description Cost of reload visits, in currency units (`depots[].cost_per_visit`).
2084
+ * @description Cost of the serving vehicle's `assignment_costs[].cost` (or the task's
2085
+ * default assignment cost), in currency units.
1572
2086
  */
1573
- depot_visits: number;
2087
+ assignment: number;
1574
2088
  /**
1575
2089
  * Format: double
1576
2090
  * @description Distance cost, in currency units: each route's distance priced at
@@ -1579,15 +2093,9 @@ export interface components {
1579
2093
  distance: number;
1580
2094
  /**
1581
2095
  * Format: double
1582
- * @description The summed `drop_fee` of the tasks left unassigned, in currency units.
1583
- */
1584
- drop_fees: number;
1585
- /**
1586
- * Format: double
1587
- * @description Vehicle cost, in currency units: `costs.fixed` once per used shift,
1588
- * at the shift's, vehicle's or fleet's rate.
2096
+ * @description The summed `drop_cost` of the tasks left unassigned, in currency units.
1589
2097
  */
1590
- fixed: number;
2098
+ drop_costs: number;
1591
2099
  /**
1592
2100
  * Format: double
1593
2101
  * @description Cost of splitting close tasks across routes, in currency units
@@ -1600,19 +2108,30 @@ export interface components {
1600
2108
  * (`objective.per_late_hour` or `time_windows[].per_late_hour`).
1601
2109
  */
1602
2110
  lateness: number;
1603
- /**
1604
- * Format: double
1605
- * @description Everything else the solver charges, in currency units: vehicle
1606
- * preferences (`preferences[].violation_cost`), `assignment_costs`, and
1607
- * the non-preferred-date cost (`objective.non_preferred_date_cost`).
1608
- */
1609
- other: number;
1610
2111
  /**
1611
2112
  * Format: double
1612
2113
  * @description Cost of work past a soft shift end, in currency units: priced at the
1613
2114
  * route's `costs.per_overtime_hour`.
1614
2115
  */
1615
2116
  overtime: number;
2117
+ /**
2118
+ * Format: double
2119
+ * @description Cost of `preferences[].violation_cost`, in currency units: paid for
2120
+ * each listed vehicle that did not serve the task. Tag preferences are
2121
+ * `tag_preference`.
2122
+ */
2123
+ preferences: number;
2124
+ /**
2125
+ * Format: double
2126
+ * @description Cost of reload visits, in currency units (`depots[].per_reload`).
2127
+ */
2128
+ reloads: number;
2129
+ /**
2130
+ * Format: double
2131
+ * @description Vehicle cost, in currency units: `costs.per_route` once per used shift,
2132
+ * at the shift's, vehicle's or fleet's rate.
2133
+ */
2134
+ routes: number;
1616
2135
  /**
1617
2136
  * Format: double
1618
2137
  * @description Cost of serving tasks outside a vehicle's `preferred_tags`, in
@@ -1634,7 +2153,8 @@ export interface components {
1634
2153
  /**
1635
2154
  * Format: double
1636
2155
  * @description Cost of waiting for time windows to open, in currency units: each
1637
- * route's wait priced at its `costs.per_wait_hour`.
2156
+ * route's wait priced at its `costs.per_wait_hour`. Idle before a
2157
+ * windowed break opens is in `time.wait_s` but not priced here.
1638
2158
  */
1639
2159
  waiting: number;
1640
2160
  /**
@@ -1650,9 +2170,27 @@ export interface components {
1650
2170
  */
1651
2171
  workload_share: number;
1652
2172
  };
1653
- /**
1654
- * @description Per-vehicle work-rate override for one task's `service_duration_s`.
1655
- * @example {
2173
+ /** @description How the search behind a plan ended. */
2174
+ SearchInfo: {
2175
+ /**
2176
+ * Format: int64
2177
+ * @description Search iterations performed. `0` when nothing was searched.
2178
+ * @example 48210
2179
+ */
2180
+ iterations: number;
2181
+ /** @description How the search ended. */
2182
+ termination: components["schemas"]["SearchTermination"];
2183
+ };
2184
+ /**
2185
+ * @description How the search ended. New values may be added; clients must accept
2186
+ * unknown values.
2187
+ *
2188
+ * Known values: `time_limit`, `no_improvement`, `not_searched`. An open set: a later release may add values, so accept any string and handle the ones you know.
2189
+ */
2190
+ SearchTermination: string;
2191
+ /**
2192
+ * @description Per-vehicle work-rate override for one task's `service_duration_s`.
2193
+ * @example {
1656
2194
  * "factor": 1.25,
1657
2195
  * "vehicle": "v1"
1658
2196
  * }
@@ -1660,9 +2198,14 @@ export interface components {
1660
2198
  ServiceFactor: {
1661
2199
  /**
1662
2200
  * Format: double
1663
- * @description Same meaning, direction and `(0, 5]` range as `vehicles[].service_factor`:
1664
- * effective service time = `service_duration_s / (vehicle_or_shift_factor * factor)`.
1665
- * `1.0` is a no-op.
2201
+ * @description Work-rate factor of `vehicle` on this task. Service time is DIVIDED by
2202
+ * it: above `1` the vehicle works faster here, below `1` slower; `1.0` is a
2203
+ * no-op. It multiplies the vehicle's own rate (the shift's
2204
+ * `service_factor` if set, else the vehicle's): effective service time =
2205
+ * `service_duration_s / (shift_or_vehicle_factor * factor)`. Same
2206
+ * direction and `[0.001, 5]` range as `vehicles[].service_factor`. V2's
2207
+ * `proficiency.durationModifier` multiplied duration instead; the V2
2208
+ * compatibility layer sends its inverse (`1 / durationModifier`) here.
1666
2209
  * @example 1.25
1667
2210
  */
1668
2211
  factor: number;
@@ -1704,7 +2247,7 @@ export interface components {
1704
2247
  * vehicle's value for that dimension; dimensions not named keep the
1705
2248
  * vehicle's `capacity`.
1706
2249
  */
1707
- capacity?: null | components["schemas"]["BTreeMap"];
2250
+ capacity?: null | components["schemas"]["Quantities"];
1708
2251
  /**
1709
2252
  * @description Costs for this shift only. Each field set here replaces the same
1710
2253
  * field of the vehicle's `costs` (or, when the vehicle does not set it,
@@ -1712,7 +2255,23 @@ export interface components {
1712
2255
  */
1713
2256
  costs?: null | components["schemas"]["Costs"];
1714
2257
  /** @description Where the shift ends. Absent = open end. */
1715
- end?: null | components["schemas"]["ShiftEnd"];
2258
+ end?: null | components["schemas"]["ShiftPlace"];
2259
+ /**
2260
+ * @description Symmetric to `free_start_travel` for travel from the last task to
2261
+ * `end`; `true` without `end` is a 400.
2262
+ * @example false
2263
+ */
2264
+ free_end_travel?: boolean | null;
2265
+ /**
2266
+ * @description When `true`, travel from `start` to the first task is free: it takes
2267
+ * no time and costs nothing, and is left out of the route's distance
2268
+ * and duration. The depot is still reported (a real stop, snapped
2269
+ * coordinate, departure time). Distinct from omitting `start` (an open
2270
+ * route, which drops the depot entirely). `true` without `start` is
2271
+ * rejected with HTTP 400 `conflicting_fields`. Default `false`.
2272
+ * @example false
2273
+ */
2274
+ free_start_travel?: boolean | null;
1716
2275
  /**
1717
2276
  * Format: date-time
1718
2277
  * @description Shift start (RFC 3339 instant, UTC offset required).
@@ -1724,22 +2283,6 @@ export interface components {
1724
2283
  * @example mon
1725
2284
  */
1726
2285
  id: string;
1727
- /**
1728
- * @description Symmetric to `ignore_start_leg` for the last-task → `end` leg.
1729
- * @example false
1730
- */
1731
- ignore_end_leg?: boolean | null;
1732
- /**
1733
- * @description When `true`, the `start` → first-task leg costs nothing (not counted
1734
- * in objective, feasibility timing, or total distance/duration) — the
1735
- * depot is still known and reported (a real stop, snapped coordinate,
1736
- * departure time). Distinct from omitting `start` (a fully open route,
1737
- * which drops the depot entirely): this keeps the depot visible while
1738
- * making the leg to it free. Requires `start`; a no-op when `start` is
1739
- * absent. Default `false`.
1740
- * @example false
1741
- */
1742
- ignore_start_leg?: boolean | null;
1743
2286
  /**
1744
2287
  * @description Load already on the vehicle at shift start (pre-loaded), per
1745
2288
  * dimension. Occupies capacity on the first trip only — flushed at the
@@ -1751,7 +2294,7 @@ export interface components {
1751
2294
  * HTTP 400. A dimension named here but absent from `capacity` behaves
1752
2295
  * the same as capacity `0` in that dimension.
1753
2296
  */
1754
- initial_load?: null | components["schemas"]["BTreeMap"];
2297
+ initial_load?: null | components["schemas"]["Quantities"];
1755
2298
  /**
1756
2299
  * @description Limits for this shift only. Each field set here replaces the
1757
2300
  * vehicle's `limits` value; fields not set keep it.
@@ -1783,7 +2326,7 @@ export interface components {
1783
2326
  /**
1784
2327
  * @description Depots (by `depots[].id`, each at most once) the vehicle may return to
1785
2328
  * mid-shift to reload and start a fresh trip. Each visit takes that
1786
- * depot's `service_duration_s` and `cost_per_visit`. Cap trips with
2329
+ * depot's `service_duration_s` and `per_reload`. Cap trips with
1787
2330
  * `max_trips`.
1788
2331
  */
1789
2332
  reloads?: string[] | null;
@@ -1795,12 +2338,14 @@ export interface components {
1795
2338
  serves_tags?: string[] | null;
1796
2339
  /**
1797
2340
  * Format: double
1798
- * @description Work-rate multiplier for this shift only, overriding
1799
- * `vehicles[].service_factor` when set (absent = inherit the vehicle's
1800
- * value, which itself defaults to 1.0).
2341
+ * @description Work-rate factor for this shift only. It REPLACES
2342
+ * `vehicles[].service_factor` for the shift when set (absent = inherit the
2343
+ * vehicle's value, which itself defaults to 1.0); a task's
2344
+ * `service_factors[].factor` for this vehicle multiplies it.
1801
2345
  *
1802
- * Same meaning, direction, and `(0, 5]` range as the vehicle-level field:
1803
- * effective service time = `service_duration_s / service_factor`. Use it
2346
+ * Same meaning, direction, and `[0.001, 5]` range as the vehicle-level
2347
+ * field: service time is DIVIDED by it, effective service time =
2348
+ * `service_duration_s / service_factor`, so above `1` is faster. Use it
1804
2349
  * when the same driver works at a different rate on different days — a
1805
2350
  * measured per-day efficiency, a trainee shift, a two-person crew on
1806
2351
  * Fridays — instead of collapsing those days into one vehicle-level mean.
@@ -1815,14 +2360,14 @@ export interface components {
1815
2360
  * @description Capabilities this shift provides, replacing the vehicle's `skills`
1816
2361
  * for this shift only (a technician covering another region on one
1817
2362
  * day, a crew that only carries a certification on some shifts). A
1818
- * job's `skills` must all appear in the skills of the shift that
2363
+ * job's `required_skills` must all appear in the skills of the shift that
1819
2364
  * serves it, at a level of at least the job's `min_level`. Same entry
1820
2365
  * shape as `vehicles[].skills`. Absent = the vehicle's `skills`; `[]` =
1821
2366
  * this shift provides none.
1822
2367
  */
1823
2368
  skills?: components["schemas"]["VehicleSkill"][] | null;
1824
2369
  /** @description Where the shift starts. Absent = open start. */
1825
- start?: null | components["schemas"]["ShiftEnd"];
2370
+ start?: null | components["schemas"]["ShiftPlace"];
1826
2371
  /**
1827
2372
  * Format: date-time
1828
2373
  * @description Shift end (RFC 3339 instant, UTC offset required; hard unless `max_overtime_s` set). The
@@ -1831,40 +2376,11 @@ export interface components {
1831
2376
  */
1832
2377
  to: string;
1833
2378
  };
1834
- /**
1835
- * @description Where a shift starts or ends: exactly one of `location` or `depot`.
1836
- * @example {
1837
- * "depot": "gent"
1838
- * }
1839
- */
1840
- ShiftEnd: {
1841
- /**
1842
- * @description A `depots[].id`. Excludes `location`.
1843
- * @example gent
1844
- */
1845
- depot?: string | null;
1846
- /** @description An inline place. Excludes `depot`. */
1847
- location?: null | components["schemas"]["Place"];
1848
- /**
1849
- * Format: int32
1850
- * @description Handling time in seconds at this end: the morning load at `start`, the
1851
- * evening unload at `end`. Overrides the depot's `service_duration_s`;
1852
- * default: the depot's value, or 0 for a `location` end. Not applied on
1853
- * an ignored leg (`ignore_start_leg`/`ignore_end_leg`). Not scaled by
1854
- * `service_factor`.
1855
- *
1856
- * The unload must finish by the shift's `to` (or `to + max_overtime_s`):
1857
- * a route whose unload would run past it is infeasible. A shift whose
1858
- * load and unload alone exceed it is rejected with HTTP 400.
1859
- * @example 600
1860
- */
1861
- service_duration_s?: number | null;
1862
- };
1863
2379
  /**
1864
2380
  * @description Per-shift limits: the route-level `limits` fields a shift may override.
1865
2381
  * Period limits apply across shifts, so they stay on the vehicle.
1866
2382
  * @example {
1867
- * "max_tasks": 12
2383
+ * "max_stops": 12
1868
2384
  * }
1869
2385
  */
1870
2386
  ShiftLimits: {
@@ -1884,12 +2400,42 @@ export interface components {
1884
2400
  max_route_duration_s?: number | null;
1885
2401
  /**
1886
2402
  * Format: int32
1887
- * @description Maximum stops served in this shift: a job counts as one stop, a
1888
- * shipment as two (pickup and delivery).
2403
+ * @description Maximum stops served in this shift; a job counts as one stop.
2404
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
2405
+ * shipment counts as two stops.
1889
2406
  * @example 50
1890
2407
  */
1891
- max_tasks?: number | null;
2408
+ max_stops?: number | null;
1892
2409
  };
2410
+ /**
2411
+ * @description Where a shift starts or ends: exactly one of `location` or `depot`.
2412
+ * @example {
2413
+ * "depot": "gent"
2414
+ * }
2415
+ */
2416
+ ShiftPlace: {
2417
+ /**
2418
+ * @description A `depots[].id`. Excludes `location`.
2419
+ * @example gent
2420
+ */
2421
+ depot?: string | null;
2422
+ /** @description An inline place. Excludes `depot`. */
2423
+ location?: null | components["schemas"]["Place"];
2424
+ /**
2425
+ * Format: int32
2426
+ * @description Handling time in seconds at this end: the morning load at `start`, the
2427
+ * evening unload at `end`. Overrides the depot's `service_duration_s`;
2428
+ * default: the depot's value, or 0 for a `location` end. Not applied on
2429
+ * free travel (`free_start_travel`/`free_end_travel`). Not scaled by
2430
+ * `service_factor`.
2431
+ *
2432
+ * The unload must finish by the shift's `to` (or `to + max_overtime_s`):
2433
+ * a route whose unload would run past it is infeasible. A shift whose
2434
+ * load and unload alone exceed it is rejected with HTTP 400.
2435
+ * @example 600
2436
+ */
2437
+ service_duration_s?: number | null;
2438
+ } & (unknown | unknown);
1893
2439
  /**
1894
2440
  * @description A vehicle and one of its shifts: the key of a plan route.
1895
2441
  * @example {
@@ -1909,7 +2455,7 @@ export interface components {
1909
2455
  * Two stops served by one vehicle, pickup strictly before delivery, with
1910
2456
  * `load` carried on the vehicle between the two legs.
1911
2457
  *
1912
- * `drop_fee` and vehicle eligibility (`eligible_vehicles`, allow
2458
+ * `drop_cost` and vehicle eligibility (`eligible_vehicles`, allow
1913
2459
  * **and** exclude, any length) are fully supported and applied to both legs — a
1914
2460
  * shipment's pickup and delivery share one droppability/eligibility decision,
1915
2461
  * since one vehicle must serve both.
@@ -1942,36 +2488,36 @@ export interface components {
1942
2488
  * `preferences`, which charges the vehicles that did NOT get the task,
1943
2489
  * this prices the vehicle that did, so a task rated badly everywhere is
1944
2490
  * the first one dropped when capacity runs out. It lives in the cost tier,
1945
- * below `priority`, and adds to `preferences`, `drop_fee` and travel.
2491
+ * below `priority`, and adds to `preferences`, `drop_cost` and travel.
1946
2492
  * Not applied by decomposition: a problem that sets it solves monolithically.
1947
2493
  */
1948
2494
  assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
1949
2495
  /** @description Delivery leg (load off). */
1950
- delivery: components["schemas"]["Stop"];
2496
+ delivery: components["schemas"]["ShipmentStop"];
1951
2497
  /**
1952
2498
  * Format: double
1953
2499
  * @description Drop **price** — what leaving this task unserved costs you, in the same
1954
2500
  * currency as `objective.costs`, and the only way to make a task
1955
- * droppable. Tasks without a `drop_fee` must be served.
2501
+ * droppable. Tasks without a `drop_cost` must be served.
1956
2502
  *
1957
2503
  * This is money, not a priority: it enters the same cost the solver
1958
2504
  * minimises, so the task is served only while serving it costs less than
1959
- * the fee. Fees the plan chose to pay are reported in
1960
- * `score.components.drop_fees` and summed into `score.cost`.
2505
+ * dropping it. Drop costs the plan chose to pay are reported in
2506
+ * `score.components.drop_costs` and summed into `score.cost`.
1961
2507
  *
1962
- * On a shipment the fee applies to the pair, charged once.
2508
+ * On a shipment the drop cost applies to the pair, charged once.
1963
2509
  *
1964
2510
  * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
1965
2511
  * is rejected with HTTP 400 (`conflicting_fields`).
1966
2512
  * @example 25
1967
2513
  */
1968
- drop_fee?: number | null;
2514
+ drop_cost?: number | null;
1969
2515
  /**
1970
2516
  * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
1971
2517
  * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
1972
2518
  * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
1973
2519
  */
1974
- eligible_vehicles?: null | components["schemas"]["Eligibility"];
2520
+ eligible_vehicles?: null | components["schemas"]["VehicleEligibility"];
1975
2521
  /**
1976
2522
  * @description Shipment id: 1 to 128 characters, unique across `jobs` + `shipments`.
1977
2523
  * @example ship-1
@@ -1982,82 +2528,47 @@ export interface components {
1982
2528
  * the same quantity dropped off at the other. Non-negative magnitudes
1983
2529
  * per named dimension.
1984
2530
  */
1985
- load?: null | components["schemas"]["BTreeMap"];
1986
- /**
1987
- * @description Hard-pin this job to one vehicle id — only that vehicle (any of its
1988
- * shifts) may serve it, and once placed, re-optimization never removes it
1989
- * or moves it to another vehicle. Stronger than `eligible_vehicles`
1990
- * (which filters a set) and hard, unlike `preferences`.
1991
- *
1992
- * A pin means "stays on this vehicle if placed", **not** "must be
1993
- * served": the task can still end up unassigned (for example when it does
1994
- * not fit), and with a `drop_fee` it then pays the fee. An id that
1995
- * matches no vehicle is rejected with HTTP 400.
1996
- * @example vehicle-1
1997
- */
1998
- locked_vehicle?: string | null;
2531
+ load?: null | components["schemas"]["Quantities"];
1999
2532
  /** @description Pickup leg (load on). */
2000
- pickup: components["schemas"]["Stop"];
2533
+ pickup: components["schemas"]["ShipmentStop"];
2001
2534
  /**
2002
2535
  * @description Soft vehicle affinity preferences, priced. Each entry is independent:
2003
2536
  * a job listing several preferred vehicles it doesn't get pays each
2004
2537
  * one's `violation_cost` (compounding, the same rule as a vehicle's
2005
2538
  * `preferred_tags`).
2006
2539
  */
2007
- preferences?: components["schemas"]["Preference"][] | null;
2008
- /**
2009
- * Format: date-time
2010
- * @description Soft preference for the calendar day this task is served on, in a
2011
- * multi-day (multi-shift) problem.
2012
- *
2013
- * An RFC 3339 datetime, UTC offset required, on the intended day. A day is the calendar date of
2014
- * the value **in its own UTC offset**, the same rule that dates a shift
2015
- * from its `from`, so passing the target shift's `from` verbatim is
2016
- * always correct.
2017
- *
2018
- * Soft, and priced by `objective.non_preferred_date_cost` — a flat charge
2019
- * applied once to a task served on any other day. **With that cost unset or
2020
- * zero this field has no effect.** The charge is part of `score.cost`,
2021
- * which ranks below serving required tasks, so a task is never left
2022
- * unassigned to honour its preferred date; `locked_vehicle` (hard) also
2023
- * still wins.
2024
- *
2025
- * Supported on shipments as well as jobs. Both legs of a shipment ride
2026
- * the same route, so the preferred day is a property of the pair: set it
2027
- * on the shipment itself, and `non_preferred_date_cost` is charged once
2028
- * for the pair rather than once per leg.
2029
- * @example 2026-08-04T08:00:00+02:00
2030
- */
2031
- preferred_date?: string | null;
2540
+ preferences?: components["schemas"]["VehiclePreference"][] | null;
2032
2541
  /**
2033
2542
  * Format: int32
2034
2543
  * @description Importance of a must-serve task when not all of them fit: the solver
2035
2544
  * maximises the summed `priority` of served tasks before any cost. `>= 1`,
2036
2545
  * default `1` (maximise the count). A rank, not money — it never makes a
2037
- * task droppable; use `drop_fee` for that. Both set is a 400.
2546
+ * task droppable; use `drop_cost` for that. Both set is a 400.
2038
2547
  * @example 3
2039
2548
  */
2040
2549
  priority?: number | null;
2041
- /**
2042
- * @description Per-vehicle work-rate overrides for this task's `service_duration_s`,
2043
- * composed multiplicatively with the serving vehicle's or shift's
2044
- * `service_factor`. On a shipment the override scales both legs. A
2045
- * vehicle not listed works at its own rate.
2046
- */
2047
- service_factors?: components["schemas"]["ServiceFactor"][] | null;
2048
2550
  /**
2049
2551
  * @description Hard skill requirements — the assigned vehicle must provide every one,
2050
2552
  * at or above each requirement's `min_level`. A request may use at most
2051
2553
  * 256 distinct `(name, min_level)` pairs across all jobs and shipments
2052
2554
  * (HTTP 400 `limit_exceeded` beyond that).
2053
2555
  */
2054
- skills?: components["schemas"]["SkillReq"][] | null;
2556
+ required_skills?: components["schemas"]["SkillRequirement"][] | null;
2557
+ /**
2558
+ * @description Per-vehicle work-rate factors for this task's `service_duration_s`,
2559
+ * which is DIVIDED by the factor (above `1` = faster). Each multiplies
2560
+ * the serving vehicle's rate (the shift's `service_factor` if set, else
2561
+ * the vehicle's): effective service time = `service_duration_s /
2562
+ * (shift_or_vehicle_factor * factor)`. On a shipment the factor scales
2563
+ * both legs. A vehicle not listed works at its own rate.
2564
+ */
2565
+ service_factors?: components["schemas"]["ServiceFactor"][] | null;
2055
2566
  /**
2056
- * @description Free-form task labels (zones/territories, grouping/relation labels).
2567
+ * @description Free-form task labels (zones/territories, relation labels).
2057
2568
  * Used for `tag`/relation resolution and, when a shift scopes itself via
2058
2569
  * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
2059
2570
  * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
2060
- * `skills`, which requires ALL. Not capability matching on its own.
2571
+ * `required_skills`, which requires ALL. Not capability matching on its own.
2061
2572
  * A request may carry at most 256 distinct tags across all jobs and
2062
2573
  * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
2063
2574
  * lists do not count.
@@ -2069,13 +2580,70 @@ export interface components {
2069
2580
  */
2070
2581
  target?: null | components["schemas"]["Target"];
2071
2582
  };
2583
+ /**
2584
+ * @description One leg of a shipment (pickup or delivery).
2585
+ * @example {
2586
+ * "id": "ship-1:pickup",
2587
+ * "location": [
2588
+ * 3.725,
2589
+ * 51.05
2590
+ * ],
2591
+ * "service_duration_s": 300,
2592
+ * "setup_duration_s": 60,
2593
+ * "time_windows": [
2594
+ * {
2595
+ * "from": "2026-07-01T09:00:00+02:00",
2596
+ * "to": "2026-07-01T12:00:00+02:00"
2597
+ * }
2598
+ * ]
2599
+ * }
2600
+ */
2601
+ ShipmentStop: {
2602
+ /**
2603
+ * @description Stop id: 1 to 128 characters when set. Defaults to
2604
+ * `"{shipment}:pickup"` / `"{shipment}:delivery"`. The effective id
2605
+ * (custom or default) must be unique across all job, shipment, and stop
2606
+ * ids — a collision is rejected with HTTP 400.
2607
+ * @example ship-1:pickup
2608
+ */
2609
+ id?: string | null;
2610
+ /** @description Where this stop happens. */
2611
+ location: components["schemas"]["Place"];
2612
+ /**
2613
+ * Format: int32
2614
+ * @description On-site service time paid per job (seconds).
2615
+ *
2616
+ * This is the nominal figure. The serving vehicle's `service_factor`
2617
+ * scales it — the time actually scheduled is
2618
+ * `service_duration_s / service_factor` — so the solution's
2619
+ * `stops[].service_s` may differ from what you sent here. Default `0`;
2620
+ * a negative value is rejected with HTTP 400.
2621
+ * @example 300
2622
+ */
2623
+ service_duration_s?: number | null;
2624
+ /**
2625
+ * Format: int32
2626
+ * @description Setup time paid once on arrival at a new location (seconds),
2627
+ * distinct from `service_duration_s`. Skipped when the immediate real
2628
+ * predecessor in the route already sits at this location — co-located
2629
+ * stops share one setup.
2630
+ *
2631
+ * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
2632
+ * overhead (parking, walking to the door), not the work itself.
2633
+ * Default `0`; a negative value is rejected with HTTP 400.
2634
+ * @example 60
2635
+ */
2636
+ setup_duration_s?: number | null;
2637
+ /** @description Time windows for this stop. */
2638
+ time_windows?: components["schemas"]["TimeWindow"][] | null;
2639
+ };
2072
2640
  /**
2073
2641
  * @description A hard skill requirement — the assigned vehicle must provide it.
2074
2642
  * @example {
2075
2643
  * "name": "fridge"
2076
2644
  * }
2077
2645
  */
2078
- SkillReq: {
2646
+ SkillRequirement: {
2079
2647
  /**
2080
2648
  * Format: int32
2081
2649
  * @description Minimum level the serving vehicle must hold for this skill (`>= 1`).
@@ -2092,7 +2660,7 @@ export interface components {
2092
2660
  /**
2093
2661
  * @description Solve options.
2094
2662
  * @example {
2095
- * "polylines": "full",
2663
+ * "polyline": "full",
2096
2664
  * "seed": 42,
2097
2665
  * "time_limit_s": 5
2098
2666
  * }
@@ -2100,15 +2668,17 @@ export interface components {
2100
2668
  SolveOptions: {
2101
2669
  /**
2102
2670
  * @description Return road geometry for each route as `routes[].polyline`:
2103
- * `simplified` or `full`. Omitted → no geometry (the default).
2671
+ * `simplified` or `full`. Omitted → no geometry (the default). One value
2672
+ * for the whole request, named like the response field it fills.
2104
2673
  */
2105
- polylines?: null | components["schemas"]["PolylineDetail"];
2674
+ polyline?: null | components["schemas"]["PolylineDetail"];
2106
2675
  /**
2107
2676
  * Format: int64
2108
2677
  * @description Random seed for the search. Default `42`: omitting it is the same as
2109
2678
  * sending `42`, so send different values to explore different plans.
2110
2679
  * Repeated runs on one machine usually return an identical plan; a
2111
2680
  * materially faster or slower machine can differ.
2681
+ * @default 42
2112
2682
  * @example 42
2113
2683
  */
2114
2684
  seed?: number | null;
@@ -2128,6 +2698,7 @@ export interface components {
2128
2698
  * overload): `estimate` (the default) solves on estimated travel and
2129
2699
  * sets `summary.travel_estimated`; `fail` returns the 502/503
2130
2700
  * instead. A request Maps rejects as invalid always fails.
2701
+ * @default estimate
2131
2702
  */
2132
2703
  travel_fallback?: null | components["schemas"]["TravelFallback"];
2133
2704
  };
@@ -2155,15 +2726,15 @@ export interface components {
2155
2726
  * 3.725,
2156
2727
  * 51.05
2157
2728
  * ],
2158
- * "pickup": {
2729
+ * "pickup_load": {
2159
2730
  * "weight": 20
2160
2731
  * },
2161
- * "service_duration_s": 300,
2162
- * "skills": [
2732
+ * "required_skills": [
2163
2733
  * {
2164
2734
  * "name": "fridge"
2165
2735
  * }
2166
2736
  * ],
2737
+ * "service_duration_s": 300,
2167
2738
  * "time_windows": [
2168
2739
  * {
2169
2740
  * "from": "2026-07-01T09:00:00+02:00",
@@ -2177,7 +2748,7 @@ export interface components {
2177
2748
  * 3.71,
2178
2749
  * 51.06
2179
2750
  * ],
2180
- * "pickup": {
2751
+ * "pickup_load": {
2181
2752
  * "weight": 35
2182
2753
  * },
2183
2754
  * "service_duration_s": 600
@@ -2236,7 +2807,7 @@ export interface components {
2236
2807
  */
2237
2808
  plan?: null | components["schemas"]["Plan"];
2238
2809
  /** @description The problem: tasks, fleet, depots, relations, objective, travel. */
2239
- problem: components["schemas"]["ProblemInput"];
2810
+ problem: components["schemas"]["Problem"];
2240
2811
  };
2241
2812
  /**
2242
2813
  * @description The result of `POST /v3/routing/solve` and `POST /v3/routing/evaluate`:
@@ -2296,6 +2867,7 @@ export interface components {
2296
2867
  * 51.05
2297
2868
  * ],
2298
2869
  * "service_s": 300,
2870
+ * "service_start": "2026-07-01T09:00:00+02:00",
2299
2871
  * "travel_s": 600,
2300
2872
  * "type": "job",
2301
2873
  * "wait_s": 3000
@@ -2314,6 +2886,7 @@ export interface components {
2314
2886
  * 51.06
2315
2887
  * ],
2316
2888
  * "service_s": 600,
2889
+ * "service_start": "2026-07-01T09:13:00+02:00",
2317
2890
  * "travel_s": 480,
2318
2891
  * "type": "job",
2319
2892
  * "wait_s": 0
@@ -2332,7 +2905,8 @@ export interface components {
2332
2905
  * ],
2333
2906
  * "service_s": 0,
2334
2907
  * "travel_s": 900,
2335
- * "type": "end"
2908
+ * "type": "end",
2909
+ * "wait_s": 0
2336
2910
  * }
2337
2911
  * ],
2338
2912
  * "time": {
@@ -2351,14 +2925,15 @@ export interface components {
2351
2925
  * "distance_m": 8450,
2352
2926
  * "score": {
2353
2927
  * "components": {
2354
- * "depot_visits": 0,
2928
+ * "assignment": 0,
2355
2929
  * "distance": 1.69,
2356
- * "drop_fees": 0,
2357
- * "fixed": 0,
2930
+ * "drop_costs": 0,
2358
2931
  * "grouping": 0,
2359
2932
  * "lateness": 0,
2360
- * "other": 0,
2361
2933
  * "overtime": 0,
2934
+ * "preferences": 0,
2935
+ * "reloads": 0,
2936
+ * "routes": 0,
2362
2937
  * "tag_preference": 0,
2363
2938
  * "target": 0,
2364
2939
  * "time": 57.1536,
@@ -2368,14 +2943,18 @@ export interface components {
2368
2943
  * },
2369
2944
  * "cost": 58.8436,
2370
2945
  * "currency": "EUR",
2371
- * "unserved_priority": 0,
2372
- * "violations": 0
2946
+ * "unassigned_priority": 0,
2947
+ * "violation_count": 0
2948
+ * },
2949
+ * "search": {
2950
+ * "iterations": 48210,
2951
+ * "termination": "time_limit"
2373
2952
  * },
2374
2953
  * "shifts_used": 1,
2375
2954
  * "tasks": {
2376
2955
  * "served": 2,
2377
- * "unserved": 0,
2378
- * "unserved_required": 0
2956
+ * "unassigned": 0,
2957
+ * "unassigned_required": 0
2379
2958
  * },
2380
2959
  * "time": {
2381
2960
  * "break_s": 0,
@@ -2392,7 +2971,8 @@ export interface components {
2392
2971
  * },
2393
2972
  * "vehicles_used": 1
2394
2973
  * },
2395
- * "unassigned": []
2974
+ * "unassigned": [],
2975
+ * "warnings": []
2396
2976
  * }
2397
2977
  */
2398
2978
  SolveResponse: {
@@ -2406,279 +2986,88 @@ export interface components {
2406
2986
  /** @description Aggregate statistics for the solve run. */
2407
2987
  summary: components["schemas"]["Summary"];
2408
2988
  /** @description Tasks that could not be feasibly assigned. */
2409
- unassigned: components["schemas"]["Unassigned"][];
2989
+ unassigned: components["schemas"]["UnassignedTask"][];
2990
+ /**
2991
+ * @description Inputs the request carried that changed nothing. Always present,
2992
+ * empty when there are none (no input produces one today); at most 100
2993
+ * are returned. Each item has a `code`, a `pointer` to the field and a
2994
+ * `message`. Accept codes you do not know.
2995
+ */
2996
+ warnings: components["schemas"]["RequestIssue"][];
2410
2997
  };
2411
2998
  /**
2412
- * @description One leg of a shipment (pickup or delivery).
2999
+ * @description The kind of a stop in a route.
3000
+ *
3001
+ * Every route has one `start` and one `end`. A served job is `job`, and a
3002
+ * shipment's legs are `pickup` and `delivery`. A driver break is `break`,
3003
+ * and a mid-shift reload at a depot is `reload`.
3004
+ *
3005
+ * Known values: `start`, `job`, `pickup`, `delivery`, `break`, `reload`, `end`. An open set: a later release may add values, so accept any string and handle the ones you know.
3006
+ * @example job
3007
+ */
3008
+ StopType: string;
3009
+ /**
3010
+ * @description Suggest options.
2413
3011
  * @example {
2414
- * "id": "ship-1:pickup",
2415
- * "location": [
2416
- * 3.725,
2417
- * 51.05
2418
- * ],
2419
- * "service_duration_s": 300,
2420
- * "setup_duration_s": 60,
2421
- * "time_windows": [
2422
- * {
2423
- * "from": "2026-07-01T09:00:00+02:00",
2424
- * "to": "2026-07-01T12:00:00+02:00"
2425
- * }
2426
- * ]
3012
+ * "max_insertions": 5,
3013
+ * "time_limit_s": 2
2427
3014
  * }
2428
3015
  */
2429
- Stop: {
2430
- /**
2431
- * @description Whether a break may interrupt service here. Default `true`. `false`
2432
- * is not supported yet and is rejected with HTTP 400.
2433
- * @example true
2434
- */
2435
- break_interruptible?: boolean | null;
2436
- /**
2437
- * @description Stop id: 1 to 128 characters when set. Defaults to
2438
- * `"{shipment}:pickup"` / `"{shipment}:delivery"`. The effective id
2439
- * (custom or default) must be unique across all job, shipment, and stop
2440
- * ids — a collision is rejected with HTTP 400.
2441
- * @example ship-1:pickup
2442
- */
2443
- id?: string | null;
2444
- /** @description Where this stop happens. */
2445
- location: components["schemas"]["Place"];
3016
+ SuggestOptions: {
2446
3017
  /**
2447
3018
  * Format: int32
2448
- * @description On-site service time paid per job (seconds).
2449
- *
2450
- * This is the nominal figure. The serving vehicle's `service_factor`
2451
- * scales it — the time actually scheduled is
2452
- * `service_duration_s / service_factor` — so the solution's
2453
- * `stops[].service_s` may differ from what you sent here. Default `0`;
2454
- * a negative value is rejected with HTTP 400.
2455
- * @example 300
3019
+ * @description Max ranked `insertions` in each `suggestions[]` entry, `1` to `10`;
3020
+ * default 5. It caps the insertions per entry, not the number of
3021
+ * entries: every task outside `plan` still gets its entry. Values outside
3022
+ * the range are a 400, never clamped. It also sets the search's beam
3023
+ * width, `max(8, 4 × max_insertions)`: for a unit of several stops, which
3024
+ * is never searched exhaustively, each stop after the unit's first keeps
3025
+ * at most that many partial placements. A single-stop task has every
3026
+ * feasible position considered unless `time_limit_s` runs out first.
3027
+ * @default 5
3028
+ * @example 5
2456
3029
  */
2457
- service_duration_s?: number | null;
3030
+ max_insertions?: number | null;
2458
3031
  /**
2459
- * Format: int32
2460
- * @description Setup time paid once on arrival at a new location (seconds),
2461
- * distinct from `service_duration_s`. Skipped when the immediate real
2462
- * predecessor in the route already sits at this location — co-located
2463
- * stops share one setup.
2464
- *
2465
- * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
2466
- * overhead (parking, walking to the door), not the work itself.
2467
- * Default `0`; a negative value is rejected with HTTP 400.
2468
- * @example 60
3032
+ * Format: double
3033
+ * @description Search budget in seconds, fractions allowed (default 1; minimum 0.1 —
3034
+ * smaller values are raised to it; maximum 60). The clock
3035
+ * starts when the search starts, after the matrix fetch and any wait for a
3036
+ * solver slot. Units are searched in problem order (jobs, then
3037
+ * shipments), each with an equal share of the time left when it starts; a
3038
+ * unit that finishes early leaves its slack to the ones after it.
3039
+ * @default 1
3040
+ * @example 2.5
2469
3041
  */
2470
- setup_duration_s?: number | null;
2471
- /** @description Time windows for this stop. */
2472
- time_windows?: components["schemas"]["TimeWindow"][] | null;
3042
+ time_limit_s?: number | null;
2473
3043
  };
2474
3044
  /**
2475
- * @description Which instant of a stop a `target` or a relation refers to. One vocabulary
2476
- * for both, each accepting the values that mean something there.
2477
- * @enum {string}
2478
- */
2479
- StopInstant: "arrival" | "start" | "end";
2480
- /**
2481
- * @description A single stop within a route.
3045
+ * @description Why a unit came back with no insertions.
2482
3046
  * @example {
2483
- * "arrival": "2026-07-01T08:10:00+02:00",
2484
- * "departure": "2026-07-01T09:05:00+02:00",
2485
- * "distance_m": 2600,
2486
- * "id": "job-1",
2487
- * "lateness_s": 0,
2488
- * "load_after": {
2489
- * "weight": 20
2490
- * },
2491
- * "location": [
2492
- * 3.725,
2493
- * 51.05
2494
- * ],
2495
- * "service_s": 300,
2496
- * "travel_s": 600,
2497
- * "type": "job",
2498
- * "wait_s": 3000
3047
+ * "code": "infeasible",
3048
+ * "message": "No feasible insertion position found"
2499
3049
  * }
2500
3050
  */
2501
- StopOutput: {
2502
- /**
2503
- * Format: date-time
2504
- * @description Physical arrival time (RFC 3339), before any waiting; the service
2505
- * start is `arrival + wait_s`. Every stop time is rendered in the UTC
2506
- * offset of the route's shift `from` (`Z` when that `from` is UTC or has
2507
- * no offset): a `+02:00` shift reports `2026-07-01T08:10:00+02:00`, the
2508
- * same instant as `2026-07-01T06:10:00Z`.
2509
- * @example 2026-07-01T08:10:00+02:00
2510
- */
2511
- arrival?: string | null;
3051
+ SuggestReason: {
3052
+ /** @description Branch on this. Open set; see [`SuggestReasonCode`]. */
3053
+ code: components["schemas"]["SuggestReasonCode"];
2512
3054
  /**
2513
- * Format: date-time
2514
- * @description Departure time (RFC 3339, in the offset of `arrival`).
2515
- * @example 2026-07-01T09:05:00+02:00
2516
- */
2517
- departure?: string | null;
2518
- /**
2519
- * @description The `depots[].id` of this stop: on a `start`/`end` stop whose shift end
2520
- * names a depot, and on every `reload` stop. Absent on a `location` or
2521
- * open end and on task and break stops.
2522
- * @example gent
3055
+ * @description `code` as an English sentence, for people and logs. Do not parse it.
3056
+ * @example No feasible insertion position found
2523
3057
  */
2524
- depot?: string | null;
2525
- /**
2526
- * Format: int32
2527
- * @description Travel distance from the previous stop, in metres.
2528
- * @example 2600
2529
- */
2530
- distance_m?: number | null;
2531
- /**
2532
- * Format: int32
2533
- * @description The part of `wait_s` spent holding for a `synchronized` or
2534
- * `time_lag` partner on another vehicle, beyond any wait the time
2535
- * window already imposed. Present on task stops only when non-zero.
2536
- * @example 0
2537
- */
2538
- hold_s?: number | null;
2539
- /**
2540
- * @description Stop id: the job id on a `job` stop, the leg's stop id on
2541
- * `pickup`/`delivery` (its own `id`, else `{shipment}:pickup` /
2542
- * `{shipment}:delivery`). Absent on start, end, break and reload stops.
2543
- * @example job-1
2544
- */
2545
- id?: string | null;
2546
- /**
2547
- * Format: int32
2548
- * @description Seconds late beyond the latest allowed arrival (`0` when on time).
2549
- * Measures the hard time window only; a soft target is reported in
2550
- * `target_lateness_s`.
2551
- * @example 0
2552
- */
2553
- lateness_s?: number | null;
2554
- /** @description Cumulative load carried after this stop, by named dimension. */
2555
- load_after?: null | components["schemas"]["BTreeMap"];
2556
- /**
2557
- * @description Stop location `[longitude, latitude]` (GeoJSON order). Absent on
2558
- * every `break` stop, including a break with a pinned location, and on
2559
- * `start`/`end` stops for a genuinely open leg (no configured depot
2560
- * coordinate for that end of the shift). A virtual (location-less) job
2561
- * has no coordinate of its own and reports its nearest located
2562
- * neighbor's instead, so it is absent only when the whole route is
2563
- * virtual with open depot ends.
2564
- * @example [
2565
- * 3.725,
2566
- * 51.05
2567
- * ]
2568
- */
2569
- location?: number[] | null;
2570
- /**
2571
- * Format: int32
2572
- * @description On-site service time at this stop, in seconds.
2573
- *
2574
- * The **effective** time, not the nominal `service_duration_s` from the
2575
- * request: on a task stop it already has the serving vehicle's
2576
- * `service_factor` applied. The timeline reconciles as
2577
- * `departure - arrival - wait_s == service_s` only when the stop pays no
2578
- * setup time; with `setup_duration_s` set, the difference is larger by
2579
- * the (unscaled) setup seconds. Depot, reload, and break stops report
2580
- * their own nominal handling/break duration, which `service_factor`
2581
- * never scales.
2582
- *
2583
- * On `start`/`end`: the depot handling time applied there (0 on an
2584
- * ignored leg); absent on an open end.
2585
- * @example 300
2586
- */
2587
- service_s?: number | null;
2588
- /**
2589
- * Format: date-time
2590
- * @description When service starts (RFC 3339, in the offset of `arrival`): after the
2591
- * arrival, any windowed
2592
- * break taken on arrival there, and the wait. Present on task and reload
2593
- * stops; absent on start, end and break stops.
2594
- * @example 2026-07-01T09:00:00+02:00
2595
- */
2596
- service_start?: string | null;
2597
- /** @description The same point snapped to the routable graph, when available. */
2598
- snapped_location?: number[] | null;
2599
- /**
2600
- * Format: int32
2601
- * @description Seconds past this task's `target.at`, measured at the stop's arrival
2602
- * or departure per `target.on`; `0` when met. Present only on a task
2603
- * stop carrying a target. A shipment's target is measured
2604
- * on its delivery leg, so it appears on the `:delivery` stop and never on
2605
- * the `:pickup` stop.
2606
- * @example 0
2607
- */
2608
- target_lateness_s?: number | null;
2609
- /**
2610
- * Format: int32
2611
- * @description Travel time from the previous stop, in seconds.
2612
- * @example 600
2613
- */
2614
- travel_s?: number | null;
2615
- /** @description What kind of stop this is. */
2616
- type: components["schemas"]["StopType"];
2617
- /**
2618
- * @description Constraint violations detected at this stop. Only populated by
2619
- * `POST /v3/routing/evaluate` (imported solutions may be infeasible); a
2620
- * solve response never emits violations, so this is absent there.
2621
- */
2622
- violations?: components["schemas"]["Violation"][];
2623
- /**
2624
- * Format: int32
2625
- * @description Seconds spent waiting here before service: for the time window to
2626
- * open, and for any cross-route hold (`hold_s`, included in this
2627
- * figure).
2628
- * @example 3000
2629
- */
2630
- wait_s?: number | null;
2631
- };
2632
- /**
2633
- * @description The kind of a stop in a route.
2634
- *
2635
- * Every route has one `start` and one `end`. A served job is `job`, and a
2636
- * shipment's legs are `pickup` and `delivery`. A driver break is `break`,
2637
- * and a mid-shift reload at a depot is `reload`.
2638
- * @example job
2639
- * @enum {string}
2640
- */
2641
- StopType: "start" | "job" | "pickup" | "delivery" | "break" | "reload" | "end";
2642
- /**
2643
- * @description Suggest options.
2644
- * @example {
2645
- * "max_suggestions": 5,
2646
- * "time_limit_s": 2
2647
- * }
2648
- */
2649
- SuggestOptions: {
2650
- /**
2651
- * @description Max ranked options per task. Default 5; positive values are clamped
2652
- * to `1..=100`; `0` lifts the cap. It also bounds the search for a unit
2653
- * of several stops, and that search is never exhaustive: even with `0`,
2654
- * each stop after the unit's first keeps at most the 40 most promising
2655
- * partial placements. A single-stop task has every feasible position
2656
- * considered unless `time_limit_s` runs out first.
2657
- * @example 5
2658
- */
2659
- max_suggestions?: number | null;
2660
- /**
2661
- * Format: double
2662
- * @description Search budget in seconds, fractions allowed (default 1; minimum 0.1 —
2663
- * smaller values are raised to it; maximum 60). The clock
2664
- * starts when the search starts, after the matrix fetch and any wait for a
2665
- * solver slot. Units are searched in problem order (jobs, then
2666
- * shipments), each with an equal share of the time left when it starts; a
2667
- * unit that finishes early leaves its slack to the ones after it.
2668
- * @example 2.5
2669
- */
2670
- time_limit_s?: number | null;
3058
+ message: string;
2671
3059
  };
2672
3060
  /**
2673
3061
  * @description Why a unit's `insertions` is empty: the machine-readable form of
2674
3062
  * `reason`, to branch on.
2675
3063
  *
2676
3064
  * Open set: values may be added within `/v3`. Accept values not listed here
2677
- * and handle them generically, for example by showing `reason`.
3065
+ * and handle them generically, for example by showing `reason.message`.
3066
+ *
3067
+ * Known values: `time_limit`, `candidates_exhausted`, `infeasible`. An open set: a later release may add values, so accept any string and handle the ones you know.
2678
3068
  * @example infeasible
2679
- * @enum {string}
2680
3069
  */
2681
- SuggestReasonCode: "time_limit" | "candidates_exhausted" | "infeasible";
3070
+ SuggestReasonCode: string;
2682
3071
  /**
2683
3072
  * @description Request body for `POST /v3/routing/suggest`.
2684
3073
  *
@@ -2691,7 +3080,7 @@ export interface components {
2691
3080
  * committed plan; the plan is never modified.
2692
3081
  * @example {
2693
3082
  * "options": {
2694
- * "max_suggestions": 5
3083
+ * "max_insertions": 5
2695
3084
  * },
2696
3085
  * "plan": {
2697
3086
  * "routes": [
@@ -2715,7 +3104,7 @@ export interface components {
2715
3104
  * 3.725,
2716
3105
  * 51.05
2717
3106
  * ],
2718
- * "pickup": {
3107
+ * "pickup_load": {
2719
3108
  * "weight": 10
2720
3109
  * },
2721
3110
  * "service_duration_s": 300
@@ -2726,7 +3115,7 @@ export interface components {
2726
3115
  * 3.71,
2727
3116
  * 51.06
2728
3117
  * ],
2729
- * "pickup": {
3118
+ * "pickup_load": {
2730
3119
  * "weight": 10
2731
3120
  * },
2732
3121
  * "service_duration_s": 300
@@ -2774,12 +3163,11 @@ export interface components {
2774
3163
  * @description Problem definition — identical to `POST /v3/routing/solve`. Every task
2775
3164
  * of it that is not in `plan` is a task to place.
2776
3165
  */
2777
- problem: components["schemas"]["ProblemInput"];
3166
+ problem: components["schemas"]["Problem"];
2778
3167
  };
2779
3168
  /**
2780
3169
  * @description Response body for `POST /v3/routing/suggest`.
2781
3170
  * @example {
2782
- * "elapsed_ms": 8,
2783
3171
  * "suggestions": [
2784
3172
  * {
2785
3173
  * "insertions": [
@@ -2787,7 +3175,7 @@ export interface components {
2787
3175
  * "delta": {
2788
3176
  * "cost": 12.4,
2789
3177
  * "distance_m": 2400,
2790
- * "duration_s": 240
3178
+ * "travel_s": 240
2791
3179
  * },
2792
3180
  * "placements": [
2793
3181
  * {
@@ -2817,34 +3205,43 @@ export interface components {
2817
3205
  * ]
2818
3206
  * }
2819
3207
  * ],
2820
- * "job_id": "job-2"
3208
+ * "task": "job-2"
2821
3209
  * }
2822
3210
  * ],
2823
- * "truncated": false
3211
+ * "timings": {
3212
+ * "total_ms": 8
3213
+ * },
3214
+ * "truncated": false,
3215
+ * "warnings": []
2824
3216
  * }
2825
3217
  */
2826
3218
  SuggestResponse: {
2827
- /**
2828
- * Format: int64
2829
- * @description Wall-clock time taken by the request, in milliseconds.
2830
- * @example 8
2831
- */
2832
- elapsed_ms: number;
2833
3219
  /**
2834
3220
  * @description One entry per unit of tasks outside `plan`, in problem order (jobs,
2835
3221
  * then shipments; a relation group sorts at its first-listed member).
2836
3222
  */
2837
- suggestions: components["schemas"]["JobSuggestions"][];
3223
+ suggestions: components["schemas"]["TaskSuggestions"][];
3224
+ /**
3225
+ * @description Where the request's wall-clock time went. Only `total_ms` is set:
3226
+ * suggest has no separate search figure.
3227
+ */
3228
+ timings: components["schemas"]["Timings"];
2838
3229
  /**
2839
3230
  * @description `true` when `options.time_limit_s` cut the search short, or a
2840
3231
  * multi-member unit came back empty after the search had discarded
2841
- * candidates (an inconclusive "not found"; its `reason_code` is
3232
+ * candidates (an inconclusive "not found"; its `reason.code` is
2842
3233
  * `candidates_exhausted`). Lists may then be incomplete or missing the
2843
3234
  * best insertion. A single visit's only level is never pruned, so its
2844
3235
  * empty list is proof of infeasibility unless the budget cut it, and its
2845
- * `reason_code` is then `time_limit`.
3236
+ * `reason.code` is then `time_limit`.
3237
+ */
3238
+ truncated: boolean;
3239
+ /**
3240
+ * @description Inputs the request carried that changed nothing, as on a solve
3241
+ * response. Always present, empty when there are none; at most 100 are
3242
+ * returned.
2846
3243
  */
2847
- truncated?: boolean;
3244
+ warnings: components["schemas"]["RequestIssue"][];
2848
3245
  };
2849
3246
  /**
2850
3247
  * @description The plan in numbers: its score, what it serves and what it takes.
@@ -2852,14 +3249,15 @@ export interface components {
2852
3249
  * "distance_m": 8450,
2853
3250
  * "score": {
2854
3251
  * "components": {
2855
- * "depot_visits": 0,
3252
+ * "assignment": 0,
2856
3253
  * "distance": 1.69,
2857
- * "drop_fees": 0,
2858
- * "fixed": 0,
3254
+ * "drop_costs": 0,
2859
3255
  * "grouping": 0,
2860
3256
  * "lateness": 0,
2861
- * "other": 0,
2862
3257
  * "overtime": 0,
3258
+ * "preferences": 0,
3259
+ * "reloads": 0,
3260
+ * "routes": 0,
2863
3261
  * "tag_preference": 0,
2864
3262
  * "target": 0,
2865
3263
  * "time": 57.1536,
@@ -2869,14 +3267,18 @@ export interface components {
2869
3267
  * },
2870
3268
  * "cost": 58.8436,
2871
3269
  * "currency": "EUR",
2872
- * "unserved_priority": 0,
2873
- * "violations": 0
3270
+ * "unassigned_priority": 0,
3271
+ * "violation_count": 0
3272
+ * },
3273
+ * "search": {
3274
+ * "iterations": 48210,
3275
+ * "termination": "time_limit"
2874
3276
  * },
2875
3277
  * "shifts_used": 1,
2876
3278
  * "tasks": {
2877
3279
  * "served": 2,
2878
- * "unserved": 0,
2879
- * "unserved_required": 0
3280
+ * "unassigned": 0,
3281
+ * "unassigned_required": 0
2880
3282
  * },
2881
3283
  * "time": {
2882
3284
  * "break_s": 0,
@@ -2902,10 +3304,12 @@ export interface components {
2902
3304
  */
2903
3305
  distance_m: number;
2904
3306
  /**
2905
- * @description How good the plan is. On `/solve`, `score.violations` is always 0; on
3307
+ * @description How good the plan is. On `/solve`, `score.violation_count` is always 0; on
2906
3308
  * `/evaluate` it counts the constraints the given plan breaks.
2907
3309
  */
2908
3310
  score: components["schemas"]["Score"];
3311
+ /** @description How the search ended. */
3312
+ search: components["schemas"]["SearchInfo"];
2909
3313
  /**
2910
3314
  * Format: int32
2911
3315
  * @description Routes with at least one task stop: one per used shift.
@@ -2923,7 +3327,7 @@ export interface components {
2923
3327
  * on estimated travel: straight-line distance × a detour factor, at a
2924
3328
  * typical speed for the profile. No one-way streets or traffic, so it
2925
3329
  * can be tens of percent off: the plan, `unassigned[].reasons` and
2926
- * `score.violations` hold only against it, and no `routes[].polyline` is
3330
+ * `score.violation_count` hold only against it, and no `routes[].polyline` is
2927
3331
  * returned. Solve again once Maps is back if the plan must hold on the
2928
3332
  * road; `options.travel_fallback: "fail"` returns the error instead.
2929
3333
  * Absent when travel is road-routed, and always absent on `/evaluate`,
@@ -2978,9 +3382,10 @@ export interface components {
2978
3382
  at: string;
2979
3383
  /**
2980
3384
  * @description Which instant of the task is compared to `at`: `arrival` (default) or
2981
- * `end`. `start` is rejected with HTTP 400.
3385
+ * `departure`, the stop fields of the same names.
3386
+ * @default arrival
2982
3387
  */
2983
- on?: null | components["schemas"]["StopInstant"];
3388
+ on?: null | components["schemas"]["TargetInstant"];
2984
3389
  /**
2985
3390
  * Format: double
2986
3391
  * @description Cost, in the objective's currency, per hour of `on` beyond `at`
@@ -2991,13 +3396,19 @@ export interface components {
2991
3396
  */
2992
3397
  per_late_hour: number;
2993
3398
  };
3399
+ /**
3400
+ * @description Which instant of a task a `target` is measured at, named after the
3401
+ * response stop field that reports it.
3402
+ * @enum {string}
3403
+ */
3404
+ TargetInstant: "arrival" | "departure";
2994
3405
  /**
2995
3406
  * @description How many tasks the plan serves. A job is one task; a shipment (pickup
2996
3407
  * plus delivery) is one task.
2997
3408
  * @example {
2998
3409
  * "served": 2,
2999
- * "unserved": 0,
3000
- * "unserved_required": 0
3410
+ * "unassigned": 0,
3411
+ * "unassigned_required": 0
3001
3412
  * }
3002
3413
  */
3003
3414
  TaskCounts: {
@@ -3010,29 +3421,90 @@ export interface components {
3010
3421
  * Format: int32
3011
3422
  * @description Tasks on no route: the length of `unassigned`.
3012
3423
  */
3013
- unserved: number;
3424
+ unassigned: number;
3014
3425
  /**
3015
3426
  * Format: int32
3016
- * @description The unserved tasks that carry no `drop_fee`: tasks the plan was
3427
+ * @description The unassigned tasks that carry no `drop_cost`: tasks the plan was
3017
3428
  * required to serve and did not.
3018
3429
  */
3019
- unserved_required: number;
3430
+ unassigned_required: number;
3431
+ };
3432
+ /**
3433
+ * @description Ranked insertion suggestions for a single unit.
3434
+ * @example {
3435
+ * "insertions": [
3436
+ * {
3437
+ * "delta": {
3438
+ * "cost": 12.4,
3439
+ * "distance_m": 2400,
3440
+ * "travel_s": 240
3441
+ * },
3442
+ * "placements": [
3443
+ * {
3444
+ * "arrival": "2026-07-01T09:30:00+02:00",
3445
+ * "id": "job-2",
3446
+ * "latest_arrival": "2026-07-01T10:15:00+02:00",
3447
+ * "shift": "mon",
3448
+ * "type": "job",
3449
+ * "vehicle": "v1"
3450
+ * }
3451
+ * ],
3452
+ * "routes": [
3453
+ * {
3454
+ * "shift": "mon",
3455
+ * "stops": [
3456
+ * {
3457
+ * "id": "job-1",
3458
+ * "type": "job"
3459
+ * },
3460
+ * {
3461
+ * "id": "job-2",
3462
+ * "type": "job"
3463
+ * }
3464
+ * ],
3465
+ * "vehicle": "v1"
3466
+ * }
3467
+ * ]
3468
+ * }
3469
+ * ],
3470
+ * "task": "job-2"
3471
+ * }
3472
+ */
3473
+ TaskSuggestions: {
3474
+ /**
3475
+ * @description Ranked feasible insertions, lowest `delta.cost` first. Empty if none
3476
+ * was found; `reason` then says why. Known limitation: suggest never
3477
+ * opens a **new reload trip** on a multi-trip vehicle.
3478
+ */
3479
+ insertions: components["schemas"]["InsertionOption"][];
3480
+ /** @description Why `insertions` is empty; absent otherwise. */
3481
+ reason?: null | components["schemas"]["SuggestReason"];
3482
+ /**
3483
+ * @description The unit's lead: its first member in placement order. That is the
3484
+ * visit, the shipment, the first stop of a `sequence` chain in the
3485
+ * unit, or else the member that comes first in problem order (`jobs`,
3486
+ * then `shipments`).
3487
+ * @example job-2
3488
+ */
3489
+ task: string;
3020
3490
  };
3021
3491
  /**
3022
3492
  * @description One end of a `time_lag` relation.
3023
3493
  * @example {
3024
- * "on": "end",
3494
+ * "on": "departure",
3025
3495
  * "stop": "job-1"
3026
3496
  * }
3027
3497
  */
3028
- TimeLagEnd: {
3498
+ TimeLagMember: {
3029
3499
  /**
3030
- * @description Which instant of the job the bound is measured at: `start` (default) or
3031
- * `end`. `arrival` is rejected with HTTP 400.
3500
+ * @description Which instant of the job the bound is measured at: `service_start`
3501
+ * (default) or `departure`, the stop fields of the same names.
3502
+ * @default service_start
3032
3503
  */
3033
- on?: null | components["schemas"]["StopInstant"];
3504
+ on?: null | components["schemas"]["RelationInstant"];
3034
3505
  /**
3035
- * @description A job id. A shipment or a shipment leg is rejected with HTTP 400.
3506
+ * @description The stop: a job id. A shipment's own id or a shipment-leg stop id is
3507
+ * rejected with HTTP 400.
3036
3508
  * @example job-1
3037
3509
  */
3038
3510
  stop: string;
@@ -3043,13 +3515,11 @@ export interface components {
3043
3515
  *
3044
3516
  * `span_s` is the wall-clock span, from the start stop's `arrival` to the
3045
3517
  * end stop's `departure`; it is what `per_route_hour` is charged on. The
3046
- * other fields break it down. They do not sum to `span_s` exactly: two
3047
- * parts of the span have no field of their own, setup time
3048
- * (`setup_duration_s`) and the idle before a windowed break's window opens
3049
- * (`wait_s` is measured after that break). And a `fixed` break that begins
3050
- * while the vehicle is driving overlaps that drive: the overlap is in both
3051
- * `travel_s` and `break_s`, so on such a route the parts can exceed
3052
- * `span_s`.
3518
+ * other fields break it down and sum to `span_s`, with two exceptions:
3519
+ * setup time (`setup_duration_s`) is inside the span with no field of its
3520
+ * own, and a `fixed` break that begins while the vehicle is driving
3521
+ * overlaps that drive: the overlap is in both `travel_s` and `break_s`, so
3522
+ * on such a route the parts can exceed `span_s`.
3053
3523
  * @example {
3054
3524
  * "break_s": 0,
3055
3525
  * "depot_s": 0,
@@ -3095,7 +3565,11 @@ export interface components {
3095
3565
  travel_s: number;
3096
3566
  /**
3097
3567
  * Format: int64
3098
- * @description Waiting before service, cross-route holds included.
3568
+ * @description Waiting before service, cross-route holds included, plus the idle
3569
+ * before a windowed break's window opens, at any stop. It is the sum of
3570
+ * the stops' `wait_s`, so it can exceed `score.components.waiting` and
3571
+ * what `per_wait_hour` charges for: that idle is priced only through
3572
+ * the span.
3099
3573
  */
3100
3574
  wait_s: number;
3101
3575
  };
@@ -3103,7 +3577,7 @@ export interface components {
3103
3577
  * @description A time window. Hard unless it (or `objective.per_late_hour`, for
3104
3578
  * every window) prices lateness.
3105
3579
  * @example {
3106
- * "cost": 15,
3580
+ * "choice_cost": 15,
3107
3581
  * "from": "2026-07-01T09:00:00+02:00",
3108
3582
  * "to": "2026-07-01T12:00:00+02:00"
3109
3583
  * }
@@ -3124,15 +3598,16 @@ export interface components {
3124
3598
  * `0`/absent has its overlapping windows merged).
3125
3599
  *
3126
3600
  * **Cannot be combined with `objective.per_late_hour > 0`** — a
3127
- * nonzero window `cost` anywhere in the request alongside priced lateness
3601
+ * nonzero `choice_cost` anywhere in the request alongside priced lateness
3128
3602
  * is rejected with HTTP 400 (the two read opposite ways about which
3129
3603
  * window was paid for). Choose one: priced alternative windows, or priced
3130
3604
  * lateness.
3131
3605
  */
3132
- cost?: number | null;
3606
+ choice_cost?: number | null;
3133
3607
  /**
3134
3608
  * Format: date-time
3135
- * @description Earliest allowed arrival (RFC 3339 instant, UTC offset required).
3609
+ * @description Earliest allowed start of service (RFC 3339 instant, UTC offset
3610
+ * required). A vehicle that arrives earlier waits.
3136
3611
  * @example 2026-07-01T09:00:00+02:00
3137
3612
  */
3138
3613
  from: string;
@@ -3149,7 +3624,9 @@ export interface components {
3149
3624
  per_late_hour?: number | null;
3150
3625
  /**
3151
3626
  * Format: date-time
3152
- * @description Latest allowed arrival (RFC 3339 instant, UTC offset required).
3627
+ * @description Latest allowed start of service (RFC 3339 instant, UTC offset
3628
+ * required), measured from arrival plus any windowed break taken first
3629
+ * (#1750 D1). Hard unless `per_late_hour` prices lateness.
3153
3630
  * @example 2026-07-01T12:00:00+02:00
3154
3631
  */
3155
3632
  to: string;
@@ -3164,14 +3641,16 @@ export interface components {
3164
3641
  Timings: {
3165
3642
  /**
3166
3643
  * Format: int64
3167
- * @description Time spent in the search. Absent on `/evaluate`, which runs none.
3644
+ * @description Time spent in the search. Absent on `/evaluate`, which runs none, and
3645
+ * on `/suggest`, which has no separate search figure.
3168
3646
  */
3169
3647
  search_ms?: number | null;
3170
3648
  /**
3171
3649
  * Format: int64
3172
3650
  * @description From the request's arrival to the end of the search (of the scoring,
3173
- * on `/evaluate`): fetching travel times and waiting for capacity
3174
- * included, building the response not.
3651
+ * on `/evaluate`; of the suggestion search, on `/suggest`): fetching
3652
+ * travel times and waiting for capacity included, building the response
3653
+ * not.
3175
3654
  */
3176
3655
  total_ms: number;
3177
3656
  };
@@ -3211,96 +3690,100 @@ export interface components {
3211
3690
  */
3212
3691
  TravelFallback: "estimate" | "fail";
3213
3692
  /**
3214
- * @description What a break trigger accumulates.
3693
+ * @description What a break trigger accumulates since the last break: `drive` counts
3694
+ * driving time only; `duty` counts travel, service and setup time, but not
3695
+ * waiting (for a time window to open or for a coupled task).
3215
3696
  * @example drive
3216
3697
  * @enum {string}
3217
3698
  */
3218
3699
  TriggerAfter: "drive" | "duty";
3219
3700
  /**
3220
- * @description A job the solver could not assign to any vehicle.
3701
+ * @description Which kind of "unassigned" a task is.
3702
+ *
3703
+ * Known values: `impossible`, `blocked`, `priced_out`, `time_limit`. An open set: a later release may add values, so accept any string and handle the ones you know.
3704
+ * @example priced_out
3705
+ */
3706
+ UnassignedCategory: string;
3707
+ /**
3708
+ * @description A machine-readable reason a task could not be assigned: the
3709
+ * `constraint` to blame, when one is, and a sentence.
3710
+ * @example {
3711
+ * "constraint": "time_window",
3712
+ * "message": "A route cannot reach this task within its time window"
3713
+ * }
3714
+ */
3715
+ UnassignedReason: {
3716
+ /**
3717
+ * @description The constraint that refused the task on at least one vehicle, in the
3718
+ * vocabulary of the evaluate violations' `code`. A task lists one reason
3719
+ * per constraint, once each, in [`ConstraintCode`] order. Absent on the
3720
+ * single reason of a `time_limit` or `priced_out` task, which names no
3721
+ * constraint.
3722
+ */
3723
+ constraint?: null | components["schemas"]["ConstraintCode"];
3724
+ /**
3725
+ * @description Human-readable explanation.
3726
+ * @example A route cannot reach this task within its time window
3727
+ */
3728
+ message: string;
3729
+ };
3730
+ /**
3731
+ * @description A task the plan leaves unassigned.
3221
3732
  * @example {
3222
3733
  * "category": "blocked",
3223
- * "job_id": "job-2",
3224
3734
  * "reasons": [
3225
3735
  * {
3226
- * "code": "TIME_WINDOW_VIOLATED",
3227
- * "message": "No vehicle can reach this job within its time window."
3736
+ * "constraint": "time_window",
3737
+ * "message": "A route cannot reach this task within its time window"
3228
3738
  * }
3229
3739
  * ],
3230
3740
  * "relaxations": [
3231
3741
  * {
3232
3742
  * "amount": 900,
3233
- * "field": "/jobs/job-2/time_windows",
3743
+ * "message": "Extend a time window by 900s (~15 min).",
3234
3744
  * "op": "extend_time_window",
3235
- * "suggestion": "Extend a time window by 900s (~15 min).",
3745
+ * "pointer": "/problem/jobs/1/time_windows",
3236
3746
  * "unit": "s"
3237
3747
  * }
3238
- * ]
3748
+ * ],
3749
+ * "task": "job-2"
3239
3750
  * }
3240
3751
  */
3241
- Unassigned: {
3752
+ UnassignedTask: {
3242
3753
  /** @description Which kind of "unassigned" this is. */
3243
- category?: components["schemas"]["UnassignedCategory"];
3754
+ category: components["schemas"]["UnassignedCategory"];
3244
3755
  /**
3245
- * @description The unassigned job id.
3246
- * @example job-2
3756
+ * @description Never empty. When `category` is `impossible` or `blocked` there is
3757
+ * one reason per constraint that refused the task on at least one
3758
+ * vehicle, named in `constraint`, once each, `unreachable` first
3759
+ * (`unknown` when no constraint was recorded). Otherwise there is one
3760
+ * reason with no `constraint`.
3247
3761
  */
3248
- job_id: string;
3249
- /** @description Structured reasons the job could not be served. */
3250
3762
  reasons: components["schemas"]["UnassignedReason"][];
3251
3763
  /**
3252
3764
  * @description Best-effort, actionable relaxation suggestions. Empty when no simple
3253
3765
  * relaxation exists (e.g. a skills mismatch).
3254
3766
  */
3255
3767
  relaxations: components["schemas"]["Relaxation"][];
3256
- };
3257
- /**
3258
- * @description Which kind of "unassigned" a task is.
3259
- * @example priced_out
3260
- * @enum {string}
3261
- */
3262
- UnassignedCategory: "impossible" | "blocked" | "priced_out" | "search_limit";
3263
- /**
3264
- * @description A machine-readable reason a task could not be assigned.
3265
- * @example {
3266
- * "code": "TIME_WINDOW_VIOLATED",
3267
- * "message": "No vehicle can reach this job within its time window."
3268
- * }
3269
- */
3270
- UnassignedReason: {
3271
- /**
3272
- * @description Stable machine code. Closed set of eleven values — exactly one of:
3273
- * `SOLVER_LIMIT` (a feasible slot existed but the time budget ran out),
3274
- * `CAPACITY_EXCEEDED`, `TIME_WINDOW_VIOLATED`, `CAPACITY_AND_TIME_WINDOW`,
3275
- * `SKILLS_MISMATCH`, `TAG_RESTRICTED`, `COMMITMENT_BLOCKED`,
3276
- * `VEHICLE_EXCLUDED`, `VEHICLE_RANGE_EXCEEDED`, `UNREACHABLE_LOCATION`,
3277
- * or `ALL_ROUTES_BLOCKED` (a mix no single code describes).
3278
- * `UNREACHABLE_LOCATION` outranks the others when it applies:
3279
- * a coordinate the routing engine cannot reach is a fact about the input,
3280
- * not about the fleet. Treat an unrecognised value as
3281
- * `ALL_ROUTES_BLOCKED`.
3282
- * @example TIME_WINDOW_VIOLATED
3283
- */
3284
- code: string;
3285
3768
  /**
3286
- * @description Human-readable explanation.
3287
- * @example No vehicle can reach this job within its time window.
3769
+ * @description The unassigned task: a job id or a shipment id.
3770
+ * @example job-2
3288
3771
  */
3289
- message: string;
3772
+ task: string;
3290
3773
  };
3291
3774
  /**
3292
- * @description The 200 body of a `?validate_only=true` call: the request passed every
3293
- * check a real call runs before the matrix fetch.
3775
+ * @description The 200 body of `POST /v3/routing/validate/{solve,evaluate,suggest}`: the
3776
+ * request passed every check a real call runs before the matrix fetch.
3294
3777
  * @example {
3295
3778
  * "valid": true,
3296
3779
  * "warnings": []
3297
3780
  * }
3298
3781
  */
3299
- ValidateOnlyResponse: {
3782
+ ValidateResponse: {
3300
3783
  /** @description Always `true`: an invalid request gets a 400 instead. */
3301
3784
  valid: boolean;
3302
- /** @description Warnings a real call would return, in the error item shape. */
3303
- warnings: components["schemas"]["ErrorItem"][];
3785
+ /** @description May contain warnings about the request; none are produced today. */
3786
+ warnings: components["schemas"]["RequestIssue"][];
3304
3787
  };
3305
3788
  /**
3306
3789
  * @description A vehicle type available to serve tasks.
@@ -3339,7 +3822,7 @@ export interface components {
3339
3822
  */
3340
3823
  Vehicle: {
3341
3824
  /** @description Named capacity dimensions. */
3342
- capacity?: null | components["schemas"]["BTreeMap"];
3825
+ capacity?: null | components["schemas"]["Quantities"];
3343
3826
  /**
3344
3827
  * @description Vehicles this one may serve a `compatible_vehicles` relation's tasks
3345
3828
  * together with, by id. Absent: any vehicle. A list is a veto, so a
@@ -3398,8 +3881,15 @@ export interface components {
3398
3881
  * depot handling (`depots[].service_duration_s`,
3399
3882
  * `start`/`end.service_duration_s`), waiting time, or break durations.
3400
3883
  *
3401
- * Must be in `(0, 5]`. Default 1.0. A shift may override it for its own
3402
- * day with `shifts[].service_factor`.
3884
+ * Must be in `[0.001, 5]`. Default 1.0. A shift's own `service_factor`
3885
+ * replaces it for that shift; a task's `service_factors[].factor` for
3886
+ * this vehicle multiplies whichever applies: effective service time =
3887
+ * `service_duration_s / (shift_or_vehicle_factor * task_factor)`.
3888
+ *
3889
+ * V2's `durationModifier` went the other way (it MULTIPLIED duration,
3890
+ * `0.8` = 20% faster); the V2 compatibility layer inverts it and sends it
3891
+ * as the task's `service_factors[].factor = 1 / durationModifier`.
3892
+ * @default 1
3403
3893
  */
3404
3894
  service_factor?: number | null;
3405
3895
  /**
@@ -3408,7 +3898,7 @@ export interface components {
3408
3898
  */
3409
3899
  shifts: components["schemas"]["Shift"][];
3410
3900
  /**
3411
- * @description Capabilities the vehicle provides. A job's `skills` must all appear
3901
+ * @description Capabilities the vehicle provides. A job's `required_skills` must all appear
3412
3902
  * here at a level of at least the job's `min_level`. Each entry is an
3413
3903
  * object `{ "name": ..., "level": N }` (`level` optional, default 1);
3414
3904
  * a bare string is rejected. A skill may appear once per list. Omitting
@@ -3420,11 +3910,12 @@ export interface components {
3420
3910
  * Format: double
3421
3911
  * @description Travel-speed multiplier (1.0 = base speed). Effective travel time =
3422
3912
  * `base travel time / speed_factor`, so values > 1.0 model a faster
3423
- * vehicle and < 1.0 a slower one. Must be in `(0, 5]`. Default 1.0.
3913
+ * vehicle and < 1.0 a slower one. Must be in `[0.001, 5]`. Default 1.0.
3424
3914
  *
3425
3915
  * Covers driving only. Its companion `service_factor` scales the
3426
3916
  * work done at stops; the two are independent and share this direction and
3427
3917
  * range.
3918
+ * @default 1
3428
3919
  */
3429
3920
  speed_factor?: number | null;
3430
3921
  /**
@@ -3438,6 +3929,27 @@ export interface components {
3438
3929
  */
3439
3930
  workload_weight?: number | null;
3440
3931
  };
3932
+ /**
3933
+ * @description Hard vehicle eligibility: whitelist or blacklist (mutually exclusive).
3934
+ * @example {
3935
+ * "allowed": [
3936
+ * "v1",
3937
+ * "v2"
3938
+ * ]
3939
+ * }
3940
+ */
3941
+ VehicleEligibility: {
3942
+ /**
3943
+ * @description Hard whitelist of vehicle ids. Omit = all vehicles allowed. An empty
3944
+ * list, or an id that names no vehicle, is rejected with HTTP 400.
3945
+ */
3946
+ allowed?: string[] | null;
3947
+ /**
3948
+ * @description Hard blacklist of vehicle ids. Mutually exclusive with `allowed`. An
3949
+ * id that names no vehicle is rejected with HTTP 400.
3950
+ */
3951
+ excluded?: string[] | null;
3952
+ };
3441
3953
  /**
3442
3954
  * @description Vehicle distance/time limits.
3443
3955
  * @example {
@@ -3459,13 +3971,14 @@ export interface components {
3459
3971
  * the `travel_s` reported on each stop, start-to-first-task and
3460
3972
  * last-task-to-`end` included. Travel only: setup, service and wait do
3461
3973
  * not count, and `speed_factor` applies first. A leg made free by
3462
- * `ignore_start_leg`/`ignore_end_leg`, or absent on an open start or
3974
+ * `free_start_travel`/`free_end_travel`, or absent on an open start or
3463
3975
  * end, is exempt. Absent = no cap. Must be > 0: `0` would make every
3464
3976
  * leg too long rather than mean "no cap", so it is rejected with HTTP
3465
- * 400 `out_of_range`, as is a value that does not fit in 32 bits.
3977
+ * 400 `out_of_range`, as is a value that does not fit in 32 bits. A
3978
+ * breach is reported as `max_leg_travel`.
3466
3979
  * @example 3600
3467
3980
  */
3468
- max_leg_travel_time_s?: number | null;
3981
+ max_leg_travel_s?: number | null;
3469
3982
  /**
3470
3983
  * Format: int64
3471
3984
  * @description Hard maximum route duration in seconds: the whole-route span —
@@ -3478,11 +3991,12 @@ export interface components {
3478
3991
  max_route_duration_s?: number | null;
3479
3992
  /**
3480
3993
  * Format: int32
3481
- * @description Maximum stops served per shift: a job counts as one stop, a shipment
3482
- * as two (pickup and delivery).
3994
+ * @description Maximum stops served per shift; a job counts as one stop.
3995
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
3996
+ * shipment counts as two stops.
3483
3997
  * @example 50
3484
3998
  */
3485
- max_tasks?: number | null;
3999
+ max_stops?: number | null;
3486
4000
  /**
3487
4001
  * @description Hard caps on this vehicle's totals across all of its shifts in a day,
3488
4002
  * a week or an explicit window. Each shift counts toward the one
@@ -3492,6 +4006,28 @@ export interface components {
3492
4006
  */
3493
4007
  periods?: components["schemas"]["PeriodLimit"][];
3494
4008
  };
4009
+ /**
4010
+ * @description A soft vehicle affinity preference, priced.
4011
+ * @example {
4012
+ * "vehicle": "v1",
4013
+ * "violation_cost": 50
4014
+ * }
4015
+ */
4016
+ VehiclePreference: {
4017
+ /**
4018
+ * @description Preferred vehicle id. An id that names no vehicle, or a vehicle listed
4019
+ * twice in one task's `preferences`, is rejected with HTTP 400.
4020
+ * @example v1
4021
+ */
4022
+ vehicle: string;
4023
+ /**
4024
+ * Format: double
4025
+ * @description Cost, in the objective's currency, incurred when a different vehicle
4026
+ * serves the job. Must be finite and `>= 0`.
4027
+ * @example 50
4028
+ */
4029
+ violation_cost: number;
4030
+ };
3495
4031
  /**
3496
4032
  * @description A capability a vehicle or shift provides, at a proficiency level:
3497
4033
  * `{ "name": "gas", "level": 3 }`. Always an object; a bare string is
@@ -3521,246 +4057,43 @@ export interface components {
3521
4057
  * Reported on stops (`routes[].stops[].violations`) and on routes
3522
4058
  * (`routes[].violations`) in the `POST /v3/routing/evaluate` response.
3523
4059
  * @example {
4060
+ * "code": "capacity",
4061
+ * "dimension": "weight",
4062
+ * "excess": 15,
3524
4063
  * "message": "Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)",
3525
- * "type": "capacity"
4064
+ * "unit": "load"
3526
4065
  * }
3527
4066
  */
3528
4067
  Violation: {
4068
+ /**
4069
+ * @description The constraint broken. `max_stops`, `break`, `multi_trip`,
4070
+ * `period_limit` and `quota` are route-level; `sequence` and `shipment`
4071
+ * are on the stop; `unreachable`, `max_leg_travel` and `capacity` can be
4072
+ * either. `unknown`
4073
+ * means the insertion check refused a stop without naming a constraint
4074
+ * (not expected in practice).
4075
+ */
4076
+ code: components["schemas"]["ConstraintCode"];
4077
+ /**
4078
+ * @description The capacity dimension over its limit. Only on `capacity`.
4079
+ * @example weight
4080
+ */
4081
+ dimension?: string | null;
4082
+ /**
4083
+ * Format: int64
4084
+ * @description How far over the limit, in `unit`. On `capacity`, `time_window` (the
4085
+ * seconds late), `shift_end`, `max_distance`, `max_route_duration` and
4086
+ * `quota`.
4087
+ * @example 15
4088
+ */
4089
+ excess?: number | null;
3529
4090
  /**
3530
4091
  * @description Human-readable description of what was violated.
3531
4092
  * @example Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)
3532
4093
  */
3533
4094
  message: string;
3534
- /**
3535
- * @description Machine-readable violation type: `time_window`, `capacity`, `skills`,
3536
- * `tags`, `first_job`, `unreachable`, `commitment`, `eligibility`,
3537
- * `same_vehicle`, `same_day`, `same_route`, `synchronized`, `time_lag`,
3538
- * `compatible_vehicles`, `max_distance`, `max_duration`, `shift_end`,
3539
- * `sequence`, `max_tasks`, `break`, `shipment`, `multi_trip`,
3540
- * `period_limit` (a `limits.periods`
3541
- * cap, reported once per period on the route of its first used shift),
3542
- * `quota` (a `quotas[]` cap, reported the same way), or `infeasible`
3543
- * (the insertion check refused a stop without naming a constraint; not
3544
- * expected in practice). `max_tasks`, `break`, `multi_trip`,
3545
- * `period_limit` and `quota` are route-level; `sequence` and
3546
- * `shipment` are on the stop.
3547
- *
3548
- * Deliberately an open string rather than an enum: stop-level types come
3549
- * from the active constraint set, so a new constraint can add one without
3550
- * a breaking schema change. Match on the values you handle and treat
3551
- * unknown ones as generic violations.
3552
- * @example capacity
3553
- */
3554
- type: string;
3555
- };
3556
- /**
3557
- * @description A single-stop visit: one location served once (the `jobs[]` entry type).
3558
- * For a pickup bound to a delivery on the same vehicle, use `shipments[]`.
3559
- * @example {
3560
- * "id": "job-1",
3561
- * "location": [
3562
- * 3.725,
3563
- * 51.05
3564
- * ],
3565
- * "pickup": {
3566
- * "weight": 20
3567
- * },
3568
- * "service_duration_s": 300,
3569
- * "skills": [
3570
- * {
3571
- * "name": "fridge"
3572
- * }
3573
- * ],
3574
- * "time_windows": [
3575
- * {
3576
- * "from": "2026-07-01T09:00:00+02:00",
3577
- * "to": "2026-07-01T12:00:00+02:00"
3578
- * }
3579
- * ]
3580
- * }
3581
- */
3582
- Visit: {
3583
- /**
3584
- * @description Absolute price of serving this task on a given vehicle, in the
3585
- * objective's currency. Charged once, when that vehicle (on any of its
3586
- * shifts) serves the task; unlisted vehicles cost nothing. Unlike
3587
- * `preferences`, which charges the vehicles that did NOT get the task,
3588
- * this prices the vehicle that did, so a task rated badly everywhere is
3589
- * the first one dropped when capacity runs out. It lives in the cost tier,
3590
- * below `priority`, and adds to `preferences`, `drop_fee` and travel.
3591
- * Not applied by decomposition: a problem that sets it solves monolithically.
3592
- */
3593
- assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
3594
- /**
3595
- * @description Whether a break may interrupt service here. Default `true`. `false`
3596
- * is not supported yet and is rejected with HTTP 400.
3597
- * @example true
3598
- */
3599
- break_interruptible?: boolean | null;
3600
- /** @description Quantity delivered at this visit — comes off the truck here, having been loaded at a depot — as non-negative magnitudes. Direction is carried by the field name, never by sign. Absent or empty means no delivery at this visit. */
3601
- delivery?: {
3602
- [key: string]: number;
3603
- } | null;
3604
- /**
3605
- * Format: double
3606
- * @description Drop **price** — what leaving this task unserved costs you, in the same
3607
- * currency as `objective.costs`, and the only way to make a task
3608
- * droppable. Tasks without a `drop_fee` must be served.
3609
- *
3610
- * This is money, not a priority: it enters the same cost the solver
3611
- * minimises, so the task is served only while serving it costs less than
3612
- * the fee. Fees the plan chose to pay are reported in
3613
- * `score.components.drop_fees` and summed into `score.cost`.
3614
- *
3615
- * On a shipment the fee applies to the pair, charged once.
3616
- *
3617
- * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
3618
- * is rejected with HTTP 400 (`conflicting_fields`).
3619
- * @example 25
3620
- */
3621
- drop_fee?: number | null;
3622
- /**
3623
- * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
3624
- * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
3625
- * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
3626
- */
3627
- eligible_vehicles?: null | components["schemas"]["Eligibility"];
3628
- /**
3629
- * @description Job id: 1 to 128 characters, unique across `jobs` + `shipments`.
3630
- * @example job-1
3631
- */
3632
- id: string;
3633
- /**
3634
- * @description Where this visit happens. Omit for a "virtual" (location-less) job:
3635
- * it still has service duration, time windows, load, and skills, but
3636
- * requires no travel — the vehicle's position doesn't change when it
3637
- * serves one. Virtual and located jobs may be mixed freely in the same
3638
- * request and route. A virtual job's stop in the solution response
3639
- * reports the resolved location of its nearest real (located)
3640
- * neighbor in the route — the predecessor when there is one, otherwise
3641
- * the successor — so it is `null` only on a route that has no located
3642
- * stop at all (an all-virtual route on an open-start/open-end shift).
3643
- * A shipment's legs still require a `location`.
3644
- */
3645
- location?: null | components["schemas"]["Place"];
3646
- /**
3647
- * @description Hard-pin this job to one vehicle id — only that vehicle (any of its
3648
- * shifts) may serve it, and once placed, re-optimization never removes it
3649
- * or moves it to another vehicle. Stronger than `eligible_vehicles`
3650
- * (which filters a set) and hard, unlike `preferences`.
3651
- *
3652
- * A pin means "stays on this vehicle if placed", **not** "must be
3653
- * served": the task can still end up unassigned (for example when it does
3654
- * not fit), and with a `drop_fee` it then pays the fee. An id that
3655
- * matches no vehicle is rejected with HTTP 400.
3656
- * @example vehicle-1
3657
- */
3658
- locked_vehicle?: string | null;
3659
- /**
3660
- * @description Quantity picked up at this visit: goes onto the vehicle here and stays
3661
- * aboard until the route ends or reloads. Non-negative magnitudes per
3662
- * named dimension. A swap that collects one quantity and drops off
3663
- * another at the same address is one job with both `pickup` and
3664
- * `delivery`.
3665
- */
3666
- pickup?: null | components["schemas"]["BTreeMap"];
3667
- /**
3668
- * @description Soft vehicle affinity preferences, priced. Each entry is independent:
3669
- * a job listing several preferred vehicles it doesn't get pays each
3670
- * one's `violation_cost` (compounding, the same rule as a vehicle's
3671
- * `preferred_tags`).
3672
- */
3673
- preferences?: components["schemas"]["Preference"][] | null;
3674
- /**
3675
- * Format: date-time
3676
- * @description Soft preference for the calendar day this task is served on, in a
3677
- * multi-day (multi-shift) problem.
3678
- *
3679
- * An RFC 3339 datetime, UTC offset required, on the intended day. A day is the calendar date of
3680
- * the value **in its own UTC offset**, the same rule that dates a shift
3681
- * from its `from`, so passing the target shift's `from` verbatim is
3682
- * always correct.
3683
- *
3684
- * Soft, and priced by `objective.non_preferred_date_cost` — a flat charge
3685
- * applied once to a task served on any other day. **With that cost unset or
3686
- * zero this field has no effect.** The charge is part of `score.cost`,
3687
- * which ranks below serving required tasks, so a task is never left
3688
- * unassigned to honour its preferred date; `locked_vehicle` (hard) also
3689
- * still wins.
3690
- *
3691
- * Supported on shipments as well as jobs. Both legs of a shipment ride
3692
- * the same route, so the preferred day is a property of the pair: set it
3693
- * on the shipment itself, and `non_preferred_date_cost` is charged once
3694
- * for the pair rather than once per leg.
3695
- * @example 2026-08-04T08:00:00+02:00
3696
- */
3697
- preferred_date?: string | null;
3698
- /**
3699
- * Format: int32
3700
- * @description Importance of a must-serve task when not all of them fit: the solver
3701
- * maximises the summed `priority` of served tasks before any cost. `>= 1`,
3702
- * default `1` (maximise the count). A rank, not money — it never makes a
3703
- * task droppable; use `drop_fee` for that. Both set is a 400.
3704
- * @example 3
3705
- */
3706
- priority?: number | null;
3707
- /**
3708
- * Format: int32
3709
- * @description On-site service time paid per job (seconds).
3710
- *
3711
- * This is the nominal figure. The serving vehicle's `service_factor`
3712
- * scales it — the time actually scheduled is
3713
- * `service_duration_s / service_factor` — so the solution's
3714
- * `stops[].service_s` may differ from what you sent here. Default `0`;
3715
- * a negative value is rejected with HTTP 400.
3716
- * @example 300
3717
- */
3718
- service_duration_s?: number | null;
3719
- /**
3720
- * @description Per-vehicle work-rate overrides for this task's `service_duration_s`,
3721
- * composed multiplicatively with the serving vehicle's or shift's
3722
- * `service_factor`. On a shipment the override scales both legs. A
3723
- * vehicle not listed works at its own rate.
3724
- */
3725
- service_factors?: components["schemas"]["ServiceFactor"][] | null;
3726
- /**
3727
- * Format: int32
3728
- * @description Setup time paid once on arrival at a new location (seconds),
3729
- * distinct from `service_duration_s`. Skipped when the immediate real
3730
- * predecessor in the route already sits at this location — co-located
3731
- * stops share one setup.
3732
- *
3733
- * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
3734
- * overhead (parking, walking to the door), not the work itself.
3735
- * Default `0`; a negative value is rejected with HTTP 400.
3736
- * @example 60
3737
- */
3738
- setup_duration_s?: number | null;
3739
- /**
3740
- * @description Hard skill requirements — the assigned vehicle must provide every one,
3741
- * at or above each requirement's `min_level`. A request may use at most
3742
- * 256 distinct `(name, min_level)` pairs across all jobs and shipments
3743
- * (HTTP 400 `limit_exceeded` beyond that).
3744
- */
3745
- skills?: components["schemas"]["SkillReq"][] | null;
3746
- /**
3747
- * @description Free-form task labels (zones/territories, grouping/relation labels).
3748
- * Used for `tag`/relation resolution and, when a shift scopes itself via
3749
- * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
3750
- * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
3751
- * `skills`, which requires ALL. Not capability matching on its own.
3752
- * A request may carry at most 256 distinct tags across all jobs and
3753
- * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
3754
- * lists do not count.
3755
- */
3756
- tags?: string[] | null;
3757
- /**
3758
- * @description Soft target for this task, measured at its arrival (default) or
3759
- * departure. On a shipment it is measured on the **delivery** leg.
3760
- */
3761
- target?: null | components["schemas"]["Target"];
3762
- /** @description Time windows for this visit. */
3763
- time_windows?: components["schemas"]["TimeWindow"][] | null;
4095
+ /** @description Unit of `excess`; present exactly when `excess` is. */
4096
+ unit?: null | components["schemas"]["QuantityUnit"];
3764
4097
  };
3765
4098
  /**
3766
4099
  * @description Spreads work across vehicles: each vehicle's scheduled service time is
@@ -3803,40 +4136,179 @@ export interface components {
3803
4136
  tolerance?: number | null;
3804
4137
  };
3805
4138
  };
3806
- responses: never;
3807
- parameters: never;
3808
- requestBodies: never;
3809
- headers: never;
3810
- pathItems: never;
3811
- }
3812
- export type $defs = Record<string, never>;
3813
- export interface operations {
3814
- evaluate: {
4139
+ responses: never;
4140
+ parameters: never;
4141
+ requestBodies: never;
4142
+ headers: never;
4143
+ pathItems: never;
4144
+ }
4145
+ export type $defs = Record<string, never>;
4146
+ export interface operations {
4147
+ evaluate: {
4148
+ parameters: {
4149
+ query?: never;
4150
+ header?: never;
4151
+ path?: never;
4152
+ cookie?: never;
4153
+ };
4154
+ requestBody: {
4155
+ content: {
4156
+ "application/json": components["schemas"]["EvaluateRequest"];
4157
+ };
4158
+ };
4159
+ responses: {
4160
+ /** @description Solution evaluated. */
4161
+ 200: {
4162
+ headers: {
4163
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4164
+ "x-request-id"?: string;
4165
+ [name: string]: unknown;
4166
+ };
4167
+ content: {
4168
+ "application/json": components["schemas"]["SolveResponse"];
4169
+ };
4170
+ };
4171
+ /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
4172
+ 400: {
4173
+ headers: {
4174
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4175
+ "x-request-id"?: string;
4176
+ [name: string]: unknown;
4177
+ };
4178
+ content: {
4179
+ "application/json": components["schemas"]["ErrorBody"];
4180
+ };
4181
+ };
4182
+ /** @description Missing or invalid API key. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
4183
+ 401: {
4184
+ headers: {
4185
+ [name: string]: unknown;
4186
+ };
4187
+ content?: never;
4188
+ };
4189
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
4190
+ 403: {
4191
+ headers: {
4192
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4193
+ "x-request-id"?: string;
4194
+ [name: string]: unknown;
4195
+ };
4196
+ content: {
4197
+ /**
4198
+ * @example {
4199
+ * "code": "feature_not_enabled",
4200
+ * "message": "travel.engine: 'tomtom_real_time' is not enabled for this account; use engine 'tomtom'",
4201
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4202
+ * "status": "FORBIDDEN"
4203
+ * }
4204
+ */
4205
+ "application/json": components["schemas"]["ErrorBody"];
4206
+ };
4207
+ };
4208
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
4209
+ 413: {
4210
+ headers: {
4211
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4212
+ "x-request-id"?: string;
4213
+ [name: string]: unknown;
4214
+ };
4215
+ content: {
4216
+ /**
4217
+ * @example {
4218
+ * "code": "payload_too_large",
4219
+ * "message": "Request body exceeds 10485760 bytes",
4220
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4221
+ * "status": "PAYLOAD_TOO_LARGE"
4222
+ * }
4223
+ */
4224
+ "application/json": components["schemas"]["ErrorBody"];
4225
+ };
4226
+ };
4227
+ /** @description Request `Content-Type` is missing or not JSON (`application/json` or `application/*+json`), or the body has a `Content-Encoding` other than `gzip` (the message says which) */
4228
+ 415: {
4229
+ headers: {
4230
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4231
+ "x-request-id"?: string;
4232
+ [name: string]: unknown;
4233
+ };
4234
+ content: {
4235
+ /**
4236
+ * @example {
4237
+ * "code": "unsupported_media_type",
4238
+ * "message": "Expected request with `Content-Type: application/json`",
4239
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4240
+ * "status": "UNSUPPORTED_MEDIA_TYPE"
4241
+ * }
4242
+ */
4243
+ "application/json": components["schemas"]["ErrorBody"];
4244
+ };
4245
+ };
4246
+ /** @description Rate limited. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape. Back off and retry. */
4247
+ 429: {
4248
+ headers: {
4249
+ [name: string]: unknown;
4250
+ };
4251
+ content?: never;
4252
+ };
4253
+ /** @description Server-side error (`code: internal`). */
4254
+ 500: {
4255
+ headers: {
4256
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4257
+ "x-request-id"?: string;
4258
+ [name: string]: unknown;
4259
+ };
4260
+ content: {
4261
+ "application/json": components["schemas"]["ErrorBody"];
4262
+ };
4263
+ };
4264
+ /** @description Travel times and distances could not be fetched (`code: travel_provider_error`). The request can be retried. This endpoint never falls back to estimated travel. */
4265
+ 502: {
4266
+ headers: {
4267
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4268
+ "x-request-id"?: string;
4269
+ [name: string]: unknown;
4270
+ };
4271
+ content: {
4272
+ "application/json": components["schemas"]["ErrorBody"];
4273
+ };
4274
+ };
4275
+ /** @description Solvice Maps is temporarily refused after repeated failures (`code: overloaded`), so travel times cannot be fetched. Evaluate takes no solver slot, so this is its only 503. Retry after the number of seconds in the `Retry-After` header. */
4276
+ 503: {
4277
+ headers: {
4278
+ /** @description Seconds to wait before retrying. */
4279
+ "Retry-After"?: number;
4280
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4281
+ "x-request-id"?: string;
4282
+ [name: string]: unknown;
4283
+ };
4284
+ content: {
4285
+ /**
4286
+ * @example {
4287
+ * "code": "overloaded",
4288
+ * "message": "Circuit breaker is open — Solvice Maps temporarily unavailable",
4289
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4290
+ * "status": "SERVICE_UNAVAILABLE"
4291
+ * }
4292
+ */
4293
+ "application/json": components["schemas"]["ErrorBody"];
4294
+ };
4295
+ };
4296
+ };
4297
+ };
4298
+ solve: {
3815
4299
  parameters: {
3816
- query?: {
3817
- /**
3818
- * @description Check the request without fetching a matrix or searching. 200
3819
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
3820
- * and caps; `plan` is matched against the problem only by the real call,
3821
- * after the fetch (suggest's check that `plan` leaves a task to place
3822
- * does run here).
3823
- * Any other query parameter is rejected with a 400 `unknown_field`, as in
3824
- * the body: a misspelt `validateOnly` must not fall through to a billed
3825
- * solve.
3826
- */
3827
- validate_only?: boolean;
3828
- };
4300
+ query?: never;
3829
4301
  header?: never;
3830
4302
  path?: never;
3831
4303
  cookie?: never;
3832
4304
  };
3833
4305
  requestBody: {
3834
4306
  content: {
3835
- "application/json": components["schemas"]["EvaluateRequest"];
4307
+ "application/json": components["schemas"]["SolveRequest"];
3836
4308
  };
3837
4309
  };
3838
4310
  responses: {
3839
- /** @description Solution evaluated. With `?validate_only=true`: a `ValidateOnlyResponse`, `{"valid": true, "warnings": []}`, without a matrix fetch, not billed. */
4311
+ /** @description Solution found. */
3840
4312
  200: {
3841
4313
  headers: {
3842
4314
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3844,7 +4316,7 @@ export interface operations {
3844
4316
  [name: string]: unknown;
3845
4317
  };
3846
4318
  content: {
3847
- "application/json": components["schemas"]["OrValidateOnly_SolveResponse"];
4319
+ "application/json": components["schemas"]["SolveResponse"];
3848
4320
  };
3849
4321
  };
3850
4322
  /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
@@ -3865,7 +4337,7 @@ export interface operations {
3865
4337
  };
3866
4338
  content?: never;
3867
4339
  };
3868
- /** @description The request uses a feature this account does not have (`tomtom_real_time`). Also returned by `?validate_only=true`. */
4340
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
3869
4341
  403: {
3870
4342
  headers: {
3871
4343
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3940,7 +4412,7 @@ export interface operations {
3940
4412
  "application/json": components["schemas"]["ErrorBody"];
3941
4413
  };
3942
4414
  };
3943
- /** @description Travel times and distances could not be fetched (`code: matrix_provider_error`). The request can be retried. This endpoint never falls back to estimated travel. */
4415
+ /** @description Travel times and distances could not be fetched (`code: travel_provider_error`). The request can be retried. If Solvice Maps is only unreachable, this needs `options.travel_fallback: "fail"`; by default the plan is solved on estimated travel and `summary.travel_estimated` is set. */
3944
4416
  502: {
3945
4417
  headers: {
3946
4418
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3951,7 +4423,7 @@ export interface operations {
3951
4423
  "application/json": components["schemas"]["ErrorBody"];
3952
4424
  };
3953
4425
  };
3954
- /** @description Solvice Maps is temporarily refused after repeated failures (`code: overloaded`), so travel times cannot be fetched. Evaluate takes no solver slot, so this is its only 503. Retry after the number of seconds in the `Retry-After` header. */
4426
+ /** @description No capacity right now (`code: overloaded`): every solver slot is busy, or the wait for one timed out. With `options.travel_fallback: "fail"`, also returned while Solvice Maps is temporarily refused after repeated failures. Retry after the number of seconds in the `Retry-After` header. */
3955
4427
  503: {
3956
4428
  headers: {
3957
4429
  /** @description Seconds to wait before retrying. */
@@ -3964,7 +4436,7 @@ export interface operations {
3964
4436
  /**
3965
4437
  * @example {
3966
4438
  * "code": "overloaded",
3967
- * "message": "Circuit breaker is open — Solvice Maps temporarily unavailable",
4439
+ * "message": "All solver slots are busy, try again later",
3968
4440
  * "request_id": "req_7f3a2c90d1e4b5a6",
3969
4441
  * "status": "SERVICE_UNAVAILABLE"
3970
4442
  * }
@@ -3974,32 +4446,20 @@ export interface operations {
3974
4446
  };
3975
4447
  };
3976
4448
  };
3977
- solve: {
4449
+ suggest: {
3978
4450
  parameters: {
3979
- query?: {
3980
- /**
3981
- * @description Check the request without fetching a matrix or searching. 200
3982
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
3983
- * and caps; `plan` is matched against the problem only by the real call,
3984
- * after the fetch (suggest's check that `plan` leaves a task to place
3985
- * does run here).
3986
- * Any other query parameter is rejected with a 400 `unknown_field`, as in
3987
- * the body: a misspelt `validateOnly` must not fall through to a billed
3988
- * solve.
3989
- */
3990
- validate_only?: boolean;
3991
- };
4451
+ query?: never;
3992
4452
  header?: never;
3993
4453
  path?: never;
3994
4454
  cookie?: never;
3995
4455
  };
3996
4456
  requestBody: {
3997
4457
  content: {
3998
- "application/json": components["schemas"]["SolveRequest"];
4458
+ "application/json": components["schemas"]["SuggestRequest"];
3999
4459
  };
4000
4460
  };
4001
4461
  responses: {
4002
- /** @description Solution found. With `?validate_only=true`: a `ValidateOnlyResponse`, `{"valid": true, "warnings": []}`, without a matrix fetch or a search, not billed. */
4462
+ /** @description Suggestions computed. */
4003
4463
  200: {
4004
4464
  headers: {
4005
4465
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4007,7 +4467,7 @@ export interface operations {
4007
4467
  [name: string]: unknown;
4008
4468
  };
4009
4469
  content: {
4010
- "application/json": components["schemas"]["OrValidateOnly_SolveResponse"];
4470
+ "application/json": components["schemas"]["SuggestResponse"];
4011
4471
  };
4012
4472
  };
4013
4473
  /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
@@ -4028,7 +4488,7 @@ export interface operations {
4028
4488
  };
4029
4489
  content?: never;
4030
4490
  };
4031
- /** @description The request uses a feature this account does not have (`tomtom_real_time`). Also returned by `?validate_only=true`. */
4491
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
4032
4492
  403: {
4033
4493
  headers: {
4034
4494
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4103,7 +4563,7 @@ export interface operations {
4103
4563
  "application/json": components["schemas"]["ErrorBody"];
4104
4564
  };
4105
4565
  };
4106
- /** @description Travel times and distances could not be fetched (`code: matrix_provider_error`). The request can be retried. If Solvice Maps is only unreachable, this needs `options.travel_fallback: "fail"`; by default the plan is solved on estimated travel and `summary.travel_estimated` is set. */
4566
+ /** @description Travel times and distances could not be fetched (`code: travel_provider_error`). The request can be retried. This endpoint never falls back to estimated travel. */
4107
4567
  502: {
4108
4568
  headers: {
4109
4569
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4114,7 +4574,7 @@ export interface operations {
4114
4574
  "application/json": components["schemas"]["ErrorBody"];
4115
4575
  };
4116
4576
  };
4117
- /** @description No capacity right now (`code: overloaded`): every solver slot is busy, or the wait for one timed out. With `options.travel_fallback: "fail"`, also returned while Solvice Maps is temporarily refused after repeated failures. Retry after the number of seconds in the `Retry-After` header. */
4577
+ /** @description No capacity right now (`code: overloaded`): every solver slot is busy, the wait for one timed out, or Solvice Maps is temporarily refused after repeated failures. Retry after the number of seconds in the `Retry-After` header. */
4118
4578
  503: {
4119
4579
  headers: {
4120
4580
  /** @description Seconds to wait before retrying. */
@@ -4137,32 +4597,139 @@ export interface operations {
4137
4597
  };
4138
4598
  };
4139
4599
  };
4140
- suggest: {
4600
+ validate_evaluate: {
4141
4601
  parameters: {
4142
- query?: {
4143
- /**
4144
- * @description Check the request without fetching a matrix or searching. 200
4145
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
4146
- * and caps; `plan` is matched against the problem only by the real call,
4147
- * after the fetch (suggest's check that `plan` leaves a task to place
4148
- * does run here).
4149
- * Any other query parameter is rejected with a 400 `unknown_field`, as in
4150
- * the body: a misspelt `validateOnly` must not fall through to a billed
4151
- * solve.
4152
- */
4153
- validate_only?: boolean;
4602
+ query?: never;
4603
+ header?: never;
4604
+ path?: never;
4605
+ cookie?: never;
4606
+ };
4607
+ requestBody: {
4608
+ content: {
4609
+ "application/json": components["schemas"]["EvaluateRequest"];
4610
+ };
4611
+ };
4612
+ responses: {
4613
+ /** @description The request passed every check made before travel times are fetched. `warnings` may contain warnings; none are produced today. */
4614
+ 200: {
4615
+ headers: {
4616
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4617
+ "x-request-id"?: string;
4618
+ [name: string]: unknown;
4619
+ };
4620
+ content: {
4621
+ "application/json": components["schemas"]["ValidateResponse"];
4622
+ };
4623
+ };
4624
+ /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
4625
+ 400: {
4626
+ headers: {
4627
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4628
+ "x-request-id"?: string;
4629
+ [name: string]: unknown;
4630
+ };
4631
+ content: {
4632
+ "application/json": components["schemas"]["ErrorBody"];
4633
+ };
4634
+ };
4635
+ /** @description Missing or invalid API key. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
4636
+ 401: {
4637
+ headers: {
4638
+ [name: string]: unknown;
4639
+ };
4640
+ content?: never;
4641
+ };
4642
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
4643
+ 403: {
4644
+ headers: {
4645
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4646
+ "x-request-id"?: string;
4647
+ [name: string]: unknown;
4648
+ };
4649
+ content: {
4650
+ /**
4651
+ * @example {
4652
+ * "code": "feature_not_enabled",
4653
+ * "message": "travel.engine: 'tomtom_real_time' is not enabled for this account; use engine 'tomtom'",
4654
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4655
+ * "status": "FORBIDDEN"
4656
+ * }
4657
+ */
4658
+ "application/json": components["schemas"]["ErrorBody"];
4659
+ };
4660
+ };
4661
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
4662
+ 413: {
4663
+ headers: {
4664
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4665
+ "x-request-id"?: string;
4666
+ [name: string]: unknown;
4667
+ };
4668
+ content: {
4669
+ /**
4670
+ * @example {
4671
+ * "code": "payload_too_large",
4672
+ * "message": "Request body exceeds 10485760 bytes",
4673
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4674
+ * "status": "PAYLOAD_TOO_LARGE"
4675
+ * }
4676
+ */
4677
+ "application/json": components["schemas"]["ErrorBody"];
4678
+ };
4679
+ };
4680
+ /** @description Request `Content-Type` is missing or not JSON (`application/json` or `application/*+json`), or the body has a `Content-Encoding` other than `gzip` (the message says which) */
4681
+ 415: {
4682
+ headers: {
4683
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4684
+ "x-request-id"?: string;
4685
+ [name: string]: unknown;
4686
+ };
4687
+ content: {
4688
+ /**
4689
+ * @example {
4690
+ * "code": "unsupported_media_type",
4691
+ * "message": "Expected request with `Content-Type: application/json`",
4692
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4693
+ * "status": "UNSUPPORTED_MEDIA_TYPE"
4694
+ * }
4695
+ */
4696
+ "application/json": components["schemas"]["ErrorBody"];
4697
+ };
4698
+ };
4699
+ /** @description Rate limited. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape. Back off and retry. */
4700
+ 429: {
4701
+ headers: {
4702
+ [name: string]: unknown;
4703
+ };
4704
+ content?: never;
4705
+ };
4706
+ /** @description Server-side error (`code: internal`). */
4707
+ 500: {
4708
+ headers: {
4709
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4710
+ "x-request-id"?: string;
4711
+ [name: string]: unknown;
4712
+ };
4713
+ content: {
4714
+ "application/json": components["schemas"]["ErrorBody"];
4715
+ };
4154
4716
  };
4717
+ };
4718
+ };
4719
+ validate_solve: {
4720
+ parameters: {
4721
+ query?: never;
4155
4722
  header?: never;
4156
4723
  path?: never;
4157
4724
  cookie?: never;
4158
4725
  };
4159
4726
  requestBody: {
4160
4727
  content: {
4161
- "application/json": components["schemas"]["SuggestRequest"];
4728
+ "application/json": components["schemas"]["SolveRequest"];
4162
4729
  };
4163
4730
  };
4164
4731
  responses: {
4165
- /** @description Suggestions computed. With `?validate_only=true`: a `ValidateOnlyResponse`, `{"valid": true, "warnings": []}`, without a matrix fetch or a search, not billed. */
4732
+ /** @description The request passed every check made before travel times are fetched. `warnings` may contain warnings; none are produced today. */
4166
4733
  200: {
4167
4734
  headers: {
4168
4735
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4170,7 +4737,7 @@ export interface operations {
4170
4737
  [name: string]: unknown;
4171
4738
  };
4172
4739
  content: {
4173
- "application/json": components["schemas"]["OrValidateOnly_SuggestResponse"];
4740
+ "application/json": components["schemas"]["ValidateResponse"];
4174
4741
  };
4175
4742
  };
4176
4743
  /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
@@ -4191,7 +4758,7 @@ export interface operations {
4191
4758
  };
4192
4759
  content?: never;
4193
4760
  };
4194
- /** @description The request uses a feature this account does not have (`tomtom_real_time`). Also returned by `?validate_only=true`. */
4761
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
4195
4762
  403: {
4196
4763
  headers: {
4197
4764
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4266,8 +4833,34 @@ export interface operations {
4266
4833
  "application/json": components["schemas"]["ErrorBody"];
4267
4834
  };
4268
4835
  };
4269
- /** @description Travel times and distances could not be fetched (`code: matrix_provider_error`). The request can be retried. This endpoint never falls back to estimated travel. */
4270
- 502: {
4836
+ };
4837
+ };
4838
+ validate_suggest: {
4839
+ parameters: {
4840
+ query?: never;
4841
+ header?: never;
4842
+ path?: never;
4843
+ cookie?: never;
4844
+ };
4845
+ requestBody: {
4846
+ content: {
4847
+ "application/json": components["schemas"]["SuggestRequest"];
4848
+ };
4849
+ };
4850
+ responses: {
4851
+ /** @description The request passed every check made before travel times are fetched. `warnings` may contain warnings; none are produced today. */
4852
+ 200: {
4853
+ headers: {
4854
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4855
+ "x-request-id"?: string;
4856
+ [name: string]: unknown;
4857
+ };
4858
+ content: {
4859
+ "application/json": components["schemas"]["ValidateResponse"];
4860
+ };
4861
+ };
4862
+ /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and, when the problem is in the body, a JSON `pointer` to it. */
4863
+ 400: {
4271
4864
  headers: {
4272
4865
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4273
4866
  "x-request-id"?: string;
@@ -4277,11 +4870,16 @@ export interface operations {
4277
4870
  "application/json": components["schemas"]["ErrorBody"];
4278
4871
  };
4279
4872
  };
4280
- /** @description No capacity right now (`code: overloaded`): every solver slot is busy, the wait for one timed out, or Solvice Maps is temporarily refused after repeated failures. Retry after the number of seconds in the `Retry-After` header. */
4281
- 503: {
4873
+ /** @description Missing or invalid API key. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
4874
+ 401: {
4875
+ headers: {
4876
+ [name: string]: unknown;
4877
+ };
4878
+ content?: never;
4879
+ };
4880
+ /** @description The request uses a feature this account does not have (`tomtom_real_time`) */
4881
+ 403: {
4282
4882
  headers: {
4283
- /** @description Seconds to wait before retrying. */
4284
- "Retry-After"?: number;
4285
4883
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4286
4884
  "x-request-id"?: string;
4287
4885
  [name: string]: unknown;
@@ -4289,15 +4887,71 @@ export interface operations {
4289
4887
  content: {
4290
4888
  /**
4291
4889
  * @example {
4292
- * "code": "overloaded",
4293
- * "message": "All solver slots are busy, try again later",
4890
+ * "code": "feature_not_enabled",
4891
+ * "message": "travel.engine: 'tomtom_real_time' is not enabled for this account; use engine 'tomtom'",
4294
4892
  * "request_id": "req_7f3a2c90d1e4b5a6",
4295
- * "status": "SERVICE_UNAVAILABLE"
4893
+ * "status": "FORBIDDEN"
4894
+ * }
4895
+ */
4896
+ "application/json": components["schemas"]["ErrorBody"];
4897
+ };
4898
+ };
4899
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
4900
+ 413: {
4901
+ headers: {
4902
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4903
+ "x-request-id"?: string;
4904
+ [name: string]: unknown;
4905
+ };
4906
+ content: {
4907
+ /**
4908
+ * @example {
4909
+ * "code": "payload_too_large",
4910
+ * "message": "Request body exceeds 10485760 bytes",
4911
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4912
+ * "status": "PAYLOAD_TOO_LARGE"
4913
+ * }
4914
+ */
4915
+ "application/json": components["schemas"]["ErrorBody"];
4916
+ };
4917
+ };
4918
+ /** @description Request `Content-Type` is missing or not JSON (`application/json` or `application/*+json`), or the body has a `Content-Encoding` other than `gzip` (the message says which) */
4919
+ 415: {
4920
+ headers: {
4921
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4922
+ "x-request-id"?: string;
4923
+ [name: string]: unknown;
4924
+ };
4925
+ content: {
4926
+ /**
4927
+ * @example {
4928
+ * "code": "unsupported_media_type",
4929
+ * "message": "Expected request with `Content-Type: application/json`",
4930
+ * "request_id": "req_7f3a2c90d1e4b5a6",
4931
+ * "status": "UNSUPPORTED_MEDIA_TYPE"
4296
4932
  * }
4297
4933
  */
4298
4934
  "application/json": components["schemas"]["ErrorBody"];
4299
4935
  };
4300
4936
  };
4937
+ /** @description Rate limited. Returned by the API gateway before the request reaches the solver, so it does not use the `ErrorBody` shape. Back off and retry. */
4938
+ 429: {
4939
+ headers: {
4940
+ [name: string]: unknown;
4941
+ };
4942
+ content?: never;
4943
+ };
4944
+ /** @description Server-side error (`code: internal`). */
4945
+ 500: {
4946
+ headers: {
4947
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4948
+ "x-request-id"?: string;
4949
+ [name: string]: unknown;
4950
+ };
4951
+ content: {
4952
+ "application/json": components["schemas"]["ErrorBody"];
4953
+ };
4954
+ };
4301
4955
  };
4302
4956
  };
4303
4957
  }