@solvice/routing 0.1.0-beta.0 → 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;
@@ -34,7 +34,7 @@ export interface paths {
34
34
  put?: never;
35
35
  /**
36
36
  * Solve a vehicle routing problem
37
- * @description Assigns the jobs and shipments in `problem` to the vehicles' shifts and returns the routes, the `plan` they follow and any tasks left unassigned, each with the reasons. The request is validated first: an invalid one is rejected with a 400 whose `errors[]` says what to fix. Travel times and distances for the request's locations are then looked up, and the search runs for `options.time_limit_s` seconds (default 1). Send a previous result's `plan` to re-optimize starting from it. `POST /v3/routing/evaluate` and `POST /v3/routing/suggest` take the same `problem`.
37
+ * @description Assigns the jobs and shipments in `problem` to the vehicles' shifts and returns the routes, the `plan` they follow and any tasks left unassigned, each with the reasons. The request is validated first: an invalid one is rejected with a 400 whose `errors[]` says what to fix. Travel times and distances for the request's locations are then looked up, and the search runs for `options.time_limit_s` seconds (default 150 ms plus 4 ms per task; maximum 60). Send a previous result's `plan` to re-optimize starting from it. `POST /v3/routing/evaluate` and `POST /v3/routing/suggest` take the same `problem`.
38
38
  */
39
39
  post: operations["solve"];
40
40
  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 {
@@ -84,21 +144,12 @@ export interface components {
84
144
  cost: number;
85
145
  /**
86
146
  * @description Vehicle id; applies to every shift of that vehicle. An id that matches
87
- * no vehicle is rejected with HTTP 400.
147
+ * no vehicle, or a vehicle listed twice in one task's
148
+ * `assignment_costs`, is rejected with HTTP 400.
88
149
  * @example v1
89
150
  */
90
151
  vehicle: string;
91
152
  };
92
- /**
93
- * @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.
94
- * @example {
95
- * "volume": 2,
96
- * "weight": 20
97
- * }
98
- */
99
- BTreeMap: {
100
- [key: string]: number;
101
- };
102
153
  /**
103
154
  * @description A scheduled break within a shift. Tagged by `type`:
104
155
  *
@@ -108,11 +159,13 @@ export interface components {
108
159
  * - `fixed`: a hard off-duty interval from `from` to `to`.
109
160
  *
110
161
  * Breaks are injected between stops and appear in the response as `break`
111
- * stops.
162
+ * stops, carrying the break's `id` when it has one.
112
163
  *
113
- * **Not yet supported** — rejected with HTTP 400 `not_supported`: more than
114
- * one `windows` entry, a `location` on a `triggered` break, and
115
- * `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`.
116
169
  *
117
170
  * There is no paid/unpaid cost accounting: a break's duration is never
118
171
  * separately priced, and no `paid` field exists on this schema — sending one
@@ -124,59 +177,34 @@ export interface components {
124
177
  * "type": "triggered"
125
178
  * }
126
179
  */
127
- Break: {
128
- /**
129
- * Format: int32
130
- * @description Break duration in seconds.
131
- */
132
- duration_s: number;
133
- /** @description Where the break is taken. Absent: wherever the vehicle is. */
134
- location?: null | components["schemas"]["Place"];
135
- /** @enum {string} */
136
- type: "windowed";
137
- /**
138
- * @description The window bounding the break's **start**. Exactly one entry; a
139
- * second one is rejected with HTTP 400 (`not_supported`).
140
- */
141
- windows: components["schemas"]["BreakWindow"][];
142
- } | {
143
- /** @description What to accumulate: drive time or duty time. */
144
- after: components["schemas"]["TriggerAfter"];
145
- /**
146
- * Format: int32
147
- * @description Break duration in seconds.
148
- */
149
- duration_s: number;
150
- /** @description Not supported yet: any value is rejected with HTTP 400. */
151
- location?: null | components["schemas"]["Place"];
152
- /**
153
- * @description Whether the accumulator resets after the break. Default `true` (the
154
- * EU-561 semantics; the accumulation window restarts after a qualifying
155
- * break). `false` is not supported yet and is rejected with HTTP 400.
156
- * @example true
157
- */
158
- resets_accumulator?: boolean | null;
159
- /**
160
- * Format: int64
161
- * @description Trigger threshold in seconds (strict `>` — the break fires when the
162
- * accumulator exceeds this). EU 561/2006 drive rule: `16200` (4 h 30).
163
- * @example 14400
164
- */
165
- threshold_s: number;
166
- /** @enum {string} */
167
- type: "triggered";
168
- } | {
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: {
169
188
  /**
170
189
  * Format: date-time
171
190
  * @description Start of the break (RFC 3339 instant, UTC offset required).
172
191
  */
173
192
  from: string;
193
+ /**
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
197
+ */
198
+ id?: string | null;
174
199
  /**
175
200
  * Format: date-time
176
201
  * @description End of the break (RFC 3339 instant, UTC offset required).
177
202
  */
178
203
  to: string;
179
- /** @enum {string} */
204
+ /**
205
+ * @description Discriminator: always `fixed`. (enum property replaced by openapi-typescript)
206
+ * @enum {string}
207
+ */
180
208
  type: "fixed";
181
209
  };
182
210
  /**
@@ -186,7 +214,7 @@ export interface components {
186
214
  * "to": "2026-07-01T13:30:00+02:00"
187
215
  * }
188
216
  */
189
- BreakWindow: {
217
+ BreakTimeWindow: {
190
218
  /**
191
219
  * Format: date-time
192
220
  * @description Earliest break start (RFC 3339 instant, UTC offset required).
@@ -198,6 +226,80 @@ export interface components {
198
226
  */
199
227
  to: string;
200
228
  };
229
+ /**
230
+ * Triggered
231
+ * @description A break taken once drive or duty time passes a threshold.
232
+ */
233
+ BreakTriggered: {
234
+ /** @description What to accumulate: drive time or duty time. */
235
+ after: components["schemas"]["TriggerAfter"];
236
+ /**
237
+ * Format: int32
238
+ * @description Break duration in seconds. Must be `> 0`.
239
+ */
240
+ duration_s: number;
241
+ /**
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
245
+ */
246
+ id?: string | null;
247
+ /**
248
+ * Format: int64
249
+ * @description Trigger threshold in seconds (strict `>` — the break fires when the
250
+ * accumulator exceeds this). EU 561/2006 drive rule: `16200` (4 h 30).
251
+ * Must be `> 0` and fit in 32 bits.
252
+ * @example 14400
253
+ */
254
+ threshold_s: number;
255
+ /**
256
+ * @description Discriminator: always `triggered`. (enum property replaced by openapi-typescript)
257
+ * @enum {string}
258
+ */
259
+ type: "triggered";
260
+ };
261
+ /**
262
+ * Windowed
263
+ * @description A break that must start inside a time window.
264
+ */
265
+ BreakWindowed: {
266
+ /**
267
+ * Format: int32
268
+ * @description Break duration in seconds. Must be `> 0`.
269
+ */
270
+ duration_s: number;
271
+ /**
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
275
+ */
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";
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;
201
303
  /**
202
304
  * @description What running a vehicle costs, in the request's currency
203
305
  * (`objective.currency` is only a label). The same type at three levels:
@@ -211,22 +313,17 @@ export interface components {
211
313
  * Rates are rounded to the internal grid (1/100 000 of a currency unit per
212
314
  * second or per metre); a nonzero rate too small to represent is rejected.
213
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.
214
320
  * @example {
215
- * "fixed": 50,
321
+ * "per_route": 50,
216
322
  * "per_route_hour": 35,
217
323
  * "per_travel_km": 0.2
218
324
  * }
219
325
  */
220
326
  Costs: {
221
- /**
222
- * Format: double
223
- * @description Flat charge for each used shift (a route with at least one task),
224
- * reported in `score.components.fixed`. Default `0`. Pricing vehicles is
225
- * how the solver is made to use fewer of them: the higher it is, the
226
- * more travel it accepts to avoid opening another route.
227
- * @example 50
228
- */
229
- fixed?: number | null;
230
327
  /**
231
328
  * Format: double
232
329
  * @description Per hour a route finishes past its shift's `to` (possible only with
@@ -235,17 +332,28 @@ export interface components {
235
332
  * @example 0
236
333
  */
237
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;
238
344
  /**
239
345
  * Format: double
240
346
  * @description Per hour of each route's wall-clock span (travel, service, waiting
241
- * 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.
242
349
  * @example 35
243
350
  */
244
351
  per_route_hour?: number | null;
245
352
  /**
246
353
  * Format: double
247
354
  * @description Per kilometre driven, reported in `score.components.distance`.
248
- * Default **0.20**.
355
+ * Default **0.20** at objective level; a vehicle or shift value inherits the
356
+ * fleet value.
249
357
  * @example 0.2
250
358
  */
251
359
  per_travel_km?: number | null;
@@ -253,7 +361,8 @@ export interface components {
253
361
  * Format: double
254
362
  * @description Per hour spent waiting for a time window to open, reported in
255
363
  * `score.components.waiting`, on top of `per_route_hour` (the span
256
- * 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`.
257
366
  * @example 0
258
367
  */
259
368
  per_wait_hour?: number | null;
@@ -261,7 +370,7 @@ export interface components {
261
370
  /**
262
371
  * @description A depot: a place a shift starts from, ends at, or reloads at mid-shift,
263
372
  * referenced by `id` from `shifts[].start`, `shifts[].end` and
264
- * `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.
265
374
  * @example {
266
375
  * "id": "gent",
267
376
  * "location": [
@@ -272,12 +381,20 @@ export interface components {
272
381
  * }
273
382
  */
274
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"];
275
391
  /**
276
392
  * Format: double
277
393
  * @description Money charged once per reload visit, in the objective's currency.
278
- * Default 0. A shift that only starts or ends here is not charged.
394
+ * Default 0; at most `1e9`. A shift that only starts or ends here is not
395
+ * charged.
279
396
  *
280
- * 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
281
398
  * cannot see — typically the driver labour for the unload itself
282
399
  * (`service_duration_s` × the hourly rate). Without it, a reload that
283
400
  * consumes only *slack* is free in the objective: it adds no route
@@ -286,14 +403,7 @@ export interface components {
286
403
  * the vehicle at a depot for no capacity benefit.
287
404
  * @example 38.66
288
405
  */
289
- cost_per_visit?: number | null;
290
- /**
291
- * @description Depot id: 1 to 128 characters, unique across `depots[]`.
292
- * @example gent
293
- */
294
- id: string;
295
- /** @description Where the depot is. */
296
- location: components["schemas"]["Place"];
406
+ per_reload?: number | null;
297
407
  /**
298
408
  * Format: int32
299
409
  * @description Handling time in seconds per visit: the load before a shift that starts
@@ -306,21 +416,6 @@ export interface components {
306
416
  */
307
417
  service_duration_s?: number | null;
308
418
  };
309
- /**
310
- * @description Hard vehicle eligibility: whitelist or blacklist (mutually exclusive).
311
- * @example {
312
- * "allowed": [
313
- * "v1",
314
- * "v2"
315
- * ]
316
- * }
317
- */
318
- Eligibility: {
319
- /** @description Hard whitelist of vehicle ids. Omit = all vehicles allowed. */
320
- allowed?: string[] | null;
321
- /** @description Hard blacklist of vehicle ids. Mutually exclusive with `allowed`. */
322
- excluded?: string[] | null;
323
- };
324
419
  /**
325
420
  * @description Error body of every `/v3/routing/*` endpoint.
326
421
  *
@@ -346,7 +441,7 @@ export interface components {
346
441
  /** @description What kind of failure this is. One value per HTTP status class. */
347
442
  code: components["schemas"]["ErrorCode"];
348
443
  /** @description One entry per problem found in the request. Empty for non-input errors. */
349
- errors?: components["schemas"]["ErrorItem"][];
444
+ errors?: components["schemas"]["RequestIssue"][];
350
445
  /**
351
446
  * @description Human-readable summary. With exactly one item it is that item's
352
447
  * message; with several, `"{n} problems in request"` (at most 100 items
@@ -364,39 +459,17 @@ export interface components {
364
459
  };
365
460
  /**
366
461
  * @description The top-level `code` of an error body.
367
- * @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.
368
464
  */
369
- ErrorCode: "invalid_request" | "feature_not_enabled" | "payload_too_large" | "unsupported_media_type" | "internal" | "matrix_provider_error" | "overloaded";
370
- /** @description One problem in a request. */
371
- ErrorItem: {
372
- /**
373
- * Format: int64
374
- * @description `limit_exceeded` only: the count this request has.
375
- */
376
- actual?: number | null;
377
- /** @description What is wrong. */
378
- code: components["schemas"]["ErrorItemCode"];
379
- /**
380
- * Format: int64
381
- * @description `limit_exceeded` only: the published cap.
382
- */
383
- limit?: number | null;
384
- /** @description Human-readable description. */
385
- message: string;
386
- /**
387
- * @description RFC 6901 JSON Pointer into the request body, when the problem has a
388
- * location. It is relative to the root of the body, so a field of the
389
- * problem reads `/problem/...` (e.g.
390
- * `"/problem/vehicles/0/shifts/0/from"`).
391
- */
392
- pointer?: string | null;
393
- };
465
+ ErrorCode: string;
394
466
  /**
395
467
  * @description The `code` of one `errors[]` item. Clients should accept values they do
396
468
  * not know yet.
397
- * @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.
398
471
  */
399
- 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;
400
473
  /**
401
474
  * @description Request body for `POST /v3/routing/evaluate`.
402
475
  *
@@ -427,7 +500,7 @@ export interface components {
427
500
  * 3.725,
428
501
  * 51.05
429
502
  * ],
430
- * "pickup": {
503
+ * "pickup_load": {
431
504
  * "weight": 10
432
505
  * },
433
506
  * "service_duration_s": 300
@@ -467,37 +540,45 @@ export interface components {
467
540
  /** @description The plan to score. */
468
541
  plan: components["schemas"]["Plan"];
469
542
  /** @description Problem definition — identical to `POST /v3/routing/solve`. */
470
- problem: components["schemas"]["ProblemInput"];
543
+ problem: components["schemas"]["Problem"];
471
544
  };
472
545
  /**
473
546
  * @description Keep geographically clustered tasks consecutive in a route.
474
547
  *
475
548
  * Two tasks are in the same **group** when they lie within `radius_m` of
476
- * each other. The solver adds `cost_per_reentry` to the objective each time
477
- * a route leaves a group and comes back — minimising the "passing-waypoint"
478
- * / area re-entry count last-mile fleets track. Presence of this object
479
- * 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.
480
555
  * @example {
481
- * "cost_per_reentry": 0.5,
482
- * "distance": "straight_line",
556
+ * "distance_metric": "straight_line",
557
+ * "per_entry": 0.5,
483
558
  * "radius_m": 180
484
559
  * }
485
560
  */
486
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"];
487
567
  /**
488
568
  * Format: double
489
- * @description Cost added to the objective per group re-entry, in the objective's
490
- * currency. At most 1000 currency units: a larger value is rejected with
491
- * HTTP 400. Higher keeps clusters together more aggressively at the
492
- * 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.
493
575
  * @example 0.5
494
576
  */
495
- cost_per_reentry: number;
496
- /** @description How neighbour distance is measured. Default `"straight_line"`. */
497
- distance?: null | components["schemas"]["GroupingDistance"];
577
+ per_entry: number;
498
578
  /**
499
579
  * Format: int32
500
- * @description Radius defining a group, in metres. Default `180`.
580
+ * @description Radius defining a group, in metres. Default `180`. Must be `> 0`.
581
+ * @default 180
501
582
  * @example 180
502
583
  */
503
584
  radius_m?: number | null;
@@ -516,14 +597,14 @@ export interface components {
516
597
  * @example {
517
598
  * "cost": 12.4,
518
599
  * "distance_m": 2400,
519
- * "duration_s": 240
600
+ * "travel_s": 240
520
601
  * }
521
602
  */
522
603
  InsertionDelta: {
523
604
  /**
524
605
  * Format: double
525
606
  * @description Change in the score's `cost`, in the request's currency. Negative when
526
- * 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.
527
608
  * @example 12.4
528
609
  */
529
610
  cost: number;
@@ -539,7 +620,7 @@ export interface components {
539
620
  * seconds.
540
621
  * @example 240
541
622
  */
542
- duration_s: number;
623
+ travel_s: number;
543
624
  };
544
625
  /**
545
626
  * @description One feasible way to place the whole unit.
@@ -547,7 +628,7 @@ export interface components {
547
628
  * "delta": {
548
629
  * "cost": 12.4,
549
630
  * "distance_m": 2400,
550
- * "duration_s": 240
631
+ * "travel_s": 240
551
632
  * },
552
633
  * "placements": [
553
634
  * {
@@ -598,67 +679,180 @@ export interface components {
598
679
  routes: components["schemas"]["PlanRoute"][];
599
680
  };
600
681
  /**
601
- * @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[]`.
602
684
  * @example {
603
- * "insertions": [
685
+ * "id": "job-1",
686
+ * "location": [
687
+ * 3.725,
688
+ * 51.05
689
+ * ],
690
+ * "pickup_load": {
691
+ * "weight": 20
692
+ * },
693
+ * "required_skills": [
604
694
  * {
605
- * "delta": {
606
- * "cost": 12.4,
607
- * "distance_m": 2400,
608
- * "duration_s": 240
609
- * },
610
- * "placements": [
611
- * {
612
- * "arrival": "2026-07-01T09:30:00+02:00",
613
- * "id": "job-2",
614
- * "latest_arrival": "2026-07-01T10:15:00+02:00",
615
- * "shift": "mon",
616
- * "type": "job",
617
- * "vehicle": "v1"
618
- * }
619
- * ],
620
- * "routes": [
621
- * {
622
- * "shift": "mon",
623
- * "stops": [
624
- * {
625
- * "id": "job-1",
626
- * "type": "job"
627
- * },
628
- * {
629
- * "id": "job-2",
630
- * "type": "job"
631
- * }
632
- * ],
633
- * "vehicle": "v1"
634
- * }
635
- * ]
695
+ * "name": "fridge"
636
696
  * }
637
697
  * ],
638
- * "job_id": "job-2"
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
+ * ]
639
705
  * }
640
706
  */
641
- JobSuggestions: {
642
- /**
643
- * @description Ranked feasible insertions, lowest `delta.cost` first. Empty if none
644
- * was found; `reason_code` then says why. Known limitation: suggest
645
- * never opens a **new reload trip** on a multi-trip vehicle.
646
- */
647
- insertions: components["schemas"]["InsertionOption"][];
707
+ Job: {
648
708
  /**
649
- * @description The unit's lead: its first member in placement order (the visit, the
650
- * shipment, or the first relation member).
651
- * @example job-2
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.
717
+ */
718
+ assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
719
+ /**
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.
652
729
  */
653
- job_id: string;
730
+ delivery_load?: null | components["schemas"]["Quantities"];
654
731
  /**
655
- * @description `reason_code` as an English sentence, for people and logs; present
656
- * exactly when `reason_code` is. Do not parse the text.
657
- * @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).
658
802
  */
659
- reason?: string | null;
660
- /** @description Why `insertions` is empty; absent otherwise. Branch on this. */
661
- reason_code?: null | components["schemas"]["SuggestReasonCode"];
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
814
+ */
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;
662
856
  };
663
857
  /**
664
858
  * @description Which road-network data prices travel times and distances.
@@ -683,8 +877,8 @@ export interface components {
683
877
  * (the summed `priority` of the required tasks left unassigned is
684
878
  * minimised), then **minimise cost** — the `costs` rates plus every priced
685
879
  * preference, reported as `score.cost`. There is no separate vehicle-count
686
- * step: to use fewer vehicles, price them with `costs.fixed` or
687
- * `vehicles[].costs.fixed`.
880
+ * step: to use fewer vehicles, price them with `costs.per_route` or
881
+ * `vehicles[].costs.per_route`.
688
882
  * @example {
689
883
  * "costs": {
690
884
  * "per_route_hour": 35,
@@ -708,21 +902,6 @@ export interface components {
708
902
  currency?: string | null;
709
903
  /** @description Job-proximity cluster cohesion. See the `Grouping` schema. */
710
904
  grouping?: null | components["schemas"]["Grouping"];
711
- /**
712
- * Format: double
713
- * @description Flat charge, in the objective's currency, for serving a task on a day
714
- * other than its `preferred_date`.
715
- *
716
- * Applied once per task whose `preferred_date` resolves to a different
717
- * calendar day (in its own offset) than the shift serving it; tasks without a `preferred_date`
718
- * are never charged. Unset or `0.0` disables the preference entirely,
719
- * which also makes every `preferred_date` in the request inert.
720
- *
721
- * Part of `score.cost`, so it trades off against travel and vehicle
722
- * cost but never against serving a required task.
723
- * @example 50
724
- */
725
- non_preferred_date_cost?: number | null;
726
905
  /**
727
906
  * Format: double
728
907
  * @description Cost per hour of lateness: the default rate for every task window
@@ -731,56 +910,14 @@ export interface components {
731
910
  * lateness and hard windows read opposite ways, and lateness is never
732
911
  * free). There is no earliness rate. It prices task windows only: a
733
912
  * shift's `to` (plus `max_overtime_s` when set) stays a hard limit.
734
- * Setting it `> 0` alongside a nonzero `time_windows[].cost` anywhere in
913
+ * Setting it `> 0` alongside a nonzero `time_windows[].choice_cost` anywhere in
735
914
  * the request is rejected with HTTP 400.
736
915
  * @example 60
737
916
  */
738
917
  per_late_hour?: number | null;
918
+ /** @description Spreads work across vehicles. See the `WorkloadShare` schema. */
919
+ workload_share?: null | components["schemas"]["WorkloadShare"];
739
920
  };
740
- /**
741
- * @description The 200 body of solve, evaluate and suggest: the call's result, or with
742
- * `?validate_only=true` the validation verdict (`ValidateOnlyResponse`).
743
- */
744
- OrValidateOnly_SolveResponse: {
745
- /**
746
- * @description The plan these routes follow, in the request's vocabulary: valid input
747
- * to evaluate, suggest or a warm-started solve as it stands.
748
- */
749
- plan: components["schemas"]["Plan"];
750
- /** @description One entry per non-empty route. */
751
- routes: components["schemas"]["Route"][];
752
- /** @description Aggregate statistics for the solve run. */
753
- summary: components["schemas"]["Summary"];
754
- /** @description Tasks that could not be feasibly assigned. */
755
- unassigned: components["schemas"]["Unassigned"][];
756
- } | components["schemas"]["ValidateOnlyResponse"];
757
- /**
758
- * @description The 200 body of solve, evaluate and suggest: the call's result, or with
759
- * `?validate_only=true` the validation verdict (`ValidateOnlyResponse`).
760
- */
761
- OrValidateOnly_SuggestResponse: {
762
- /**
763
- * Format: int64
764
- * @description Wall-clock time taken by the request, in milliseconds.
765
- * @example 8
766
- */
767
- elapsed_ms: number;
768
- /**
769
- * @description One entry per unit of tasks outside `plan`, in problem order (jobs,
770
- * then shipments; a relation group sorts at its first-listed member).
771
- */
772
- suggestions: components["schemas"]["JobSuggestions"][];
773
- /**
774
- * @description `true` when `options.time_limit_s` cut the search short, or a
775
- * multi-member unit came back empty after the search had discarded
776
- * candidates (an inconclusive "not found"; its `reason_code` is
777
- * `candidates_exhausted`). Lists may then be incomplete or missing the
778
- * best insertion. A single visit's only level is never pruned, so its
779
- * empty list is proof of infeasibility unless the budget cut it, and its
780
- * `reason_code` is then `time_limit`.
781
- */
782
- truncated?: boolean;
783
- } | components["schemas"]["ValidateOnlyResponse"];
784
921
  /**
785
922
  * @description The recurrence of a period limit (`limits.periods[].every`).
786
923
  * @enum {string}
@@ -791,8 +928,8 @@ export interface components {
791
928
  * Set exactly one of `every`, or `from` and `to`; and at least one maximum.
792
929
  * @example {
793
930
  * "every": "week",
794
- * "max_duration_s": 144000,
795
- * "max_tasks": 40
931
+ * "max_route_duration_s": 144000,
932
+ * "max_stops": 40
796
933
  * }
797
934
  */
798
935
  PeriodLimit: {
@@ -808,33 +945,35 @@ export interface components {
808
945
  from?: string | null;
809
946
  /**
810
947
  * Format: int64
811
- * @description Hard cap on the summed distance driven, in metres.
948
+ * @description Hard cap on the summed distance driven, in metres. Must be `>= 0`.
812
949
  * @example 900000
813
950
  */
814
951
  max_distance_m?: number | null;
815
952
  /**
816
953
  * Format: int64
817
- * @description Hard cap on the summed route span of the period's shifts, measured as
818
- * for `max_route_duration_s`. An unused shift adds nothing.
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`.
819
957
  * @example 144000
820
958
  */
821
- max_duration_s?: number | null;
959
+ max_route_duration_s?: number | null;
822
960
  /**
823
961
  * Format: int32
824
- * @description Hard cap on served stops, counted as a shift's `max_tasks` counts
825
- * 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.
826
965
  * @example 40
827
966
  */
828
- max_tasks?: number | null;
967
+ max_stops?: number | null;
829
968
  /**
830
969
  * Format: date-time
831
970
  * @description End of one explicit period (RFC 3339, UTC offset required, exclusive), with `from`.
832
971
  * @example 2026-10-12T00:00:00+02:00
833
972
  */
834
973
  to?: string | null;
835
- };
974
+ } & (unknown | unknown);
836
975
  /**
837
- * @description A place: a coordinate `[longitude, latitude]` in GeoJSON order — exactly two numbers. Tasks at the same coordinate are treated as one location.
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.
838
977
  * @example [
839
978
  * 3.725,
840
979
  * 51.05
@@ -930,44 +1069,77 @@ export interface components {
930
1069
  * "type": "pickup"
931
1070
  * }
932
1071
  */
933
- 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: {
934
1094
  /**
935
1095
  * @description Job id.
936
1096
  * @example boiler-17
937
1097
  */
938
1098
  id: string;
939
- /** @enum {string} */
1099
+ /**
1100
+ * @description Discriminator: always `job`. (enum property replaced by openapi-typescript)
1101
+ * @enum {string}
1102
+ */
940
1103
  type: "job";
941
- } | {
1104
+ };
1105
+ /**
1106
+ * PlanStopPickup
1107
+ * @description A shipment's pickup leg.
1108
+ */
1109
+ PlanStopPickup: {
942
1110
  /**
943
1111
  * @description The leg's stop id: its own `id`, else `{shipment}:pickup`.
944
1112
  * @example parts-9:pickup
945
1113
  */
946
1114
  id: string;
947
- /** @enum {string} */
948
- type: "pickup";
949
- } | {
950
1115
  /**
951
- * @description The leg's stop id: its own `id`, else `{shipment}:delivery`.
952
- * @example parts-9:delivery
1116
+ * @description Discriminator: always `pickup`. (enum property replaced by openapi-typescript)
1117
+ * @enum {string}
953
1118
  */
954
- id: string;
955
- /** @enum {string} */
956
- type: "delivery";
957
- } | {
1119
+ type: "pickup";
1120
+ };
1121
+ /**
1122
+ * PlanStopReload
1123
+ * @description A reload at a depot: the next trip starts there.
1124
+ */
1125
+ PlanStopReload: {
958
1126
  /**
959
1127
  * @description A depot id from the shift's `reloads`.
960
1128
  * @example gent
961
1129
  */
962
1130
  depot: string;
963
- /** @enum {string} */
1131
+ /**
1132
+ * @description Discriminator: always `reload`. (enum property replaced by openapi-typescript)
1133
+ * @enum {string}
1134
+ */
964
1135
  type: "reload";
965
1136
  };
966
1137
  /**
967
1138
  * @description The `type` of a plan stop.
968
- * @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.
969
1141
  */
970
- PlanStopType: "job" | "pickup" | "delivery" | "reload";
1142
+ PlanStopType: string;
971
1143
  /**
972
1144
  * @description How much road detail `routes[].polyline` carries.
973
1145
  *
@@ -987,27 +1159,6 @@ export interface components {
987
1159
  * @enum {string}
988
1160
  */
989
1161
  PolylineDetail: "simplified" | "full";
990
- /**
991
- * @description A soft vehicle affinity preference, priced.
992
- * @example {
993
- * "vehicle": "v1",
994
- * "violation_cost": 50
995
- * }
996
- */
997
- Preference: {
998
- /**
999
- * @description Preferred vehicle id.
1000
- * @example v1
1001
- */
1002
- vehicle: string;
1003
- /**
1004
- * Format: double
1005
- * @description Cost, in the objective's currency, incurred when a different vehicle
1006
- * serves the job. Must be finite and `>= 0`.
1007
- * @example 50
1008
- */
1009
- violation_cost: number;
1010
- };
1011
1162
  /**
1012
1163
  * @description The problem part of every V3 request body.
1013
1164
  * @example {
@@ -1027,7 +1178,7 @@ export interface components {
1027
1178
  * 3.725,
1028
1179
  * 51.05
1029
1180
  * ],
1030
- * "pickup": {
1181
+ * "pickup_load": {
1031
1182
  * "weight": 20
1032
1183
  * },
1033
1184
  * "service_duration_s": 300
@@ -1056,22 +1207,28 @@ export interface components {
1056
1207
  * ]
1057
1208
  * }
1058
1209
  */
1059
- ProblemInput: {
1210
+ Problem: {
1060
1211
  /** @description Depots that shifts start from, end at, or reload at, by id. */
1061
1212
  depots?: components["schemas"]["Depot"][];
1062
- /** @description Single-stop visits to serve. */
1063
- jobs?: components["schemas"]["Visit"][];
1213
+ /**
1214
+ * @description Single-stop visits to serve. At most 10,000 tasks per request, `jobs`
1215
+ * and `shipments` combined (HTTP 400 `limit_exceeded` beyond that).
1216
+ */
1217
+ jobs?: components["schemas"]["Job"][];
1064
1218
  /** @description Objective configuration. */
1065
1219
  objective?: null | components["schemas"]["Objective"];
1066
- /** @description Stop caps shared by a set of vehicles. */
1220
+ /** @description Stop caps shared by a set of vehicles. At most 65,535. */
1067
1221
  quotas?: components["schemas"]["Quota"][];
1068
- /** @description Ordering, grouping, and synchronization constraints. */
1222
+ /** @description Ordering, co-assignment and synchronization constraints. */
1069
1223
  relations?: components["schemas"]["Relation"][] | null;
1070
- /** @description Bound pickup→delivery shipments to serve. */
1224
+ /**
1225
+ * @description Bound pickup→delivery shipments to serve. Counts toward the same
1226
+ * 10,000-task cap as `jobs`.
1227
+ */
1071
1228
  shipments?: components["schemas"]["Shipment"][];
1072
1229
  /** @description Where travel times and distances come from. */
1073
1230
  travel?: null | components["schemas"]["Travel"];
1074
- /** @description Available vehicles. */
1231
+ /** @description Available vehicles: 1 to 2,000 (HTTP 400 otherwise). */
1075
1232
  vehicles: components["schemas"]["Vehicle"][];
1076
1233
  };
1077
1234
  /**
@@ -1081,21 +1238,39 @@ export interface components {
1081
1238
  */
1082
1239
  Profile: "car" | "truck" | "bike";
1083
1240
  /**
1084
- * @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
1085
1259
  * in a window. A stop counts when its service starts in `[from, to)`
1086
- * (`arrival + wait_s` in the response); without a window every stop counts.
1087
- * 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
1088
1263
  * over-cap job is left unassigned. Unlike `limits.periods[]`, which counts a
1089
1264
  * shift by its start, a quota has no `every` recurrence and caps only stop
1090
1265
  * counts.
1091
1266
  * @example {
1092
1267
  * "id": "pool-install",
1093
- * "job_ids": [
1268
+ * "max_stops": 2,
1269
+ * "tasks": [
1094
1270
  * "j1",
1095
1271
  * "j2",
1096
1272
  * "j3"
1097
1273
  * ],
1098
- * "max_tasks": 2,
1099
1274
  * "vehicles": [
1100
1275
  * "c0",
1101
1276
  * "c1"
@@ -1105,7 +1280,9 @@ export interface components {
1105
1280
  Quota: {
1106
1281
  /**
1107
1282
  * Format: date-time
1108
- * @description Window start (RFC 3339, UTC offset required), with `to`.
1283
+ * @description Window start (RFC 3339, UTC offset required), with `to`. The window
1284
+ * must overlap a shift of one of `vehicles` (counting its
1285
+ * `max_overtime_s`), else the request is rejected with HTTP 400.
1109
1286
  * @example 2026-10-05T00:00:00+02:00
1110
1287
  */
1111
1288
  from?: string | null;
@@ -1114,20 +1291,28 @@ export interface components {
1114
1291
  * `/evaluate` `quota` violation.
1115
1292
  */
1116
1293
  id: string;
1117
- /** @description Job or shipment ids whose stops count, each at most once. */
1118
- job_ids: string[];
1119
1294
  /**
1120
1295
  * Format: int32
1121
- * @description The cap on counted stops.
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.
1299
+ */
1300
+ max_stops: number;
1301
+ /**
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.
1122
1304
  */
1123
- max_tasks: number;
1305
+ tasks: string[];
1124
1306
  /**
1125
1307
  * Format: date-time
1126
1308
  * @description Window end (RFC 3339, UTC offset required, exclusive), with `from`.
1127
1309
  * @example 2026-10-06T00:00:00+02:00
1128
1310
  */
1129
1311
  to?: string | null;
1130
- /** @description Vehicle ids that share the cap, each at most once. */
1312
+ /**
1313
+ * @description Vehicle ids that share the cap, each at most once. At least one; an id
1314
+ * that names no vehicle is rejected with HTTP 400.
1315
+ */
1131
1316
  vehicles: string[];
1132
1317
  };
1133
1318
  /**
@@ -1137,17 +1322,22 @@ export interface components {
1137
1322
  * Each type carries only its own fields; any other `type` is rejected with
1138
1323
  * HTTP 400.
1139
1324
  *
1140
- * Members are named by `stops` (stop ids). `same_vehicle`, `same_day` and
1325
+ * Members are named by `stops` (job ids, or shipment-leg stop ids where
1326
+ * the type accepts them, see below). `same_vehicle`, `same_day` and
1141
1327
  * `same_route` take **either** `stops` **or** a `tag`, not both. Every
1142
1328
  * relation is hard.
1143
1329
  *
1144
- * Relations constrain jobs, not shipments. A shipment id in the `stops` of
1145
- * a `sequence`, `same_vehicle`, `same_day` or `synchronized` relation, and
1146
- * a shipment carrying the `tag` of a `same_vehicle` or `same_day` relation,
1147
- * passes validation but is skipped: the request returns HTTP 200 and the
1148
- * relation does not constrain that shipment. `same_route`, `time_lag`,
1149
- * `compatible_vehicles`, `all_or_none` and `tag_order` reject a shipment
1150
- * with HTTP 400.
1330
+ * A shipment takes part through its legs: `sequence`, `same_vehicle`,
1331
+ * `same_day` and `same_route` accept a leg's stop id (`pickup.id` /
1332
+ * `delivery.id`, by default `"{shipment}:pickup"` / `":delivery"`) and bind
1333
+ * that leg like a job. A leg coupled to other tasks by a `synchronized` or
1334
+ * `time_lag` relation (directly, or through a `sequence` with a member that
1335
+ * is) is rejected with HTTP 400, as is a `sequence` putting a delivery before
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.
1151
1341
  * @example {
1152
1342
  * "stops": [
1153
1343
  * "job-1",
@@ -1156,119 +1346,259 @@ export interface components {
1156
1346
  * "type": "sequence"
1157
1347
  * }
1158
1348
  */
1159
- 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: {
1160
1363
  /**
1161
- * @description Job or shipment ids, in the order they must be served. A shipment
1162
- * is named by its id, not by a leg's stop id (stop-id members are
1163
- * not resolved yet).
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
+ * ]
1164
1370
  */
1165
1371
  stops: string[];
1166
- /** @enum {string} */
1167
- type: "sequence";
1168
- } | {
1169
- /** @description Tag labels in precedence order. Requires at least 2 entries. */
1170
- tags: string[];
1171
- /** @enum {string} */
1172
- type: "tag_order";
1173
- } | {
1174
1372
  /**
1175
- * @description Job or shipment ids in the relation (mutually exclusive with
1176
- * `tag`; stop-id members are not resolved yet).
1373
+ * @description Discriminator: always `all_or_none`. (enum property replaced by openapi-typescript)
1374
+ * @enum {string}
1177
1375
  */
1178
- stops?: string[] | null;
1179
- /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1180
- tag?: string | null;
1181
- /** @enum {string} */
1182
- type: "same_vehicle";
1183
- } | {
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: {
1184
1422
  /**
1185
- * @description Job or shipment ids in the relation (mutually exclusive with
1186
- * `tag`; stop-id members are not resolved yet).
1423
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1424
+ * exclusive with `tag`). A shipment's own id is rejected with
1425
+ * HTTP 400 `not_supported`.
1187
1426
  */
1188
1427
  stops?: string[] | null;
1189
1428
  /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1190
1429
  tag?: string | null;
1191
- /** @enum {string} */
1430
+ /**
1431
+ * @description Discriminator: always `same_day`. (enum property replaced by openapi-typescript)
1432
+ * @enum {string}
1433
+ */
1192
1434
  type: "same_day";
1193
- } | {
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: {
1194
1445
  /**
1195
- * @description Job or shipment ids in the relation (mutually exclusive with
1196
- * `tag`; stop-id members are not resolved yet).
1446
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1447
+ * exclusive with `tag`). A shipment's own id is rejected with HTTP
1448
+ * 400.
1197
1449
  */
1198
1450
  stops?: string[] | null;
1199
1451
  /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1200
1452
  tag?: string | null;
1201
- /** @enum {string} */
1202
- type: "same_route";
1203
- } | {
1204
1453
  /**
1205
- * Format: int64
1206
- * @description Maximum spread between the synchronized instants in seconds
1207
- * (`0` = exact simultaneity). Required. A negative value is rejected
1208
- * with HTTP 400 `out_of_range`.
1454
+ * @description Discriminator: always `same_route`. (enum property replaced by openapi-typescript)
1455
+ * @enum {string}
1209
1456
  */
1210
- max_wait_s: number;
1457
+ type: "same_route";
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: {
1211
1465
  /**
1212
- * @description Which instant is synchronized: the service `start` (default) or
1213
- * the service `end`. `arrival` is rejected with HTTP 400.
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`.
1214
1469
  */
1215
- on?: null | components["schemas"]["StopInstant"];
1470
+ stops?: string[] | null;
1471
+ /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1472
+ tag?: string | null;
1216
1473
  /**
1217
- * @description Participating job or shipment ids (stop-id members are not
1218
- * resolved yet).
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: {
1511
+ /**
1512
+ * Format: int64
1513
+ * @description Maximum spread between the synchronized instants in seconds
1514
+ * (`0` = exact simultaneity). Required. A negative value, or one that
1515
+ * does not fit in 32 bits, is rejected with HTTP 400 `out_of_range`.
1516
+ */
1517
+ max_spread_s: number;
1518
+ /**
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
1522
+ */
1523
+ on?: null | components["schemas"]["RelationInstant"];
1524
+ /**
1525
+ * @description Participating job ids, at most 8 (HTTP 400 `limit_exceeded`
1526
+ * beyond that). A shipment-leg stop id is rejected with HTTP 400;
1527
+ * a shipment's own id with HTTP 400 `not_supported`.
1219
1528
  */
1220
1529
  stops: string[];
1221
- /** @enum {string} */
1530
+ /**
1531
+ * @description Discriminator: always `synchronized`. (enum property replaced by openapi-typescript)
1532
+ * @enum {string}
1533
+ */
1222
1534
  type: "synchronized";
1223
- } | {
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: {
1224
1571
  /** @description The reference end. */
1225
- from: components["schemas"]["TimeLagEnd"];
1572
+ from: components["schemas"]["TimeLagMember"];
1226
1573
  /**
1227
1574
  * Format: int64
1228
1575
  * @description Upper bound on `t(to) − t(from)` in seconds. Absent = unbounded.
1576
+ * Must fit in 32 bits and be `>= min_s` (HTTP 400 otherwise).
1229
1577
  */
1230
1578
  max_s?: number | null;
1231
1579
  /**
1232
1580
  * Format: int64
1233
- * @description Lower bound on `t(to) − t(from)` in seconds. Default `0`.
1581
+ * @description Lower bound on `t(to) − t(from)` in seconds. Default `0`. Must fit
1582
+ * in 32 bits.
1583
+ * @default 0
1234
1584
  */
1235
1585
  min_s?: number | null;
1236
1586
  /** @description The bounded end. */
1237
- to: components["schemas"]["TimeLagEnd"];
1238
- /** @enum {string} */
1239
- type: "time_lag";
1240
- } | {
1241
- /**
1242
- * @description Job or shipment ids, at least two (stop-id members are not
1243
- * resolved yet).
1244
- * @example [
1245
- * "job-1",
1246
- * "job-2"
1247
- * ]
1248
- */
1249
- stops: string[];
1250
- /** @enum {string} */
1251
- type: "compatible_vehicles";
1252
- } | {
1587
+ to: components["schemas"]["TimeLagMember"];
1253
1588
  /**
1254
- * @description Job ids, at least two.
1255
- * @example [
1256
- * "job-1",
1257
- * "job-2"
1258
- * ]
1589
+ * @description Discriminator: always `time_lag`. (enum property replaced by openapi-typescript)
1590
+ * @enum {string}
1259
1591
  */
1260
- stops: string[];
1261
- /** @enum {string} */
1262
- type: "all_or_none";
1592
+ type: "time_lag";
1263
1593
  };
1264
1594
  /**
1265
1595
  * @description A best-effort, actionable suggestion for relaxing the problem so a task can be
1266
1596
  * assigned — derived from the smallest constraint relaxation the solver found.
1267
1597
  * @example {
1268
1598
  * "amount": 900,
1269
- * "field": "/jobs/job-2/time_windows",
1599
+ * "message": "Extend a time window by 900s (~15 min).",
1270
1600
  * "op": "extend_time_window",
1271
- * "suggestion": "Extend a time window by 900s (~15 min).",
1601
+ * "pointer": "/problem/jobs/1/time_windows",
1272
1602
  * "unit": "s"
1273
1603
  * }
1274
1604
  */
@@ -1279,37 +1609,60 @@ export interface components {
1279
1609
  * @example 900
1280
1610
  */
1281
1611
  amount: number;
1282
- /**
1283
- * @description Names the task and the field to change. For a job: `/jobs/{id}/pickup`
1284
- * (`/jobs/{id}/delivery` for a job with only a `delivery`) or
1285
- * `/jobs/{id}/time_windows`. For a shipment: `/shipments/{id}/load` or
1286
- * `/shipments/{id}/pickup/time_windows` (either leg's window may be the
1287
- * one to extend). `{id}` is the task id, the same value as `job_id`. It is
1288
- * a label, not a JSON Pointer into the request body: it uses the id, not
1289
- * the array index, and has no `/problem` prefix.
1290
- * @example /jobs/job-2/time_windows
1291
- */
1292
- field: string;
1293
- /** @description The kind of change suggested. */
1294
- op: components["schemas"]["RelaxationOp"];
1295
1612
  /**
1296
1613
  * @description Human-readable suggestion.
1297
1614
  * @example Extend a time window by 900s (~15 min).
1298
1615
  */
1299
- suggestion: string;
1616
+ message: string;
1617
+ /** @description The kind of change suggested. */
1618
+ op: components["schemas"]["RelaxationOp"];
1300
1619
  /**
1301
- * @description Unit of `amount`: `"s"` (seconds, for `extend_time_window`) or
1302
- * `"load"` (demand units, for `reduce_demand`).
1303
- * @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
1304
1630
  */
1305
- unit: string;
1631
+ pointer: string;
1632
+ /** @description Unit of `amount`: `s` for `extend_time_window`, `load` for `reduce_load`. */
1633
+ unit: components["schemas"]["QuantityUnit"];
1306
1634
  };
1307
1635
  /**
1308
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.
1309
1639
  * @example extend_time_window
1310
- * @enum {string}
1311
1640
  */
1312
- 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
+ };
1313
1666
  /**
1314
1667
  * @description A single vehicle's route.
1315
1668
  * @example {
@@ -1347,6 +1700,7 @@ export interface components {
1347
1700
  * 51.05
1348
1701
  * ],
1349
1702
  * "service_s": 300,
1703
+ * "service_start": "2026-07-01T09:00:00+02:00",
1350
1704
  * "travel_s": 600,
1351
1705
  * "type": "job",
1352
1706
  * "wait_s": 3000
@@ -1365,6 +1719,7 @@ export interface components {
1365
1719
  * 51.06
1366
1720
  * ],
1367
1721
  * "service_s": 600,
1722
+ * "service_start": "2026-07-01T09:13:00+02:00",
1368
1723
  * "travel_s": 480,
1369
1724
  * "type": "job",
1370
1725
  * "wait_s": 0
@@ -1383,7 +1738,8 @@ export interface components {
1383
1738
  * ],
1384
1739
  * "service_s": 0,
1385
1740
  * "travel_s": 900,
1386
- * "type": "end"
1741
+ * "type": "end",
1742
+ * "wait_s": 0
1387
1743
  * }
1388
1744
  * ],
1389
1745
  * "time": {
@@ -1406,11 +1762,11 @@ export interface components {
1406
1762
  */
1407
1763
  distance_m: number;
1408
1764
  /** @description Peak load reached on the route, by named dimension. */
1409
- load_peak?: null | components["schemas"]["BTreeMap"];
1765
+ load_peak?: null | components["schemas"]["Quantities"];
1410
1766
  /**
1411
1767
  * @description Road geometry for this route as an [encoded polyline] at precision 5
1412
1768
  * (~1.1 m), ready to hand to a map library. Present only when
1413
- * `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
1414
1770
  * routing engine could not produce.
1415
1771
  *
1416
1772
  * Traced with this vehicle's `profile` at the solve's departure time, so
@@ -1427,8 +1783,14 @@ export interface components {
1427
1783
  * @example mon
1428
1784
  */
1429
1785
  shift: string;
1430
- /** @description Ordered stops, including depot bookends. */
1431
- 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"][];
1432
1794
  /**
1433
1795
  * @description Where this route's time goes. `time.span_s` is what the route's
1434
1796
  * `costs.per_route_hour` is charged on: the shift's rate, else its
@@ -1438,7 +1800,7 @@ export interface components {
1438
1800
  /** @description The vehicle id (`vehicle.id` from the request) serving this route. */
1439
1801
  vehicle: string;
1440
1802
  /**
1441
- * @description Route-level constraint violations (e.g. `max_distance`, `max_duration`,
1803
+ * @description Route-level constraint violations (e.g. `max_distance`, `max_route_duration`,
1442
1804
  * or `unreachable` for a leg whose destination is not a job stop — the
1443
1805
  * return to the end depot, or a leg into a reload).
1444
1806
  * Only populated by `POST /v3/routing/evaluate`; absent on solve responses.
@@ -1446,28 +1808,223 @@ export interface components {
1446
1808
  violations?: components["schemas"]["Violation"][];
1447
1809
  };
1448
1810
  /**
1449
- * @description How good a plan is. Plans compare in order: fewer `violations` first,
1450
- * 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`.
1451
2006
  * @example {
1452
2007
  * "components": {
1453
- * "depot_visits": 0,
2008
+ * "assignment": 0,
1454
2009
  * "distance": 1.69,
1455
- * "drop_fees": 0,
1456
- * "fixed": 0,
2010
+ * "drop_costs": 0,
1457
2011
  * "grouping": 0,
1458
2012
  * "lateness": 0,
1459
- * "other": 0,
1460
2013
  * "overtime": 0,
2014
+ * "preferences": 0,
2015
+ * "reloads": 0,
2016
+ * "routes": 0,
1461
2017
  * "tag_preference": 0,
1462
2018
  * "target": 0,
1463
2019
  * "time": 57.1536,
1464
2020
  * "waiting": 0,
1465
- * "window_choice": 0
2021
+ * "window_choice": 0,
2022
+ * "workload_share": 0
1466
2023
  * },
1467
2024
  * "cost": 58.8436,
1468
2025
  * "currency": "EUR",
1469
- * "unserved_priority": 0,
1470
- * "violations": 0
2026
+ * "unassigned_priority": 0,
2027
+ * "violation_count": 0
1471
2028
  * }
1472
2029
  */
1473
2030
  Score: {
@@ -1487,43 +2044,47 @@ export interface components {
1487
2044
  /**
1488
2045
  * Format: int64
1489
2046
  * @description Summed `priority` of the required tasks left unassigned (a task that
1490
- * priced a `drop_fee` counts in `components.drop_fees` instead).
2047
+ * priced a `drop_cost` counts in `components.drop_costs` instead).
1491
2048
  * @example 0
1492
2049
  */
1493
- unserved_priority: number;
2050
+ unassigned_priority: number;
1494
2051
  /**
1495
2052
  * Format: int32
1496
- * @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.
1497
2055
  * @example 0
1498
2056
  */
1499
- violations: number;
2057
+ violation_count: number;
1500
2058
  };
1501
2059
  /**
1502
2060
  * @description The money of each objective term, in the objective's currency. The
1503
2061
  * components always sum to `score.cost` exactly: every term the solver
1504
2062
  * charges lands in exactly one of them.
1505
2063
  * @example {
1506
- * "depot_visits": 0,
2064
+ * "assignment": 0,
1507
2065
  * "distance": 1.69,
1508
- * "drop_fees": 0,
1509
- * "fixed": 0,
2066
+ * "drop_costs": 0,
1510
2067
  * "grouping": 0,
1511
2068
  * "lateness": 0,
1512
- * "other": 0,
1513
2069
  * "overtime": 0,
2070
+ * "preferences": 0,
2071
+ * "reloads": 0,
2072
+ * "routes": 0,
1514
2073
  * "tag_preference": 0,
1515
2074
  * "target": 0,
1516
2075
  * "time": 57.1536,
1517
2076
  * "waiting": 0,
1518
- * "window_choice": 0
2077
+ * "window_choice": 0,
2078
+ * "workload_share": 0
1519
2079
  * }
1520
2080
  */
1521
2081
  ScoreComponents: {
1522
2082
  /**
1523
2083
  * Format: double
1524
- * @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.
1525
2086
  */
1526
- depot_visits: number;
2087
+ assignment: number;
1527
2088
  /**
1528
2089
  * Format: double
1529
2090
  * @description Distance cost, in currency units: each route's distance priced at
@@ -1532,15 +2093,9 @@ export interface components {
1532
2093
  distance: number;
1533
2094
  /**
1534
2095
  * Format: double
1535
- * @description The summed `drop_fee` of the tasks left unassigned, in currency units.
1536
- */
1537
- drop_fees: number;
1538
- /**
1539
- * Format: double
1540
- * @description Vehicle cost, in currency units: `costs.fixed` once per used shift,
1541
- * at the shift's, vehicle's or fleet's rate.
2096
+ * @description The summed `drop_cost` of the tasks left unassigned, in currency units.
1542
2097
  */
1543
- fixed: number;
2098
+ drop_costs: number;
1544
2099
  /**
1545
2100
  * Format: double
1546
2101
  * @description Cost of splitting close tasks across routes, in currency units
@@ -1553,19 +2108,30 @@ export interface components {
1553
2108
  * (`objective.per_late_hour` or `time_windows[].per_late_hour`).
1554
2109
  */
1555
2110
  lateness: number;
1556
- /**
1557
- * Format: double
1558
- * @description Everything else the solver charges, in currency units: vehicle
1559
- * preferences (`preferences[].violation_cost`) and the
1560
- * non-preferred-date cost.
1561
- */
1562
- other: number;
1563
2111
  /**
1564
2112
  * Format: double
1565
2113
  * @description Cost of work past a soft shift end, in currency units: priced at the
1566
2114
  * route's `costs.per_overtime_hour`.
1567
2115
  */
1568
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;
1569
2135
  /**
1570
2136
  * Format: double
1571
2137
  * @description Cost of serving tasks outside a vehicle's `preferred_tags`, in
@@ -1587,7 +2153,8 @@ export interface components {
1587
2153
  /**
1588
2154
  * Format: double
1589
2155
  * @description Cost of waiting for time windows to open, in currency units: each
1590
- * 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.
1591
2158
  */
1592
2159
  waiting: number;
1593
2160
  /**
@@ -1596,7 +2163,31 @@ export interface components {
1596
2163
  * units (`time_windows[].cost`).
1597
2164
  */
1598
2165
  window_choice: number;
2166
+ /**
2167
+ * Format: double
2168
+ * @description Workload outside the equal-share band, in currency units
2169
+ * (`objective.workload_share`).
2170
+ */
2171
+ workload_share: number;
2172
+ };
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"];
1599
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;
1600
2191
  /**
1601
2192
  * @description Per-vehicle work-rate override for one task's `service_duration_s`.
1602
2193
  * @example {
@@ -1607,9 +2198,14 @@ export interface components {
1607
2198
  ServiceFactor: {
1608
2199
  /**
1609
2200
  * Format: double
1610
- * @description Same meaning, direction and `(0, 5]` range as `vehicles[].service_factor`:
1611
- * effective service time = `service_duration_s / (vehicle_or_shift_factor * factor)`.
1612
- * `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.
1613
2209
  * @example 1.25
1614
2210
  */
1615
2211
  factor: number;
@@ -1651,7 +2247,7 @@ export interface components {
1651
2247
  * vehicle's value for that dimension; dimensions not named keep the
1652
2248
  * vehicle's `capacity`.
1653
2249
  */
1654
- capacity?: null | components["schemas"]["BTreeMap"];
2250
+ capacity?: null | components["schemas"]["Quantities"];
1655
2251
  /**
1656
2252
  * @description Costs for this shift only. Each field set here replaces the same
1657
2253
  * field of the vehicle's `costs` (or, when the vehicle does not set it,
@@ -1659,7 +2255,23 @@ export interface components {
1659
2255
  */
1660
2256
  costs?: null | components["schemas"]["Costs"];
1661
2257
  /** @description Where the shift ends. Absent = open end. */
1662
- 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;
1663
2275
  /**
1664
2276
  * Format: date-time
1665
2277
  * @description Shift start (RFC 3339 instant, UTC offset required).
@@ -1671,22 +2283,6 @@ export interface components {
1671
2283
  * @example mon
1672
2284
  */
1673
2285
  id: string;
1674
- /**
1675
- * @description Symmetric to `ignore_start_leg` for the last-task → `end` leg.
1676
- * @example false
1677
- */
1678
- ignore_end_leg?: boolean | null;
1679
- /**
1680
- * @description When `true`, the `start` → first-task leg costs nothing (not counted
1681
- * in objective, feasibility timing, or total distance/duration) — the
1682
- * depot is still known and reported (a real stop, snapped coordinate,
1683
- * departure time). Distinct from omitting `start` (a fully open route,
1684
- * which drops the depot entirely): this keeps the depot visible while
1685
- * making the leg to it free. Requires `start`; a no-op when `start` is
1686
- * absent. Default `false`.
1687
- * @example false
1688
- */
1689
- ignore_start_leg?: boolean | null;
1690
2286
  /**
1691
2287
  * @description Load already on the vehicle at shift start (pre-loaded), per
1692
2288
  * dimension. Occupies capacity on the first trip only — flushed at the
@@ -1698,7 +2294,7 @@ export interface components {
1698
2294
  * HTTP 400. A dimension named here but absent from `capacity` behaves
1699
2295
  * the same as capacity `0` in that dimension.
1700
2296
  */
1701
- initial_load?: null | components["schemas"]["BTreeMap"];
2297
+ initial_load?: null | components["schemas"]["Quantities"];
1702
2298
  /**
1703
2299
  * @description Limits for this shift only. Each field set here replaces the
1704
2300
  * vehicle's `limits` value; fields not set keep it.
@@ -1708,7 +2304,7 @@ export interface components {
1708
2304
  * Format: int32
1709
2305
  * @description Maximum allowed overtime beyond `to` in seconds. Overtime is reached
1710
2306
  * by working late, never by waiting: a `synchronized` or `time_lag`
1711
- * hold stops at `to`.
2307
+ * hold stops at `to`. Default: none (`to` is hard). Must be `>= 0`.
1712
2308
  * @example 1800
1713
2309
  */
1714
2310
  max_overtime_s?: number | null;
@@ -1719,17 +2315,18 @@ export interface components {
1719
2315
  * means a single trip — reloads are permitted in `reloads` but the cap
1720
2316
  * prevents ever using one. `reloads` present with `max_trips` absent
1721
2317
  * means unlimited trips. A single reload depot can only be
1722
- * revisited up to 8 times per vehicle regardless of `max_trips`;
2318
+ * revisited up to 8 times per shift regardless of `max_trips`;
1723
2319
  * a `max_trips` beyond that against one depot
1724
2320
  * is accepted but the extra headroom is unreachable — list more than
1725
- * one reload depot to raise the practical ceiling.
2321
+ * one reload depot to raise the practical ceiling. `0` is rejected with
2322
+ * HTTP 400 (the first trip already counts as trip 1).
1726
2323
  * @example 2
1727
2324
  */
1728
2325
  max_trips?: number | null;
1729
2326
  /**
1730
2327
  * @description Depots (by `depots[].id`, each at most once) the vehicle may return to
1731
2328
  * mid-shift to reload and start a fresh trip. Each visit takes that
1732
- * depot's `service_duration_s` and `cost_per_visit`. Cap trips with
2329
+ * depot's `service_duration_s` and `per_reload`. Cap trips with
1733
2330
  * `max_trips`.
1734
2331
  */
1735
2332
  reloads?: string[] | null;
@@ -1741,12 +2338,14 @@ export interface components {
1741
2338
  serves_tags?: string[] | null;
1742
2339
  /**
1743
2340
  * Format: double
1744
- * @description Work-rate multiplier for this shift only, overriding
1745
- * `vehicles[].service_factor` when set (absent = inherit the vehicle's
1746
- * 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.
1747
2345
  *
1748
- * Same meaning, direction, and `(0, 5]` range as the vehicle-level field:
1749
- * 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
1750
2349
  * when the same driver works at a different rate on different days — a
1751
2350
  * measured per-day efficiency, a trainee shift, a two-person crew on
1752
2351
  * Fridays — instead of collapsing those days into one vehicle-level mean.
@@ -1761,14 +2360,14 @@ export interface components {
1761
2360
  * @description Capabilities this shift provides, replacing the vehicle's `skills`
1762
2361
  * for this shift only (a technician covering another region on one
1763
2362
  * day, a crew that only carries a certification on some shifts). A
1764
- * 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
1765
2364
  * serves it, at a level of at least the job's `min_level`. Same entry
1766
2365
  * shape as `vehicles[].skills`. Absent = the vehicle's `skills`; `[]` =
1767
2366
  * this shift provides none.
1768
2367
  */
1769
2368
  skills?: components["schemas"]["VehicleSkill"][] | null;
1770
2369
  /** @description Where the shift starts. Absent = open start. */
1771
- start?: null | components["schemas"]["ShiftEnd"];
2370
+ start?: null | components["schemas"]["ShiftPlace"];
1772
2371
  /**
1773
2372
  * Format: date-time
1774
2373
  * @description Shift end (RFC 3339 instant, UTC offset required; hard unless `max_overtime_s` set). The
@@ -1778,62 +2377,65 @@ export interface components {
1778
2377
  to: string;
1779
2378
  };
1780
2379
  /**
1781
- * @description Where a shift starts or ends: exactly one of `location` or `depot`.
2380
+ * @description Per-shift limits: the route-level `limits` fields a shift may override.
2381
+ * Period limits apply across shifts, so they stay on the vehicle.
1782
2382
  * @example {
1783
- * "depot": "gent"
2383
+ * "max_stops": 12
1784
2384
  * }
1785
2385
  */
1786
- ShiftEnd: {
2386
+ ShiftLimits: {
1787
2387
  /**
1788
- * @description A `depots[].id`. Excludes `location`.
1789
- * @example gent
2388
+ * Format: int64
2389
+ * @description Hard cap on this shift's route distance, in metres. `0` to
2390
+ * `2147483647`, as on the vehicle.
2391
+ * @example 200000
1790
2392
  */
1791
- depot?: string | null;
1792
- /** @description An inline place. Excludes `depot`. */
1793
- location?: null | components["schemas"]["Place"];
2393
+ max_distance_m?: number | null;
2394
+ /**
2395
+ * Format: int64
2396
+ * @description Hard cap on this shift's route span, in seconds. `0` to
2397
+ * `2147483647`, as on the vehicle.
2398
+ * @example 32400
2399
+ */
2400
+ max_route_duration_s?: number | null;
1794
2401
  /**
1795
2402
  * Format: int32
1796
- * @description Handling time in seconds at this end: the morning load at `start`, the
1797
- * evening unload at `end`. Overrides the depot's `service_duration_s`;
1798
- * default: the depot's value, or 0 for a `location` end. Not applied on
1799
- * an ignored leg (`ignore_start_leg`/`ignore_end_leg`). Not scaled by
1800
- * `service_factor`.
1801
- *
1802
- * The unload must finish by the shift's `to` (or `to + max_overtime_s`):
1803
- * a route whose unload would run past it is infeasible. A shift whose
1804
- * load and unload alone exceed it is rejected with HTTP 400.
1805
- * @example 600
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.
2406
+ * @example 50
1806
2407
  */
1807
- service_duration_s?: number | null;
2408
+ max_stops?: number | null;
1808
2409
  };
1809
2410
  /**
1810
- * @description Per-shift limits: the route-level `limits` fields a shift may override.
1811
- * Period limits apply across shifts, so they stay on the vehicle.
2411
+ * @description Where a shift starts or ends: exactly one of `location` or `depot`.
1812
2412
  * @example {
1813
- * "max_tasks": 12
2413
+ * "depot": "gent"
1814
2414
  * }
1815
2415
  */
1816
- ShiftLimits: {
1817
- /**
1818
- * Format: int64
1819
- * @description Hard cap on this shift's route distance, in metres.
1820
- * @example 200000
1821
- */
1822
- max_distance_m?: number | null;
2416
+ ShiftPlace: {
1823
2417
  /**
1824
- * Format: int64
1825
- * @description Hard cap on this shift's route span, in seconds.
1826
- * @example 32400
2418
+ * @description A `depots[].id`. Excludes `location`.
2419
+ * @example gent
1827
2420
  */
1828
- max_route_duration_s?: number | null;
2421
+ depot?: string | null;
2422
+ /** @description An inline place. Excludes `depot`. */
2423
+ location?: null | components["schemas"]["Place"];
1829
2424
  /**
1830
2425
  * Format: int32
1831
- * @description Maximum stops served in this shift: a job counts as one stop, a
1832
- * shipment as two (pickup and delivery).
1833
- * @example 50
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
1834
2436
  */
1835
- max_tasks?: number | null;
1836
- };
2437
+ service_duration_s?: number | null;
2438
+ } & (unknown | unknown);
1837
2439
  /**
1838
2440
  * @description A vehicle and one of its shifts: the key of a plan route.
1839
2441
  * @example {
@@ -1853,7 +2455,7 @@ export interface components {
1853
2455
  * Two stops served by one vehicle, pickup strictly before delivery, with
1854
2456
  * `load` carried on the vehicle between the two legs.
1855
2457
  *
1856
- * `drop_fee` and vehicle eligibility (`eligible_vehicles`, allow
2458
+ * `drop_cost` and vehicle eligibility (`eligible_vehicles`, allow
1857
2459
  * **and** exclude, any length) are fully supported and applied to both legs — a
1858
2460
  * shipment's pickup and delivery share one droppability/eligibility decision,
1859
2461
  * since one vehicle must serve both.
@@ -1886,29 +2488,36 @@ export interface components {
1886
2488
  * `preferences`, which charges the vehicles that did NOT get the task,
1887
2489
  * this prices the vehicle that did, so a task rated badly everywhere is
1888
2490
  * the first one dropped when capacity runs out. It lives in the cost tier,
1889
- * below `priority`, and adds to `preferences`, `drop_fee` and travel.
2491
+ * below `priority`, and adds to `preferences`, `drop_cost` and travel.
1890
2492
  * Not applied by decomposition: a problem that sets it solves monolithically.
1891
2493
  */
1892
2494
  assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
1893
2495
  /** @description Delivery leg (load off). */
1894
- delivery: components["schemas"]["Stop"];
2496
+ delivery: components["schemas"]["ShipmentStop"];
1895
2497
  /**
1896
2498
  * Format: double
1897
2499
  * @description Drop **price** — what leaving this task unserved costs you, in the same
1898
2500
  * currency as `objective.costs`, and the only way to make a task
1899
- * droppable. Tasks without a `drop_fee` must be served.
2501
+ * droppable. Tasks without a `drop_cost` must be served.
1900
2502
  *
1901
2503
  * This is money, not a priority: it enters the same cost the solver
1902
2504
  * minimises, so the task is served only while serving it costs less than
1903
- * the fee. Fees the plan chose to pay are reported in
1904
- * `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`.
1905
2507
  *
1906
- * On a shipment the fee applies to the pair, charged once.
2508
+ * On a shipment the drop cost applies to the pair, charged once.
2509
+ *
2510
+ * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
2511
+ * is rejected with HTTP 400 (`conflicting_fields`).
1907
2512
  * @example 25
1908
2513
  */
1909
- drop_fee?: number | null;
1910
- /** @description Hard vehicle allow/exclude. */
1911
- eligible_vehicles?: null | components["schemas"]["Eligibility"];
2514
+ drop_cost?: number | null;
2515
+ /**
2516
+ * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
2517
+ * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
2518
+ * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
2519
+ */
2520
+ eligible_vehicles?: null | components["schemas"]["VehicleEligibility"];
1912
2521
  /**
1913
2522
  * @description Shipment id: 1 to 128 characters, unique across `jobs` + `shipments`.
1914
2523
  * @example ship-1
@@ -1919,80 +2528,50 @@ export interface components {
1919
2528
  * the same quantity dropped off at the other. Non-negative magnitudes
1920
2529
  * per named dimension.
1921
2530
  */
1922
- load?: null | components["schemas"]["BTreeMap"];
1923
- /**
1924
- * @description Hard-pin this job to one vehicle id — only that vehicle (any of its
1925
- * shifts) may serve it, and once placed, re-optimization never removes it
1926
- * or moves it to another vehicle. Stronger than `eligible_vehicles`
1927
- * (which filters a set) and hard, unlike `preferences`.
1928
- *
1929
- * A pin means "stays on this vehicle if placed", **not** "must be
1930
- * served": the task can still end up unassigned (for example when it does
1931
- * not fit), and with a `drop_fee` it then pays the fee. An id that
1932
- * matches no vehicle is rejected with HTTP 400.
1933
- * @example vehicle-1
1934
- */
1935
- locked_vehicle?: string | null;
2531
+ load?: null | components["schemas"]["Quantities"];
1936
2532
  /** @description Pickup leg (load on). */
1937
- pickup: components["schemas"]["Stop"];
2533
+ pickup: components["schemas"]["ShipmentStop"];
1938
2534
  /**
1939
2535
  * @description Soft vehicle affinity preferences, priced. Each entry is independent:
1940
2536
  * a job listing several preferred vehicles it doesn't get pays each
1941
2537
  * one's `violation_cost` (compounding, the same rule as a vehicle's
1942
2538
  * `preferred_tags`).
1943
2539
  */
1944
- preferences?: components["schemas"]["Preference"][] | null;
1945
- /**
1946
- * Format: date-time
1947
- * @description Soft preference for the calendar day this task is served on, in a
1948
- * multi-day (multi-shift) problem.
1949
- *
1950
- * An RFC 3339 datetime, UTC offset required, on the intended day. A day is the calendar date of
1951
- * the value **in its own UTC offset**, the same rule that dates a shift
1952
- * from its `from`, so passing the target shift's `from` verbatim is
1953
- * always correct.
1954
- *
1955
- * Soft, and priced by `objective.non_preferred_date_cost` — a flat charge
1956
- * applied once to a task served on any other day. **With that cost unset or
1957
- * zero this field has no effect.** The charge is part of `score.cost`,
1958
- * which ranks below serving required tasks, so a task is never left
1959
- * unassigned to honour its preferred date; `locked_vehicle` (hard) also
1960
- * still wins.
1961
- *
1962
- * Supported on shipments as well as jobs. Both legs of a shipment ride
1963
- * the same route, so the preferred day is a property of the pair: set it
1964
- * on the shipment itself, and `non_preferred_date_cost` is charged once
1965
- * for the pair rather than once per leg.
1966
- * @example 2026-08-04T08:00:00+02:00
1967
- */
1968
- preferred_date?: string | null;
2540
+ preferences?: components["schemas"]["VehiclePreference"][] | null;
1969
2541
  /**
1970
2542
  * Format: int32
1971
2543
  * @description Importance of a must-serve task when not all of them fit: the solver
1972
2544
  * maximises the summed `priority` of served tasks before any cost. `>= 1`,
1973
2545
  * default `1` (maximise the count). A rank, not money — it never makes a
1974
- * 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.
1975
2547
  * @example 3
1976
2548
  */
1977
2549
  priority?: number | null;
1978
2550
  /**
1979
- * @description Per-vehicle work-rate overrides for this task's `service_duration_s`,
1980
- * composed multiplicatively with the serving vehicle's or shift's
1981
- * `service_factor`. On a shipment the override scales both legs. A
1982
- * vehicle not listed works at its own rate.
2551
+ * @description Hard skill requirements — the assigned vehicle must provide every one,
2552
+ * at or above each requirement's `min_level`. A request may use at most
2553
+ * 256 distinct `(name, min_level)` pairs across all jobs and shipments
2554
+ * (HTTP 400 `limit_exceeded` beyond that).
1983
2555
  */
1984
- service_factors?: components["schemas"]["ServiceFactor"][] | null;
2556
+ required_skills?: components["schemas"]["SkillRequirement"][] | null;
1985
2557
  /**
1986
- * @description Hard skill requirements — the assigned vehicle must provide every one,
1987
- * at or above each requirement's `min_level`.
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.
1988
2564
  */
1989
- skills?: components["schemas"]["SkillReq"][] | null;
2565
+ service_factors?: components["schemas"]["ServiceFactor"][] | null;
1990
2566
  /**
1991
- * @description Free-form task labels (zones/territories, grouping/relation labels).
2567
+ * @description Free-form task labels (zones/territories, relation labels).
1992
2568
  * Used for `tag`/relation resolution and, when a shift scopes itself via
1993
2569
  * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
1994
2570
  * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
1995
- * `skills`, which requires ALL. Not capability matching on its own.
2571
+ * `required_skills`, which requires ALL. Not capability matching on its own.
2572
+ * A request may carry at most 256 distinct tags across all jobs and
2573
+ * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
2574
+ * lists do not count.
1996
2575
  */
1997
2576
  tags?: string[] | null;
1998
2577
  /**
@@ -2001,13 +2580,70 @@ export interface components {
2001
2580
  */
2002
2581
  target?: null | components["schemas"]["Target"];
2003
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
+ };
2004
2640
  /**
2005
2641
  * @description A hard skill requirement — the assigned vehicle must provide it.
2006
2642
  * @example {
2007
2643
  * "name": "fridge"
2008
2644
  * }
2009
2645
  */
2010
- SkillReq: {
2646
+ SkillRequirement: {
2011
2647
  /**
2012
2648
  * Format: int32
2013
2649
  * @description Minimum level the serving vehicle must hold for this skill (`>= 1`).
@@ -2024,7 +2660,7 @@ export interface components {
2024
2660
  /**
2025
2661
  * @description Solve options.
2026
2662
  * @example {
2027
- * "polylines": "full",
2663
+ * "polyline": "full",
2028
2664
  * "seed": 42,
2029
2665
  * "time_limit_s": 5
2030
2666
  * }
@@ -2032,25 +2668,28 @@ export interface components {
2032
2668
  SolveOptions: {
2033
2669
  /**
2034
2670
  * @description Return road geometry for each route as `routes[].polyline`:
2035
- * `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.
2036
2673
  */
2037
- polylines?: null | components["schemas"]["PolylineDetail"];
2674
+ polyline?: null | components["schemas"]["PolylineDetail"];
2038
2675
  /**
2039
2676
  * Format: int64
2040
2677
  * @description Random seed for the search. Default `42`: omitting it is the same as
2041
2678
  * sending `42`, so send different values to explore different plans.
2042
2679
  * Repeated runs on one machine usually return an identical plan; a
2043
2680
  * materially faster or slower machine can differ.
2681
+ * @default 42
2044
2682
  * @example 42
2045
2683
  */
2046
2684
  seed?: number | null;
2047
2685
  /**
2048
2686
  * Format: double
2049
- * @description Search time budget in seconds, fractions allowed (default 1). Maximum
2050
- * 300: a larger value is rejected with HTTP 400. A value below 0.1 is
2051
- * raised to a 100 ms floor. Pure search time: fetching travel times and
2052
- * waiting for capacity are not deducted from it, so the request takes
2053
- * longer than this value.
2687
+ * @description Search time budget in seconds, fractions allowed. Default when omitted:
2688
+ * 150 ms plus 4 ms per task (jobs and shipments combined), so 100 tasks
2689
+ * search for 0.55 s. Maximum 60: a larger value is rejected with HTTP 400.
2690
+ * A value below 0.1 is raised to a 100 ms floor. Pure search time:
2691
+ * fetching travel times and waiting for capacity are not deducted from it,
2692
+ * so the request takes longer than this value.
2054
2693
  * @example 2.5
2055
2694
  */
2056
2695
  time_limit_s?: number | null;
@@ -2059,6 +2698,7 @@ export interface components {
2059
2698
  * overload): `estimate` (the default) solves on estimated travel and
2060
2699
  * sets `summary.travel_estimated`; `fail` returns the 502/503
2061
2700
  * instead. A request Maps rejects as invalid always fails.
2701
+ * @default estimate
2062
2702
  */
2063
2703
  travel_fallback?: null | components["schemas"]["TravelFallback"];
2064
2704
  };
@@ -2086,15 +2726,15 @@ export interface components {
2086
2726
  * 3.725,
2087
2727
  * 51.05
2088
2728
  * ],
2089
- * "pickup": {
2729
+ * "pickup_load": {
2090
2730
  * "weight": 20
2091
2731
  * },
2092
- * "service_duration_s": 300,
2093
- * "skills": [
2732
+ * "required_skills": [
2094
2733
  * {
2095
2734
  * "name": "fridge"
2096
2735
  * }
2097
2736
  * ],
2737
+ * "service_duration_s": 300,
2098
2738
  * "time_windows": [
2099
2739
  * {
2100
2740
  * "from": "2026-07-01T09:00:00+02:00",
@@ -2108,7 +2748,7 @@ export interface components {
2108
2748
  * 3.71,
2109
2749
  * 51.06
2110
2750
  * ],
2111
- * "pickup": {
2751
+ * "pickup_load": {
2112
2752
  * "weight": 35
2113
2753
  * },
2114
2754
  * "service_duration_s": 600
@@ -2167,7 +2807,7 @@ export interface components {
2167
2807
  */
2168
2808
  plan?: null | components["schemas"]["Plan"];
2169
2809
  /** @description The problem: tasks, fleet, depots, relations, objective, travel. */
2170
- problem: components["schemas"]["ProblemInput"];
2810
+ problem: components["schemas"]["Problem"];
2171
2811
  };
2172
2812
  /**
2173
2813
  * @description The result of `POST /v3/routing/solve` and `POST /v3/routing/evaluate`:
@@ -2227,6 +2867,7 @@ export interface components {
2227
2867
  * 51.05
2228
2868
  * ],
2229
2869
  * "service_s": 300,
2870
+ * "service_start": "2026-07-01T09:00:00+02:00",
2230
2871
  * "travel_s": 600,
2231
2872
  * "type": "job",
2232
2873
  * "wait_s": 3000
@@ -2245,6 +2886,7 @@ export interface components {
2245
2886
  * 51.06
2246
2887
  * ],
2247
2888
  * "service_s": 600,
2889
+ * "service_start": "2026-07-01T09:13:00+02:00",
2248
2890
  * "travel_s": 480,
2249
2891
  * "type": "job",
2250
2892
  * "wait_s": 0
@@ -2263,7 +2905,8 @@ export interface components {
2263
2905
  * ],
2264
2906
  * "service_s": 0,
2265
2907
  * "travel_s": 900,
2266
- * "type": "end"
2908
+ * "type": "end",
2909
+ * "wait_s": 0
2267
2910
  * }
2268
2911
  * ],
2269
2912
  * "time": {
@@ -2282,30 +2925,36 @@ export interface components {
2282
2925
  * "distance_m": 8450,
2283
2926
  * "score": {
2284
2927
  * "components": {
2285
- * "depot_visits": 0,
2928
+ * "assignment": 0,
2286
2929
  * "distance": 1.69,
2287
- * "drop_fees": 0,
2288
- * "fixed": 0,
2930
+ * "drop_costs": 0,
2289
2931
  * "grouping": 0,
2290
2932
  * "lateness": 0,
2291
- * "other": 0,
2292
2933
  * "overtime": 0,
2934
+ * "preferences": 0,
2935
+ * "reloads": 0,
2936
+ * "routes": 0,
2293
2937
  * "tag_preference": 0,
2294
2938
  * "target": 0,
2295
2939
  * "time": 57.1536,
2296
2940
  * "waiting": 0,
2297
- * "window_choice": 0
2941
+ * "window_choice": 0,
2942
+ * "workload_share": 0
2298
2943
  * },
2299
2944
  * "cost": 58.8436,
2300
2945
  * "currency": "EUR",
2301
- * "unserved_priority": 0,
2302
- * "violations": 0
2946
+ * "unassigned_priority": 0,
2947
+ * "violation_count": 0
2948
+ * },
2949
+ * "search": {
2950
+ * "iterations": 48210,
2951
+ * "termination": "time_limit"
2303
2952
  * },
2304
2953
  * "shifts_used": 1,
2305
2954
  * "tasks": {
2306
2955
  * "served": 2,
2307
- * "unserved": 0,
2308
- * "unserved_required": 0
2956
+ * "unassigned": 0,
2957
+ * "unassigned_required": 0
2309
2958
  * },
2310
2959
  * "time": {
2311
2960
  * "break_s": 0,
@@ -2322,7 +2971,8 @@ export interface components {
2322
2971
  * },
2323
2972
  * "vehicles_used": 1
2324
2973
  * },
2325
- * "unassigned": []
2974
+ * "unassigned": [],
2975
+ * "warnings": []
2326
2976
  * }
2327
2977
  */
2328
2978
  SolveResponse: {
@@ -2336,273 +2986,88 @@ export interface components {
2336
2986
  /** @description Aggregate statistics for the solve run. */
2337
2987
  summary: components["schemas"]["Summary"];
2338
2988
  /** @description Tasks that could not be feasibly assigned. */
2339
- 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"][];
2340
2997
  };
2341
2998
  /**
2342
- * @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.
2343
3011
  * @example {
2344
- * "id": "ship-1:pickup",
2345
- * "location": [
2346
- * 3.725,
2347
- * 51.05
2348
- * ],
2349
- * "service_duration_s": 300,
2350
- * "setup_duration_s": 60,
2351
- * "time_windows": [
2352
- * {
2353
- * "from": "2026-07-01T09:00:00+02:00",
2354
- * "to": "2026-07-01T12:00:00+02:00"
2355
- * }
2356
- * ]
3012
+ * "max_insertions": 5,
3013
+ * "time_limit_s": 2
2357
3014
  * }
2358
3015
  */
2359
- Stop: {
2360
- /**
2361
- * @description Whether a break may interrupt service here. Default `true`. `false`
2362
- * is not supported yet and is rejected with HTTP 400.
2363
- * @example true
2364
- */
2365
- break_interruptible?: boolean | null;
2366
- /**
2367
- * @description Stop id: 1 to 128 characters when set. Defaults to
2368
- * `"{shipment}:pickup"` / `"{shipment}:delivery"`. The effective id
2369
- * (custom or default) must be unique across all job, shipment, and stop
2370
- * ids — a collision is rejected with HTTP 400.
2371
- * @example ship-1:pickup
2372
- */
2373
- id?: string | null;
2374
- /** @description Where this stop happens. */
2375
- location: components["schemas"]["Place"];
3016
+ SuggestOptions: {
2376
3017
  /**
2377
3018
  * Format: int32
2378
- * @description On-site service time paid per job (seconds).
2379
- *
2380
- * This is the nominal figure. The serving vehicle's `service_factor`
2381
- * scales it — the time actually scheduled is
2382
- * `service_duration_s / service_factor` — so the solution's
2383
- * `stops[].service_s` may differ from what you sent here.
2384
- * @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
2385
3029
  */
2386
- service_duration_s?: number | null;
3030
+ max_insertions?: number | null;
2387
3031
  /**
2388
- * Format: int32
2389
- * @description Setup time paid once on arrival at a new location (seconds),
2390
- * distinct from `service_duration_s`. Skipped when the immediate real
2391
- * predecessor in the route already sits at this location — co-located
2392
- * stops share one setup.
2393
- *
2394
- * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
2395
- * overhead (parking, walking to the door), not the work itself.
2396
- * @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
2397
3041
  */
2398
- setup_duration_s?: number | null;
2399
- /** @description Time windows for this stop. */
2400
- time_windows?: components["schemas"]["TimeWindow"][] | null;
3042
+ time_limit_s?: number | null;
2401
3043
  };
2402
3044
  /**
2403
- * @description Which instant of a stop a `target` or a relation refers to. One vocabulary
2404
- * for both, each accepting the values that mean something there.
2405
- * @enum {string}
2406
- */
2407
- StopInstant: "arrival" | "start" | "end";
2408
- /**
2409
- * @description A single stop within a route.
3045
+ * @description Why a unit came back with no insertions.
2410
3046
  * @example {
2411
- * "arrival": "2026-07-01T08:10:00+02:00",
2412
- * "departure": "2026-07-01T09:05:00+02:00",
2413
- * "distance_m": 2600,
2414
- * "id": "job-1",
2415
- * "lateness_s": 0,
2416
- * "load_after": {
2417
- * "weight": 20
2418
- * },
2419
- * "location": [
2420
- * 3.725,
2421
- * 51.05
2422
- * ],
2423
- * "service_s": 300,
2424
- * "travel_s": 600,
2425
- * "type": "job",
2426
- * "wait_s": 3000
3047
+ * "code": "infeasible",
3048
+ * "message": "No feasible insertion position found"
2427
3049
  * }
2428
3050
  */
2429
- StopOutput: {
2430
- /**
2431
- * Format: date-time
2432
- * @description Physical arrival time (RFC 3339), before any waiting; the service
2433
- * start is `arrival + wait_s`. Every stop time is rendered in the UTC
2434
- * offset of the route's shift `from` (`Z` when that `from` is UTC or has
2435
- * no offset): a `+02:00` shift reports `2026-07-01T08:10:00+02:00`, the
2436
- * same instant as `2026-07-01T06:10:00Z`.
2437
- * @example 2026-07-01T08:10:00+02:00
2438
- */
2439
- arrival?: string | null;
2440
- /**
2441
- * Format: date-time
2442
- * @description Departure time (RFC 3339, in the offset of `arrival`).
2443
- * @example 2026-07-01T09:05:00+02:00
2444
- */
2445
- departure?: string | null;
2446
- /**
2447
- * @description The `depots[].id` of this stop: on a `start`/`end` stop whose shift end
2448
- * names a depot, and on every `reload` stop. Absent on a `location` or
2449
- * open end and on task and break stops.
2450
- * @example gent
2451
- */
2452
- depot?: string | null;
2453
- /**
2454
- * Format: int32
2455
- * @description Travel distance from the previous stop, in metres.
2456
- * @example 2600
2457
- */
2458
- distance_m?: number | null;
2459
- /**
2460
- * Format: int32
2461
- * @description The part of `wait_s` spent holding for a `synchronized` or
2462
- * `time_lag` partner on another vehicle, beyond any wait the time
2463
- * window already imposed. Present on task stops only when non-zero.
2464
- * @example 0
2465
- */
2466
- hold_s?: number | null;
2467
- /**
2468
- * @description Stop id: the job id on a `job` stop, the leg's stop id on
2469
- * `pickup`/`delivery` (its own `id`, else `{shipment}:pickup` /
2470
- * `{shipment}:delivery`). Absent on start, end, break and reload stops.
2471
- * @example job-1
2472
- */
2473
- id?: string | null;
2474
- /**
2475
- * Format: int32
2476
- * @description Seconds late beyond the latest allowed arrival (`0` when on time).
2477
- * Measures the hard time window only; a soft target is reported in
2478
- * `target_lateness_s`.
2479
- * @example 0
2480
- */
2481
- lateness_s?: number | null;
2482
- /** @description Cumulative load carried after this stop, by named dimension. */
2483
- load_after?: null | components["schemas"]["BTreeMap"];
2484
- /**
2485
- * @description Stop location `[longitude, latitude]` (GeoJSON order). Absent on
2486
- * every `break` stop, including a break with a pinned location, and on
2487
- * `start`/`end` stops for a genuinely open leg (no configured depot
2488
- * coordinate for that end of the shift). A virtual (location-less) job
2489
- * has no coordinate of its own and reports its nearest located
2490
- * neighbor's instead, so it is absent only when the whole route is
2491
- * virtual with open depot ends.
2492
- * @example [
2493
- * 3.725,
2494
- * 51.05
2495
- * ]
2496
- */
2497
- location?: number[] | null;
3051
+ SuggestReason: {
3052
+ /** @description Branch on this. Open set; see [`SuggestReasonCode`]. */
3053
+ code: components["schemas"]["SuggestReasonCode"];
2498
3054
  /**
2499
- * Format: int32
2500
- * @description On-site service time at this stop, in seconds.
2501
- *
2502
- * The **effective** time, not the nominal `service_duration_s` from the
2503
- * request: on a task stop it already has the serving vehicle's
2504
- * `service_factor` applied. The timeline reconciles as
2505
- * `departure - arrival - wait_s == service_s` only when the stop pays no
2506
- * setup time; with `setup_duration_s` set, the difference is larger by
2507
- * the (unscaled) setup seconds. Depot, reload, and break stops report
2508
- * their own nominal handling/break duration, which `service_factor`
2509
- * never scales.
2510
- *
2511
- * On `start`/`end`: the depot handling time applied there (0 on an
2512
- * ignored leg); absent on an open end.
2513
- * @example 300
3055
+ * @description `code` as an English sentence, for people and logs. Do not parse it.
3056
+ * @example No feasible insertion position found
2514
3057
  */
2515
- service_s?: number | null;
2516
- /**
2517
- * Format: date-time
2518
- * @description When service starts (RFC 3339, in the offset of `arrival`): after the
2519
- * arrival, any windowed
2520
- * break taken on arrival there, and the wait. On task and reload stops;
2521
- * like `arrival`, absent on a request without time windows.
2522
- * @example 2026-07-01T09:00:00+02:00
2523
- */
2524
- service_start?: string | null;
2525
- /** @description The same point snapped to the routable graph, when available. */
2526
- snapped_location?: number[] | null;
2527
- /**
2528
- * Format: int32
2529
- * @description Seconds past this task's `target.at`, measured at the stop's arrival
2530
- * or departure per `target.on`; `0` when met. Present only on a task
2531
- * stop carrying a target. A shipment's target is measured
2532
- * on its delivery leg, so it appears on the `:delivery` stop and never on
2533
- * the `:pickup` stop.
2534
- * @example 0
2535
- */
2536
- target_lateness_s?: number | null;
2537
- /**
2538
- * Format: int32
2539
- * @description Travel time from the previous stop, in seconds.
2540
- * @example 600
2541
- */
2542
- travel_s?: number | null;
2543
- /** @description What kind of stop this is. */
2544
- type: components["schemas"]["StopType"];
2545
- /**
2546
- * @description Constraint violations detected at this stop. Only populated by
2547
- * `POST /v3/routing/evaluate` (imported solutions may be infeasible); a
2548
- * solve response never emits violations, so this is absent there.
2549
- */
2550
- violations?: components["schemas"]["Violation"][];
2551
- /**
2552
- * Format: int32
2553
- * @description Seconds spent waiting here before service: for the time window to
2554
- * open, and for any cross-route hold (`hold_s`, included in this
2555
- * figure).
2556
- * @example 3000
2557
- */
2558
- wait_s?: number | null;
2559
- };
2560
- /**
2561
- * @description The kind of a stop in a route.
2562
- *
2563
- * Every route has one `start` and one `end`. A served job is `job`, and a
2564
- * shipment's legs are `pickup` and `delivery`. A driver break is `break`,
2565
- * and a mid-shift reload at a depot is `reload`.
2566
- * @example job
2567
- * @enum {string}
2568
- */
2569
- StopType: "start" | "job" | "pickup" | "delivery" | "break" | "reload" | "end";
2570
- /**
2571
- * @description Suggest options.
2572
- * @example {
2573
- * "max_suggestions": 5,
2574
- * "time_limit_s": 2
2575
- * }
2576
- */
2577
- SuggestOptions: {
2578
- /**
2579
- * @description Max ranked options per task. Default 5; `0` returns every feasible
2580
- * placement; positive values are clamped to `1..=100`.
2581
- * @example 5
2582
- */
2583
- max_suggestions?: number | null;
2584
- /**
2585
- * Format: double
2586
- * @description Search budget in seconds, fractions allowed (default 1, as on `/solve`;
2587
- * minimum 0.1 — smaller values are raised to it; maximum 300). The clock
2588
- * starts when the search starts, after the matrix fetch and any wait for a
2589
- * solver slot. Units are searched in problem order (jobs, then
2590
- * shipments), each with an equal share of the time left when it starts; a
2591
- * unit that finishes early leaves its slack to the ones after it.
2592
- * @example 2.5
2593
- */
2594
- time_limit_s?: number | null;
3058
+ message: string;
2595
3059
  };
2596
3060
  /**
2597
3061
  * @description Why a unit's `insertions` is empty: the machine-readable form of
2598
3062
  * `reason`, to branch on.
2599
3063
  *
2600
3064
  * Open set: values may be added within `/v3`. Accept values not listed here
2601
- * 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.
2602
3068
  * @example infeasible
2603
- * @enum {string}
2604
3069
  */
2605
- SuggestReasonCode: "time_limit" | "candidates_exhausted" | "infeasible";
3070
+ SuggestReasonCode: string;
2606
3071
  /**
2607
3072
  * @description Request body for `POST /v3/routing/suggest`.
2608
3073
  *
@@ -2615,7 +3080,7 @@ export interface components {
2615
3080
  * committed plan; the plan is never modified.
2616
3081
  * @example {
2617
3082
  * "options": {
2618
- * "max_suggestions": 5
3083
+ * "max_insertions": 5
2619
3084
  * },
2620
3085
  * "plan": {
2621
3086
  * "routes": [
@@ -2639,7 +3104,7 @@ export interface components {
2639
3104
  * 3.725,
2640
3105
  * 51.05
2641
3106
  * ],
2642
- * "pickup": {
3107
+ * "pickup_load": {
2643
3108
  * "weight": 10
2644
3109
  * },
2645
3110
  * "service_duration_s": 300
@@ -2650,7 +3115,7 @@ export interface components {
2650
3115
  * 3.71,
2651
3116
  * 51.06
2652
3117
  * ],
2653
- * "pickup": {
3118
+ * "pickup_load": {
2654
3119
  * "weight": 10
2655
3120
  * },
2656
3121
  * "service_duration_s": 300
@@ -2698,12 +3163,11 @@ export interface components {
2698
3163
  * @description Problem definition — identical to `POST /v3/routing/solve`. Every task
2699
3164
  * of it that is not in `plan` is a task to place.
2700
3165
  */
2701
- problem: components["schemas"]["ProblemInput"];
3166
+ problem: components["schemas"]["Problem"];
2702
3167
  };
2703
3168
  /**
2704
3169
  * @description Response body for `POST /v3/routing/suggest`.
2705
3170
  * @example {
2706
- * "elapsed_ms": 8,
2707
3171
  * "suggestions": [
2708
3172
  * {
2709
3173
  * "insertions": [
@@ -2711,7 +3175,7 @@ export interface components {
2711
3175
  * "delta": {
2712
3176
  * "cost": 12.4,
2713
3177
  * "distance_m": 2400,
2714
- * "duration_s": 240
3178
+ * "travel_s": 240
2715
3179
  * },
2716
3180
  * "placements": [
2717
3181
  * {
@@ -2741,34 +3205,43 @@ export interface components {
2741
3205
  * ]
2742
3206
  * }
2743
3207
  * ],
2744
- * "job_id": "job-2"
3208
+ * "task": "job-2"
2745
3209
  * }
2746
3210
  * ],
2747
- * "truncated": false
3211
+ * "timings": {
3212
+ * "total_ms": 8
3213
+ * },
3214
+ * "truncated": false,
3215
+ * "warnings": []
2748
3216
  * }
2749
3217
  */
2750
3218
  SuggestResponse: {
2751
- /**
2752
- * Format: int64
2753
- * @description Wall-clock time taken by the request, in milliseconds.
2754
- * @example 8
2755
- */
2756
- elapsed_ms: number;
2757
3219
  /**
2758
3220
  * @description One entry per unit of tasks outside `plan`, in problem order (jobs,
2759
3221
  * then shipments; a relation group sorts at its first-listed member).
2760
3222
  */
2761
- 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"];
2762
3229
  /**
2763
3230
  * @description `true` when `options.time_limit_s` cut the search short, or a
2764
3231
  * multi-member unit came back empty after the search had discarded
2765
- * candidates (an inconclusive "not found"; its `reason_code` is
3232
+ * candidates (an inconclusive "not found"; its `reason.code` is
2766
3233
  * `candidates_exhausted`). Lists may then be incomplete or missing the
2767
3234
  * best insertion. A single visit's only level is never pruned, so its
2768
3235
  * empty list is proof of infeasibility unless the budget cut it, and its
2769
- * `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.
2770
3243
  */
2771
- truncated?: boolean;
3244
+ warnings: components["schemas"]["RequestIssue"][];
2772
3245
  };
2773
3246
  /**
2774
3247
  * @description The plan in numbers: its score, what it serves and what it takes.
@@ -2776,30 +3249,36 @@ export interface components {
2776
3249
  * "distance_m": 8450,
2777
3250
  * "score": {
2778
3251
  * "components": {
2779
- * "depot_visits": 0,
3252
+ * "assignment": 0,
2780
3253
  * "distance": 1.69,
2781
- * "drop_fees": 0,
2782
- * "fixed": 0,
3254
+ * "drop_costs": 0,
2783
3255
  * "grouping": 0,
2784
3256
  * "lateness": 0,
2785
- * "other": 0,
2786
3257
  * "overtime": 0,
3258
+ * "preferences": 0,
3259
+ * "reloads": 0,
3260
+ * "routes": 0,
2787
3261
  * "tag_preference": 0,
2788
3262
  * "target": 0,
2789
3263
  * "time": 57.1536,
2790
3264
  * "waiting": 0,
2791
- * "window_choice": 0
3265
+ * "window_choice": 0,
3266
+ * "workload_share": 0
2792
3267
  * },
2793
3268
  * "cost": 58.8436,
2794
3269
  * "currency": "EUR",
2795
- * "unserved_priority": 0,
2796
- * "violations": 0
3270
+ * "unassigned_priority": 0,
3271
+ * "violation_count": 0
3272
+ * },
3273
+ * "search": {
3274
+ * "iterations": 48210,
3275
+ * "termination": "time_limit"
2797
3276
  * },
2798
3277
  * "shifts_used": 1,
2799
3278
  * "tasks": {
2800
3279
  * "served": 2,
2801
- * "unserved": 0,
2802
- * "unserved_required": 0
3280
+ * "unassigned": 0,
3281
+ * "unassigned_required": 0
2803
3282
  * },
2804
3283
  * "time": {
2805
3284
  * "break_s": 0,
@@ -2825,10 +3304,12 @@ export interface components {
2825
3304
  */
2826
3305
  distance_m: number;
2827
3306
  /**
2828
- * @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
2829
3308
  * `/evaluate` it counts the constraints the given plan breaks.
2830
3309
  */
2831
3310
  score: components["schemas"]["Score"];
3311
+ /** @description How the search ended. */
3312
+ search: components["schemas"]["SearchInfo"];
2832
3313
  /**
2833
3314
  * Format: int32
2834
3315
  * @description Routes with at least one task stop: one per used shift.
@@ -2846,10 +3327,11 @@ export interface components {
2846
3327
  * on estimated travel: straight-line distance × a detour factor, at a
2847
3328
  * typical speed for the profile. No one-way streets or traffic, so it
2848
3329
  * can be tens of percent off: the plan, `unassigned[].reasons` and
2849
- * `score.violations` hold only against it, and no `routes[].polyline` is
3330
+ * `score.violation_count` hold only against it, and no `routes[].polyline` is
2850
3331
  * returned. Solve again once Maps is back if the plan must hold on the
2851
3332
  * road; `options.travel_fallback: "fail"` returns the error instead.
2852
- * Absent when travel is road-routed.
3333
+ * Absent when travel is road-routed, and always absent on `/evaluate`,
3334
+ * which returns the error rather than estimate.
2853
3335
  */
2854
3336
  travel_estimated?: boolean;
2855
3337
  /**
@@ -2875,7 +3357,7 @@ export interface components {
2875
3357
  /**
2876
3358
  * Format: double
2877
3359
  * @description Cost, in the objective's currency, incurred when a task without this
2878
- * tag is served.
3360
+ * tag is served. Must be finite and `>= 0`.
2879
3361
  * @example 25
2880
3362
  */
2881
3363
  violation_cost: number;
@@ -2900,9 +3382,10 @@ export interface components {
2900
3382
  at: string;
2901
3383
  /**
2902
3384
  * @description Which instant of the task is compared to `at`: `arrival` (default) or
2903
- * `end`. `start` is rejected with HTTP 400.
3385
+ * `departure`, the stop fields of the same names.
3386
+ * @default arrival
2904
3387
  */
2905
- on?: null | components["schemas"]["StopInstant"];
3388
+ on?: null | components["schemas"]["TargetInstant"];
2906
3389
  /**
2907
3390
  * Format: double
2908
3391
  * @description Cost, in the objective's currency, per hour of `on` beyond `at`
@@ -2913,13 +3396,19 @@ export interface components {
2913
3396
  */
2914
3397
  per_late_hour: number;
2915
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";
2916
3405
  /**
2917
3406
  * @description How many tasks the plan serves. A job is one task; a shipment (pickup
2918
3407
  * plus delivery) is one task.
2919
3408
  * @example {
2920
3409
  * "served": 2,
2921
- * "unserved": 0,
2922
- * "unserved_required": 0
3410
+ * "unassigned": 0,
3411
+ * "unassigned_required": 0
2923
3412
  * }
2924
3413
  */
2925
3414
  TaskCounts: {
@@ -2932,29 +3421,90 @@ export interface components {
2932
3421
  * Format: int32
2933
3422
  * @description Tasks on no route: the length of `unassigned`.
2934
3423
  */
2935
- unserved: number;
3424
+ unassigned: number;
2936
3425
  /**
2937
3426
  * Format: int32
2938
- * @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
2939
3428
  * required to serve and did not.
2940
3429
  */
2941
- 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;
2942
3490
  };
2943
3491
  /**
2944
3492
  * @description One end of a `time_lag` relation.
2945
3493
  * @example {
2946
- * "on": "end",
3494
+ * "on": "departure",
2947
3495
  * "stop": "job-1"
2948
3496
  * }
2949
3497
  */
2950
- TimeLagEnd: {
3498
+ TimeLagMember: {
2951
3499
  /**
2952
- * @description Which instant of the job the bound is measured at: `start` (default) or
2953
- * `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
2954
3503
  */
2955
- on?: null | components["schemas"]["StopInstant"];
3504
+ on?: null | components["schemas"]["RelationInstant"];
2956
3505
  /**
2957
- * @description A job id (shipment legs are not supported yet).
3506
+ * @description The stop: a job id. A shipment's own id or a shipment-leg stop id is
3507
+ * rejected with HTTP 400.
2958
3508
  * @example job-1
2959
3509
  */
2960
3510
  stop: string;
@@ -2965,13 +3515,11 @@ export interface components {
2965
3515
  *
2966
3516
  * `span_s` is the wall-clock span, from the start stop's `arrival` to the
2967
3517
  * end stop's `departure`; it is what `per_route_hour` is charged on. The
2968
- * other fields break it down. They do not sum to `span_s` exactly: two
2969
- * parts of the span have no field of their own, setup time
2970
- * (`setup_duration_s`) and the idle before a windowed break's window opens
2971
- * (`wait_s` is measured after that break). And a `fixed` break that begins
2972
- * while the vehicle is driving overlaps that drive: the overlap is in both
2973
- * `travel_s` and `break_s`, so on such a route the parts can exceed
2974
- * `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`.
2975
3523
  * @example {
2976
3524
  * "break_s": 0,
2977
3525
  * "depot_s": 0,
@@ -3017,7 +3565,11 @@ export interface components {
3017
3565
  travel_s: number;
3018
3566
  /**
3019
3567
  * Format: int64
3020
- * @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.
3021
3573
  */
3022
3574
  wait_s: number;
3023
3575
  };
@@ -3025,7 +3577,7 @@ export interface components {
3025
3577
  * @description A time window. Hard unless it (or `objective.per_late_hour`, for
3026
3578
  * every window) prices lateness.
3027
3579
  * @example {
3028
- * "cost": 15,
3580
+ * "choice_cost": 15,
3029
3581
  * "from": "2026-07-01T09:00:00+02:00",
3030
3582
  * "to": "2026-07-01T12:00:00+02:00"
3031
3583
  * }
@@ -3041,19 +3593,21 @@ export interface components {
3041
3593
  * alternatives; it does not soften time-window feasibility. Must be
3042
3594
  * finite and `>= 0`, and requires at least 2 windows on the task. Once
3043
3595
  * any window on the task carries a *nonzero* cost, that task's windows
3044
- * must also be pairwise non-overlapping (a task whose costs are all
3596
+ * must also be pairwise non-overlapping, and windows that only touch
3597
+ * count as overlapping (a task whose costs are all
3045
3598
  * `0`/absent has its overlapping windows merged).
3046
3599
  *
3047
3600
  * **Cannot be combined with `objective.per_late_hour > 0`** — a
3048
- * nonzero window `cost` anywhere in the request alongside priced lateness
3601
+ * nonzero `choice_cost` anywhere in the request alongside priced lateness
3049
3602
  * is rejected with HTTP 400 (the two read opposite ways about which
3050
3603
  * window was paid for). Choose one: priced alternative windows, or priced
3051
3604
  * lateness.
3052
3605
  */
3053
- cost?: number | null;
3606
+ choice_cost?: number | null;
3054
3607
  /**
3055
3608
  * Format: date-time
3056
- * @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.
3057
3611
  * @example 2026-07-01T09:00:00+02:00
3058
3612
  */
3059
3613
  from: string;
@@ -3070,7 +3624,9 @@ export interface components {
3070
3624
  per_late_hour?: number | null;
3071
3625
  /**
3072
3626
  * Format: date-time
3073
- * @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.
3074
3630
  * @example 2026-07-01T12:00:00+02:00
3075
3631
  */
3076
3632
  to: string;
@@ -3085,14 +3641,16 @@ export interface components {
3085
3641
  Timings: {
3086
3642
  /**
3087
3643
  * Format: int64
3088
- * @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.
3089
3646
  */
3090
3647
  search_ms?: number | null;
3091
3648
  /**
3092
3649
  * Format: int64
3093
3650
  * @description From the request's arrival to the end of the search (of the scoring,
3094
- * on `/evaluate`): fetching travel times and waiting for capacity
3095
- * 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.
3096
3654
  */
3097
3655
  total_ms: number;
3098
3656
  };
@@ -3125,103 +3683,107 @@ export interface components {
3125
3683
  engine?: null | components["schemas"]["MatrixEngine"];
3126
3684
  };
3127
3685
  /**
3128
- * @description [`SolveOptions::travel_fallback`]: what a solve does when travel times
3129
- * cannot be fetched.
3686
+ * @description `options.travel_fallback`: what a solve does when travel times cannot be
3687
+ * fetched. `/evaluate` and `/suggest` never estimate: they fail instead.
3130
3688
  * @example estimate
3131
3689
  * @enum {string}
3132
3690
  */
3133
3691
  TravelFallback: "estimate" | "fail";
3134
3692
  /**
3135
- * @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).
3136
3696
  * @example drive
3137
3697
  * @enum {string}
3138
3698
  */
3139
3699
  TriggerAfter: "drive" | "duty";
3140
3700
  /**
3141
- * @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.
3142
3732
  * @example {
3143
3733
  * "category": "blocked",
3144
- * "job_id": "job-2",
3145
3734
  * "reasons": [
3146
3735
  * {
3147
- * "code": "TIME_WINDOW_VIOLATED",
3148
- * "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"
3149
3738
  * }
3150
3739
  * ],
3151
3740
  * "relaxations": [
3152
3741
  * {
3153
3742
  * "amount": 900,
3154
- * "field": "/jobs/job-2/time_windows",
3743
+ * "message": "Extend a time window by 900s (~15 min).",
3155
3744
  * "op": "extend_time_window",
3156
- * "suggestion": "Extend a time window by 900s (~15 min).",
3745
+ * "pointer": "/problem/jobs/1/time_windows",
3157
3746
  * "unit": "s"
3158
3747
  * }
3159
- * ]
3748
+ * ],
3749
+ * "task": "job-2"
3160
3750
  * }
3161
3751
  */
3162
- Unassigned: {
3752
+ UnassignedTask: {
3163
3753
  /** @description Which kind of "unassigned" this is. */
3164
- category?: components["schemas"]["UnassignedCategory"];
3754
+ category: components["schemas"]["UnassignedCategory"];
3165
3755
  /**
3166
- * @description The unassigned job id.
3167
- * @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`.
3168
3761
  */
3169
- job_id: string;
3170
- /** @description Structured reasons the job could not be served. */
3171
3762
  reasons: components["schemas"]["UnassignedReason"][];
3172
3763
  /**
3173
3764
  * @description Best-effort, actionable relaxation suggestions. Empty when no simple
3174
3765
  * relaxation exists (e.g. a skills mismatch).
3175
3766
  */
3176
3767
  relaxations: components["schemas"]["Relaxation"][];
3177
- };
3178
- /**
3179
- * @description Which kind of "unassigned" a task is.
3180
- * @example priced_out
3181
- * @enum {string}
3182
- */
3183
- UnassignedCategory: "impossible" | "blocked" | "priced_out" | "search_limit";
3184
- /**
3185
- * @description A machine-readable reason a task could not be assigned.
3186
- * @example {
3187
- * "code": "TIME_WINDOW_VIOLATED",
3188
- * "message": "No vehicle can reach this job within its time window."
3189
- * }
3190
- */
3191
- UnassignedReason: {
3192
- /**
3193
- * @description Stable machine code. Closed set of eleven values — exactly one of:
3194
- * `SOLVER_LIMIT` (a feasible slot existed but the time budget ran out),
3195
- * `CAPACITY_EXCEEDED`, `TIME_WINDOW_VIOLATED`, `CAPACITY_AND_TIME_WINDOW`,
3196
- * `SKILLS_MISMATCH`, `TAG_RESTRICTED`, `COMMITMENT_BLOCKED`,
3197
- * `VEHICLE_EXCLUDED`, `VEHICLE_RANGE_EXCEEDED`, `UNREACHABLE_LOCATION`,
3198
- * or `ALL_ROUTES_BLOCKED` (a mix no single code describes).
3199
- * `UNREACHABLE_LOCATION` outranks the others when it applies:
3200
- * a coordinate the routing engine cannot reach is a fact about the input,
3201
- * not about the fleet. Treat an unrecognised value as
3202
- * `ALL_ROUTES_BLOCKED`.
3203
- * @example TIME_WINDOW_VIOLATED
3204
- */
3205
- code: string;
3206
3768
  /**
3207
- * @description Human-readable explanation.
3208
- * @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
3209
3771
  */
3210
- message: string;
3772
+ task: string;
3211
3773
  };
3212
3774
  /**
3213
- * @description The 200 body of a `?validate_only=true` call: the request passed every
3214
- * 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.
3215
3777
  * @example {
3216
3778
  * "valid": true,
3217
3779
  * "warnings": []
3218
3780
  * }
3219
3781
  */
3220
- ValidateOnlyResponse: {
3782
+ ValidateResponse: {
3221
3783
  /** @description Always `true`: an invalid request gets a 400 instead. */
3222
3784
  valid: boolean;
3223
- /** @description Warnings a real call would return, in the error item shape. */
3224
- warnings: components["schemas"]["ErrorItem"][];
3785
+ /** @description May contain warnings about the request; none are produced today. */
3786
+ warnings: components["schemas"]["RequestIssue"][];
3225
3787
  };
3226
3788
  /**
3227
3789
  * @description A vehicle type available to serve tasks.
@@ -3260,7 +3822,7 @@ export interface components {
3260
3822
  */
3261
3823
  Vehicle: {
3262
3824
  /** @description Named capacity dimensions. */
3263
- capacity?: null | components["schemas"]["BTreeMap"];
3825
+ capacity?: null | components["schemas"]["Quantities"];
3264
3826
  /**
3265
3827
  * @description Vehicles this one may serve a `compatible_vehicles` relation's tasks
3266
3828
  * together with, by id. Absent: any vehicle. A list is a veto, so a
@@ -3319,14 +3881,24 @@ export interface components {
3319
3881
  * depot handling (`depots[].service_duration_s`,
3320
3882
  * `start`/`end.service_duration_s`), waiting time, or break durations.
3321
3883
  *
3322
- * Must be in `(0, 5]`. Default 1.0. A shift may override it for its own
3323
- * 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
3324
3893
  */
3325
3894
  service_factor?: number | null;
3326
- /** @description One or more working shifts. */
3895
+ /**
3896
+ * @description One or more working shifts. A vehicle without shifts is rejected with
3897
+ * HTTP 400.
3898
+ */
3327
3899
  shifts: components["schemas"]["Shift"][];
3328
3900
  /**
3329
- * @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
3330
3902
  * here at a level of at least the job's `min_level`. Each entry is an
3331
3903
  * object `{ "name": ..., "level": N }` (`level` optional, default 1);
3332
3904
  * a bare string is rejected. A skill may appear once per list. Omitting
@@ -3338,13 +3910,45 @@ export interface components {
3338
3910
  * Format: double
3339
3911
  * @description Travel-speed multiplier (1.0 = base speed). Effective travel time =
3340
3912
  * `base travel time / speed_factor`, so values > 1.0 model a faster
3341
- * 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.
3342
3914
  *
3343
3915
  * Covers driving only. Its companion `service_factor` scales the
3344
3916
  * work done at stops; the two are independent and share this direction and
3345
3917
  * range.
3918
+ * @default 1
3346
3919
  */
3347
3920
  speed_factor?: number | null;
3921
+ /**
3922
+ * Format: double
3923
+ * @description Share of the work this vehicle carries under `objective.workload_share`,
3924
+ * relative to the other vehicles. Default `1`; `0.5` carries half as much;
3925
+ * `0` leaves the vehicle out of the balancing. `0` to `1000000`
3926
+ * (HTTP 400 `out_of_range` outside that). Ignored when
3927
+ * `objective.workload_share` is not set.
3928
+ * @example 0.5
3929
+ */
3930
+ workload_weight?: number | null;
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;
3348
3952
  };
3349
3953
  /**
3350
3954
  * @description Vehicle distance/time limits.
@@ -3356,38 +3960,43 @@ export interface components {
3356
3960
  VehicleLimits: {
3357
3961
  /**
3358
3962
  * Format: int64
3359
- * @description Hard maximum distance in metres.
3963
+ * @description Hard maximum distance in metres. `0` to `2147483647`; a value
3964
+ * outside that range is rejected with HTTP 400 `out_of_range`.
3360
3965
  * @example 200000
3361
3966
  */
3362
3967
  max_distance_m?: number | null;
3363
3968
  /**
3364
3969
  * Format: int64
3365
3970
  * @description Hard cap in seconds on any single travel leg of this vehicle's routes:
3366
- * the `travel_time_s` reported on each stop, start-to-first-task and
3971
+ * the `travel_s` reported on each stop, start-to-first-task and
3367
3972
  * last-task-to-`end` included. Travel only: setup, service and wait do
3368
3973
  * not count, and `speed_factor` applies first. A leg made free by
3369
- * `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
3370
3975
  * end, is exempt. Absent = no cap. Must be > 0: `0` would make every
3371
3976
  * leg too long rather than mean "no cap", so it is rejected with HTTP
3372
- * 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`.
3373
3979
  * @example 3600
3374
3980
  */
3375
- max_leg_travel_time_s?: number | null;
3981
+ max_leg_travel_s?: number | null;
3376
3982
  /**
3377
3983
  * Format: int64
3378
3984
  * @description Hard maximum route duration in seconds: the whole-route span —
3379
3985
  * travel, service, and wait all count, depot load and unload included.
3380
- * The same quantity as the response's `routes[].time.span_s`.
3986
+ * The same quantity as the response's `routes[].time.span_s`. `0` to
3987
+ * `2147483647`; a value outside that range is rejected with HTTP 400
3988
+ * `out_of_range`.
3381
3989
  * @example 32400
3382
3990
  */
3383
3991
  max_route_duration_s?: number | null;
3384
3992
  /**
3385
3993
  * Format: int32
3386
- * @description Maximum stops served per shift: a job counts as one stop, a shipment
3387
- * 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.
3388
3997
  * @example 50
3389
3998
  */
3390
- max_tasks?: number | null;
3999
+ max_stops?: number | null;
3391
4000
  /**
3392
4001
  * @description Hard caps on this vehicle's totals across all of its shifts in a day,
3393
4002
  * a week or an explicit window. Each shift counts toward the one
@@ -3397,6 +4006,28 @@ export interface components {
3397
4006
  */
3398
4007
  periods?: components["schemas"]["PeriodLimit"][];
3399
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
+ };
3400
4031
  /**
3401
4032
  * @description A capability a vehicle or shift provides, at a proficiency level:
3402
4033
  * `{ "name": "gas", "level": 3 }`. Always an object; a bare string is
@@ -3426,262 +4057,258 @@ export interface components {
3426
4057
  * Reported on stops (`routes[].stops[].violations`) and on routes
3427
4058
  * (`routes[].violations`) in the `POST /v3/routing/evaluate` response.
3428
4059
  * @example {
4060
+ * "code": "capacity",
4061
+ * "dimension": "weight",
4062
+ * "excess": 15,
3429
4063
  * "message": "Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)",
3430
- * "type": "capacity"
4064
+ * "unit": "load"
3431
4065
  * }
3432
4066
  */
3433
4067
  Violation: {
3434
4068
  /**
3435
- * @description Human-readable description of what was violated.
3436
- * @example Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)
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).
3437
4075
  */
3438
- message: string;
4076
+ code: components["schemas"]["ConstraintCode"];
3439
4077
  /**
3440
- * @description Machine-readable violation type: `time_window`, `capacity`, `skills`,
3441
- * `tags`, `first_job`, `unreachable`, `commitment`, `eligibility`,
3442
- * `same_vehicle`, `same_day`, `same_route`, `synchronized`, `time_lag`,
3443
- * `max_distance`, `max_duration`, `shift_end`, `sequence`, `max_tasks`,
3444
- * `break`, `shipment`, `multi_trip`, `period_limit` (a `limits.periods`
3445
- * cap, reported once per period on the route of its first used shift),
3446
- * `quota` (a `quotas[]` cap, reported the same way), or `infeasible`
3447
- * (the insertion check refused a stop without naming a constraint; not
3448
- * expected in practice). `max_tasks`, `break`, `multi_trip`,
3449
- * `period_limit` and `quota` are route-level; `sequence` and
3450
- * `shipment` are on the stop.
3451
- *
3452
- * Deliberately an open string rather than an enum: stop-level types come
3453
- * from the active constraint set, so a new constraint can add one without
3454
- * a breaking schema change. Match on the values you handle and treat
3455
- * unknown ones as generic violations.
3456
- * @example capacity
4078
+ * @description The capacity dimension over its limit. Only on `capacity`.
4079
+ * @example weight
3457
4080
  */
3458
- type: string;
3459
- };
3460
- /**
3461
- * @description A single-stop visit: one location served once (the `jobs[]` entry type).
3462
- * For a pickup bound to a delivery on the same vehicle, use `shipments[]`.
3463
- * @example {
3464
- * "id": "job-1",
3465
- * "location": [
3466
- * 3.725,
3467
- * 51.05
3468
- * ],
3469
- * "pickup": {
3470
- * "weight": 20
3471
- * },
3472
- * "service_duration_s": 300,
3473
- * "skills": [
3474
- * {
3475
- * "name": "fridge"
3476
- * }
3477
- * ],
3478
- * "time_windows": [
3479
- * {
3480
- * "from": "2026-07-01T09:00:00+02:00",
3481
- * "to": "2026-07-01T12:00:00+02:00"
3482
- * }
3483
- * ]
3484
- * }
3485
- */
3486
- Visit: {
4081
+ dimension?: string | null;
3487
4082
  /**
3488
- * @description Absolute price of serving this task on a given vehicle, in the
3489
- * objective's currency. Charged once, when that vehicle (on any of its
3490
- * shifts) serves the task; unlisted vehicles cost nothing. Unlike
3491
- * `preferences`, which charges the vehicles that did NOT get the task,
3492
- * this prices the vehicle that did, so a task rated badly everywhere is
3493
- * the first one dropped when capacity runs out. It lives in the cost tier,
3494
- * below `priority`, and adds to `preferences`, `drop_fee` and travel.
3495
- * Not applied by decomposition: a problem that sets it solves monolithically.
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
3496
4088
  */
3497
- assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
4089
+ excess?: number | null;
3498
4090
  /**
3499
- * @description Whether a break may interrupt service here. Default `true`. `false`
3500
- * is not supported yet and is rejected with HTTP 400.
3501
- * @example true
4091
+ * @description Human-readable description of what was violated.
4092
+ * @example Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)
3502
4093
  */
3503
- break_interruptible?: boolean | null;
3504
- /** @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. */
3505
- delivery?: {
3506
- [key: string]: number;
3507
- } | null;
4094
+ message: string;
4095
+ /** @description Unit of `excess`; present exactly when `excess` is. */
4096
+ unit?: null | components["schemas"]["QuantityUnit"];
4097
+ };
4098
+ /**
4099
+ * @description Spreads work across vehicles: each vehicle's scheduled service time is
4100
+ * compared with its share of all the work, and the part outside a tolerance
4101
+ * band is charged.
4102
+ *
4103
+ * The balanced quantity is **service time only**: every served task's
4104
+ * `service_duration_s`, scaled by the vehicle's `service_factor`. Travel,
4105
+ * `setup_duration_s`, waiting and breaks are not counted, and a task-level
4106
+ * `service_factors` entry scales the measure but not the target. Shares are
4107
+ * fixed when the request is read: every task counts towards the total,
4108
+ * served or not, so with many unassigned tasks every vehicle sits under its
4109
+ * share and the term pulls work in without ordering the routes between them;
4110
+ * balancing pressure appears once routes enter their band. A vehicle with
4111
+ * several shifts has its share split across them by the work each shift can
4112
+ * reach (the service time of the tasks whose windows overlap it), weighted
4113
+ * by shift length, so a day with no tasks carries none of the share; each
4114
+ * shift is charged on its own part. An empty, non-exempt shift pays for its whole share, so pair the
4115
+ * term with `costs.fixed` or `per_vehicle` only when both are meant.
4116
+ * See `vehicles[].workload_weight` to give a part-time vehicle a smaller
4117
+ * share. A problem that sets the term solves without decomposition, like
4118
+ * `assignment_costs`.
4119
+ */
4120
+ WorkloadShare: {
3508
4121
  /**
3509
4122
  * Format: double
3510
- * @description Drop **price** — what leaving this task unserved costs you, in the same
3511
- * currency as `objective.costs`, and the only way to make a task
3512
- * droppable. Tasks without a `drop_fee` must be served.
3513
- *
3514
- * This is money, not a priority: it enters the same cost the solver
3515
- * minimises, so the task is served only while serving it costs less than
3516
- * the fee. Fees the plan chose to pay are reported in
3517
- * `score.components.drop_fees` and summed into `score.cost`.
3518
- *
3519
- * On a shipment the fee applies to the pair, charged once.
3520
- * @example 25
3521
- */
3522
- drop_fee?: number | null;
3523
- /** @description Hard vehicle allow/exclude. */
3524
- eligible_vehicles?: null | components["schemas"]["Eligibility"];
3525
- /**
3526
- * @description Job id: 1 to 128 characters, unique across `jobs` + `shipments`.
3527
- * @example job-1
3528
- */
3529
- id: string;
3530
- /**
3531
- * @description Where this visit happens. Omit for a "virtual" (location-less) job:
3532
- * it still has service duration, time windows, load, and skills, but
3533
- * requires no travel — the vehicle's position doesn't change when it
3534
- * serves one. Virtual and located jobs may be mixed freely in the same
3535
- * request and route. A virtual job's stop in the solution response
3536
- * reports the resolved location of its nearest real (located)
3537
- * neighbor in the route — the predecessor when there is one, otherwise
3538
- * the successor — so it is `null` only on a route that has no located
3539
- * stop at all (an all-virtual route on an open-start/open-end shift).
3540
- * A shipment's legs still require a `location`.
3541
- */
3542
- location?: null | components["schemas"]["Place"];
3543
- /**
3544
- * @description Hard-pin this job to one vehicle id — only that vehicle (any of its
3545
- * shifts) may serve it, and once placed, re-optimization never removes it
3546
- * or moves it to another vehicle. Stronger than `eligible_vehicles`
3547
- * (which filters a set) and hard, unlike `preferences`.
3548
- *
3549
- * A pin means "stays on this vehicle if placed", **not** "must be
3550
- * served": the task can still end up unassigned (for example when it does
3551
- * not fit), and with a `drop_fee` it then pays the fee. An id that
3552
- * matches no vehicle is rejected with HTTP 400.
3553
- * @example vehicle-1
3554
- */
3555
- locked_vehicle?: string | null;
3556
- /**
3557
- * @description Quantity picked up at this visit: goes onto the vehicle here and stays
3558
- * aboard until the route ends or reloads. Non-negative magnitudes per
3559
- * named dimension. A swap that collects one quantity and drops off
3560
- * another at the same address is one job with both `pickup` and
3561
- * `delivery`.
3562
- */
3563
- pickup?: null | components["schemas"]["BTreeMap"];
3564
- /**
3565
- * @description Soft vehicle affinity preferences, priced. Each entry is independent:
3566
- * a job listing several preferred vehicles it doesn't get pays each
3567
- * one's `violation_cost` (compounding, the same rule as a vehicle's
3568
- * `preferred_tags`).
3569
- */
3570
- preferences?: components["schemas"]["Preference"][] | null;
3571
- /**
3572
- * Format: date-time
3573
- * @description Soft preference for the calendar day this task is served on, in a
3574
- * multi-day (multi-shift) problem.
3575
- *
3576
- * An RFC 3339 datetime, UTC offset required, on the intended day. A day is the calendar date of
3577
- * the value **in its own UTC offset**, the same rule that dates a shift
3578
- * from its `from`, so passing the target shift's `from` verbatim is
3579
- * always correct.
3580
- *
3581
- * Soft, and priced by `objective.non_preferred_date_cost` — a flat charge
3582
- * applied once to a task served on any other day. **With that cost unset or
3583
- * zero this field has no effect.** The charge is part of `score.cost`,
3584
- * which ranks below serving required tasks, so a task is never left
3585
- * unassigned to honour its preferred date; `locked_vehicle` (hard) also
3586
- * still wins.
3587
- *
3588
- * Supported on shipments as well as jobs. Both legs of a shipment ride
3589
- * the same route, so the preferred day is a property of the pair: set it
3590
- * on the shipment itself, and `non_preferred_date_cost` is charged once
3591
- * for the pair rather than once per leg.
3592
- * @example 2026-08-04T08:00:00+02:00
3593
- */
3594
- preferred_date?: string | null;
3595
- /**
3596
- * Format: int32
3597
- * @description Importance of a must-serve task when not all of them fit: the solver
3598
- * maximises the summed `priority` of served tasks before any cost. `>= 1`,
3599
- * default `1` (maximise the count). A rank, not money — it never makes a
3600
- * task droppable; use `drop_fee` for that. Both set is a 400.
3601
- * @example 3
3602
- */
3603
- priority?: number | null;
3604
- /**
3605
- * Format: int32
3606
- * @description On-site service time paid per job (seconds).
3607
- *
3608
- * This is the nominal figure. The serving vehicle's `service_factor`
3609
- * scales it — the time actually scheduled is
3610
- * `service_duration_s / service_factor` — so the solution's
3611
- * `stops[].service_s` may differ from what you sent here.
3612
- * @example 300
3613
- */
3614
- service_duration_s?: number | null;
3615
- /**
3616
- * @description Per-vehicle work-rate overrides for this task's `service_duration_s`,
3617
- * composed multiplicatively with the serving vehicle's or shift's
3618
- * `service_factor`. On a shipment the override scales both legs. A
3619
- * vehicle not listed works at its own rate.
3620
- */
3621
- service_factors?: components["schemas"]["ServiceFactor"][] | null;
3622
- /**
3623
- * Format: int32
3624
- * @description Setup time paid once on arrival at a new location (seconds),
3625
- * distinct from `service_duration_s`. Skipped when the immediate real
3626
- * predecessor in the route already sits at this location — co-located
3627
- * stops share one setup.
3628
- *
3629
- * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
3630
- * overhead (parking, walking to the door), not the work itself.
3631
- * @example 60
3632
- */
3633
- setup_duration_s?: number | null;
3634
- /**
3635
- * @description Hard skill requirements — the assigned vehicle must provide every one,
3636
- * at or above each requirement's `min_level`.
3637
- */
3638
- skills?: components["schemas"]["SkillReq"][] | null;
3639
- /**
3640
- * @description Free-form task labels (zones/territories, grouping/relation labels).
3641
- * Used for `tag`/relation resolution and, when a shift scopes itself via
3642
- * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
3643
- * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
3644
- * `skills`, which requires ALL. Not capability matching on its own.
4123
+ * @description Money per hour a vehicle's service time is outside the band, in the
4124
+ * request's currency. Greater than 0 and at least 0.036 (the internal
4125
+ * resolution); omit `workload_share` to switch the term off.
4126
+ * @example 35
3645
4127
  */
3646
- tags?: string[] | null;
4128
+ per_imbalance_hour: number;
3647
4129
  /**
3648
- * @description Soft target for this task, measured at its arrival (default) or
3649
- * departure. On a shipment it is measured on the **delivery** leg.
4130
+ * Format: double
4131
+ * @description Half-width of the band as a fraction of the vehicle's share, `0` up to
4132
+ * but not including `1`. Default `0.1`: a vehicle within 10% of its share
4133
+ * is not charged. The charge grows from the band edge.
4134
+ * @example 0.1
3650
4135
  */
3651
- target?: null | components["schemas"]["Target"];
3652
- /** @description Time windows for this visit. */
3653
- time_windows?: components["schemas"]["TimeWindow"][] | null;
4136
+ tolerance?: number | null;
4137
+ };
4138
+ };
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
+ };
3654
4296
  };
3655
4297
  };
3656
- responses: never;
3657
- parameters: never;
3658
- requestBodies: never;
3659
- headers: never;
3660
- pathItems: never;
3661
- }
3662
- export type $defs = Record<string, never>;
3663
- export interface operations {
3664
- evaluate: {
4298
+ solve: {
3665
4299
  parameters: {
3666
- query?: {
3667
- /**
3668
- * @description Check the request without fetching a matrix or searching. 200
3669
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
3670
- * and caps; `plan` is checked only by the real call, after the fetch.
3671
- */
3672
- validate_only?: boolean;
3673
- };
4300
+ query?: never;
3674
4301
  header?: never;
3675
4302
  path?: never;
3676
4303
  cookie?: never;
3677
4304
  };
3678
4305
  requestBody: {
3679
4306
  content: {
3680
- "application/json": components["schemas"]["EvaluateRequest"];
4307
+ "application/json": components["schemas"]["SolveRequest"];
3681
4308
  };
3682
4309
  };
3683
4310
  responses: {
3684
- /** @description Solution evaluated. With `?validate_only=true`: a `ValidateOnlyResponse`, `{"valid": true, "warnings": []}`, without a matrix fetch, not billed. */
4311
+ /** @description Solution found. */
3685
4312
  200: {
3686
4313
  headers: {
3687
4314
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3689,10 +4316,10 @@ export interface operations {
3689
4316
  [name: string]: unknown;
3690
4317
  };
3691
4318
  content: {
3692
- "application/json": components["schemas"]["OrValidateOnly_SolveResponse"];
4319
+ "application/json": components["schemas"]["SolveResponse"];
3693
4320
  };
3694
4321
  };
3695
- /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and a JSON pointer into the request body. */
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. */
3696
4323
  400: {
3697
4324
  headers: {
3698
4325
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3729,7 +4356,7 @@ export interface operations {
3729
4356
  "application/json": components["schemas"]["ErrorBody"];
3730
4357
  };
3731
4358
  };
3732
- /** @description Request body larger than 10 MiB */
4359
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
3733
4360
  413: {
3734
4361
  headers: {
3735
4362
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3748,7 +4375,7 @@ export interface operations {
3748
4375
  "application/json": components["schemas"]["ErrorBody"];
3749
4376
  };
3750
4377
  };
3751
- /** @description Request `Content-Type` is not `application/json` */
4378
+ /** @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) */
3752
4379
  415: {
3753
4380
  headers: {
3754
4381
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3785,7 +4412,7 @@ export interface operations {
3785
4412
  "application/json": components["schemas"]["ErrorBody"];
3786
4413
  };
3787
4414
  };
3788
- /** @description Travel times and distances could not be fetched (`code: matrix_provider_error`). The request can be retried. */
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. */
3789
4416
  502: {
3790
4417
  headers: {
3791
4418
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3796,7 +4423,7 @@ export interface operations {
3796
4423
  "application/json": components["schemas"]["ErrorBody"];
3797
4424
  };
3798
4425
  };
3799
- /** @description No capacity right now (`code: overloaded`). 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. */
3800
4427
  503: {
3801
4428
  headers: {
3802
4429
  /** @description Seconds to wait before retrying. */
@@ -3819,27 +4446,20 @@ export interface operations {
3819
4446
  };
3820
4447
  };
3821
4448
  };
3822
- solve: {
4449
+ suggest: {
3823
4450
  parameters: {
3824
- query?: {
3825
- /**
3826
- * @description Check the request without fetching a matrix or searching. 200
3827
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
3828
- * and caps; `plan` is checked only by the real call, after the fetch.
3829
- */
3830
- validate_only?: boolean;
3831
- };
4451
+ query?: never;
3832
4452
  header?: never;
3833
4453
  path?: never;
3834
4454
  cookie?: never;
3835
4455
  };
3836
4456
  requestBody: {
3837
4457
  content: {
3838
- "application/json": components["schemas"]["SolveRequest"];
4458
+ "application/json": components["schemas"]["SuggestRequest"];
3839
4459
  };
3840
4460
  };
3841
4461
  responses: {
3842
- /** @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. */
3843
4463
  200: {
3844
4464
  headers: {
3845
4465
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3847,10 +4467,10 @@ export interface operations {
3847
4467
  [name: string]: unknown;
3848
4468
  };
3849
4469
  content: {
3850
- "application/json": components["schemas"]["OrValidateOnly_SolveResponse"];
4470
+ "application/json": components["schemas"]["SuggestResponse"];
3851
4471
  };
3852
4472
  };
3853
- /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and a JSON pointer into the request body. */
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. */
3854
4474
  400: {
3855
4475
  headers: {
3856
4476
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3887,7 +4507,7 @@ export interface operations {
3887
4507
  "application/json": components["schemas"]["ErrorBody"];
3888
4508
  };
3889
4509
  };
3890
- /** @description Request body larger than 10 MiB */
4510
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
3891
4511
  413: {
3892
4512
  headers: {
3893
4513
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3906,7 +4526,7 @@ export interface operations {
3906
4526
  "application/json": components["schemas"]["ErrorBody"];
3907
4527
  };
3908
4528
  };
3909
- /** @description Request `Content-Type` is not `application/json` */
4529
+ /** @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) */
3910
4530
  415: {
3911
4531
  headers: {
3912
4532
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3943,7 +4563,7 @@ export interface operations {
3943
4563
  "application/json": components["schemas"]["ErrorBody"];
3944
4564
  };
3945
4565
  };
3946
- /** @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. */
3947
4567
  502: {
3948
4568
  headers: {
3949
4569
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -3954,7 +4574,7 @@ export interface operations {
3954
4574
  "application/json": components["schemas"]["ErrorBody"];
3955
4575
  };
3956
4576
  };
3957
- /** @description No capacity right now (`code: overloaded`). 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. */
3958
4578
  503: {
3959
4579
  headers: {
3960
4580
  /** @description Seconds to wait before retrying. */
@@ -3977,27 +4597,139 @@ export interface operations {
3977
4597
  };
3978
4598
  };
3979
4599
  };
3980
- suggest: {
4600
+ validate_evaluate: {
3981
4601
  parameters: {
3982
- query?: {
3983
- /**
3984
- * @description Check the request without fetching a matrix or searching. 200
3985
- * `{"valid": true, "warnings": []}`, or a 400 for the problem, options
3986
- * and caps; `plan` is checked only by the real call, after the fetch.
3987
- */
3988
- 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
+ };
3989
4716
  };
4717
+ };
4718
+ };
4719
+ validate_solve: {
4720
+ parameters: {
4721
+ query?: never;
3990
4722
  header?: never;
3991
4723
  path?: never;
3992
4724
  cookie?: never;
3993
4725
  };
3994
4726
  requestBody: {
3995
4727
  content: {
3996
- "application/json": components["schemas"]["SuggestRequest"];
4728
+ "application/json": components["schemas"]["SolveRequest"];
3997
4729
  };
3998
4730
  };
3999
4731
  responses: {
4000
- /** @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. */
4001
4733
  200: {
4002
4734
  headers: {
4003
4735
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4005,10 +4737,10 @@ export interface operations {
4005
4737
  [name: string]: unknown;
4006
4738
  };
4007
4739
  content: {
4008
- "application/json": components["schemas"]["OrValidateOnly_SuggestResponse"];
4740
+ "application/json": components["schemas"]["ValidateResponse"];
4009
4741
  };
4010
4742
  };
4011
- /** @description The request is invalid. `errors[]` lists what to fix, each entry with a `code` and a JSON pointer into the request body. */
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. */
4012
4744
  400: {
4013
4745
  headers: {
4014
4746
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4045,7 +4777,7 @@ export interface operations {
4045
4777
  "application/json": components["schemas"]["ErrorBody"];
4046
4778
  };
4047
4779
  };
4048
- /** @description Request body larger than 10 MiB */
4780
+ /** @description Request body larger than 10 MiB (10,485,760 bytes), counted after gzip decompression */
4049
4781
  413: {
4050
4782
  headers: {
4051
4783
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4064,7 +4796,7 @@ export interface operations {
4064
4796
  "application/json": components["schemas"]["ErrorBody"];
4065
4797
  };
4066
4798
  };
4067
- /** @description Request `Content-Type` is not `application/json` */
4799
+ /** @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) */
4068
4800
  415: {
4069
4801
  headers: {
4070
4802
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
@@ -4101,8 +4833,34 @@ export interface operations {
4101
4833
  "application/json": components["schemas"]["ErrorBody"];
4102
4834
  };
4103
4835
  };
4104
- /** @description Travel times and distances could not be fetched (`code: matrix_provider_error`). The request can be retried. */
4105
- 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: {
4106
4864
  headers: {
4107
4865
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4108
4866
  "x-request-id"?: string;
@@ -4112,11 +4870,16 @@ export interface operations {
4112
4870
  "application/json": components["schemas"]["ErrorBody"];
4113
4871
  };
4114
4872
  };
4115
- /** @description No capacity right now (`code: overloaded`). Retry after the number of seconds in the `Retry-After` header. */
4116
- 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: {
4117
4882
  headers: {
4118
- /** @description Seconds to wait before retrying. */
4119
- "Retry-After"?: number;
4120
4883
  /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
4121
4884
  "x-request-id"?: string;
4122
4885
  [name: string]: unknown;
@@ -4124,15 +4887,71 @@ export interface operations {
4124
4887
  content: {
4125
4888
  /**
4126
4889
  * @example {
4127
- * "code": "overloaded",
4128
- * "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'",
4129
4892
  * "request_id": "req_7f3a2c90d1e4b5a6",
4130
- * "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"
4131
4932
  * }
4132
4933
  */
4133
4934
  "application/json": components["schemas"]["ErrorBody"];
4134
4935
  };
4135
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
+ };
4136
4955
  };
4137
4956
  };
4138
4957
  }