@solvice/routing 0.17.2-beta.0 → 0.17.3-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/runs.d.ts ADDED
@@ -0,0 +1,4141 @@
1
+ /**
2
+ * This file was auto-generated by openapi-typescript.
3
+ * Do not make direct changes to the file.
4
+ */
5
+ export interface paths {
6
+ "/v3/routing/runs": {
7
+ parameters: {
8
+ query?: never;
9
+ header?: never;
10
+ path?: never;
11
+ cookie?: never;
12
+ };
13
+ get?: never;
14
+ put?: never;
15
+ /**
16
+ * Submit an async run
17
+ * @description Starts a solve in the background and returns at once with `202` and the run. The body is the same as `POST /v3/routing/solve`, except that `options.time_limit_s` may go up to 3600 and `callback` is not supported yet. The request is checked before the run is accepted, so a bad body is a `400` here, not a failed run later.
18
+ *
19
+ * Poll `GET /v3/routing/runs/{id}` until `status` is `succeeded`, `failed` or `cancelled`, then read the plan from `GET /v3/routing/runs/{id}/result`. At most 10 runs per account are queued or running at once.
20
+ */
21
+ post: operations["submitRoutingRun"];
22
+ delete?: never;
23
+ options?: never;
24
+ head?: never;
25
+ patch?: never;
26
+ trace?: never;
27
+ };
28
+ "/v3/routing/runs/{id}": {
29
+ parameters: {
30
+ query?: never;
31
+ header?: never;
32
+ path?: never;
33
+ cookie?: never;
34
+ };
35
+ /**
36
+ * Get the status of a run
37
+ * @description Returns the run. A run that was not finished is checked against its worker on every call: if the worker is gone, the run turns `failed` with `worker_lost`.
38
+ */
39
+ get: operations["getRoutingRunStatus"];
40
+ put?: never;
41
+ post?: never;
42
+ delete?: never;
43
+ options?: never;
44
+ head?: never;
45
+ patch?: never;
46
+ trace?: never;
47
+ };
48
+ "/v3/routing/runs/{id}/result": {
49
+ parameters: {
50
+ query?: never;
51
+ header?: never;
52
+ path?: never;
53
+ cookie?: never;
54
+ };
55
+ /**
56
+ * Get the plan of a run
57
+ * @description Returns the plan of a `succeeded` run: the same `SolveResponse` that `POST /v3/routing/solve` returns. While the run is `queued` or `running` this is a `409` with `run_not_finished`; a `failed` or `cancelled` run has no plan (`409`, `no_result`).
58
+ */
59
+ get: operations["getRoutingRunResult"];
60
+ put?: never;
61
+ post?: never;
62
+ delete?: never;
63
+ options?: never;
64
+ head?: never;
65
+ patch?: never;
66
+ trace?: never;
67
+ };
68
+ "/v3/routing/runs/{id}/cancel": {
69
+ parameters: {
70
+ query?: never;
71
+ header?: never;
72
+ path?: never;
73
+ cookie?: never;
74
+ };
75
+ get?: never;
76
+ put?: never;
77
+ /**
78
+ * Cancel a run
79
+ * @description Cancels a `queued` or `running` run. The answer is the run: `cancelled`, or unchanged when it had already finished (finishing wins a race). Cancelling does not stop the worker, so the run keeps counting toward the limit of 10 queued or running runs until its worker stops, and a cancelled run never serves a plan.
80
+ */
81
+ post: operations["cancelRoutingRun"];
82
+ delete?: never;
83
+ options?: never;
84
+ head?: never;
85
+ patch?: never;
86
+ trace?: never;
87
+ };
88
+ }
89
+ export type webhooks = Record<string, never>;
90
+ export interface components {
91
+ schemas: {
92
+ /**
93
+ * @description Absolute price of serving one task on one vehicle.
94
+ * @example {
95
+ * "cost": 12.5,
96
+ * "vehicle": "v1"
97
+ * }
98
+ */
99
+ AssignmentCost: {
100
+ /**
101
+ * Format: double
102
+ * @description Cost, in the objective's currency, incurred when this vehicle serves
103
+ * the task. Must be finite and `>= 0`. A vehicle not listed costs `0`.
104
+ * @example 12.5
105
+ */
106
+ cost: number;
107
+ /**
108
+ * @description Vehicle id; applies to every shift of that vehicle. An id that matches
109
+ * no vehicle, or a vehicle listed twice in one task's
110
+ * `assignment_costs`, is rejected with HTTP 400.
111
+ * @example v1
112
+ */
113
+ vehicle: string;
114
+ };
115
+ /**
116
+ * @description A scheduled break within a shift. Tagged by `type`:
117
+ *
118
+ * - `windowed`: a break of `duration_s` that starts inside its window.
119
+ * - `triggered`: a break of `duration_s` taken once drive or duty time
120
+ * passes `threshold_s` (the EU-561 mechanism).
121
+ * - `fixed`: a hard off-duty interval from `from` to `to`.
122
+ *
123
+ * Breaks are injected between stops and appear in the response as `break`
124
+ * stops, carrying the break's `id` when it has one.
125
+ *
126
+ * A `triggered` break always resets its accumulator after a qualifying break
127
+ * and is taken wherever the vehicle is: `resets_accumulator` and `location`
128
+ * do not exist on it. A `windowed` break takes exactly one `time_window` and
129
+ * is also taken wherever the vehicle is: a `location` on it is HTTP 400
130
+ * `not_supported`.
131
+ *
132
+ * There is no paid/unpaid cost accounting: a break's duration is never
133
+ * separately priced, and no `paid` field exists on this schema — sending one
134
+ * is rejected as an unknown field (HTTP 400, `unknown_field`), like any other extra key.
135
+ * @example {
136
+ * "after": "drive",
137
+ * "duration_s": 1800,
138
+ * "threshold_s": 14400,
139
+ * "type": "triggered"
140
+ * }
141
+ */
142
+ Break: components["schemas"]["BreakWindowed"] | components["schemas"]["BreakTriggered"] | components["schemas"]["BreakFixed"];
143
+ /**
144
+ * Fixed
145
+ * @description Mandatory off-duty interval at a fixed time. No service is scheduled
146
+ * inside it, but a drive already under way at `from` continues through
147
+ * it and counts in both `travel_s` and `break_s`.
148
+ */
149
+ BreakFixed: {
150
+ /**
151
+ * Format: date-time
152
+ * @description Start of the break (RFC 3339 instant, UTC offset required).
153
+ */
154
+ from: string;
155
+ /**
156
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
157
+ * Echoed as `id` on the `break` stop that realises this break.
158
+ * @example lunch
159
+ */
160
+ id?: string | null;
161
+ /**
162
+ * Format: date-time
163
+ * @description End of the break (RFC 3339 instant, UTC offset required).
164
+ */
165
+ to: string;
166
+ /**
167
+ * @description Discriminator: always `fixed`. (enum property replaced by openapi-typescript)
168
+ * @enum {string}
169
+ */
170
+ type: "fixed";
171
+ };
172
+ /**
173
+ * @description The window a `windowed` break must start in. Always hard.
174
+ * @example {
175
+ * "from": "2026-07-01T12:00:00+02:00",
176
+ * "to": "2026-07-01T13:30:00+02:00"
177
+ * }
178
+ */
179
+ BreakTimeWindow: {
180
+ /**
181
+ * Format: date-time
182
+ * @description Earliest break start (RFC 3339 instant, UTC offset required).
183
+ */
184
+ from: string;
185
+ /**
186
+ * Format: date-time
187
+ * @description Latest break start (RFC 3339 instant, UTC offset required).
188
+ */
189
+ to: string;
190
+ };
191
+ /**
192
+ * Triggered
193
+ * @description A break taken once drive or duty time passes a threshold.
194
+ */
195
+ BreakTriggered: {
196
+ /** @description What to accumulate: drive time or duty time. */
197
+ after: components["schemas"]["TriggerAfter"];
198
+ /**
199
+ * Format: int32
200
+ * @description Break duration in seconds. Must be `> 0`.
201
+ */
202
+ duration_s: number;
203
+ /**
204
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
205
+ * Echoed as `id` on the `break` stop that realises this break.
206
+ * @example lunch
207
+ */
208
+ id?: string | null;
209
+ /**
210
+ * Format: int64
211
+ * @description Trigger threshold in seconds (strict `>` — the break fires when the
212
+ * accumulator exceeds this). EU 561/2006 drive rule: `16200` (4 h 30).
213
+ * Must be `> 0` and fit in 32 bits.
214
+ * @example 14400
215
+ */
216
+ threshold_s: number;
217
+ /**
218
+ * @description Discriminator: always `triggered`. (enum property replaced by openapi-typescript)
219
+ * @enum {string}
220
+ */
221
+ type: "triggered";
222
+ };
223
+ /**
224
+ * Windowed
225
+ * @description A break that must start inside a time window.
226
+ */
227
+ BreakWindowed: {
228
+ /**
229
+ * Format: int32
230
+ * @description Break duration in seconds. Must be `> 0`.
231
+ */
232
+ duration_s: number;
233
+ /**
234
+ * @description Optional break id: 1 to 128 characters, unique within the shift.
235
+ * Echoed as `id` on the `break` stop that realises this break.
236
+ * @example lunch
237
+ */
238
+ id?: string | null;
239
+ /**
240
+ * @description Not supported on V3: a windowed break is taken wherever the
241
+ * vehicle is when it starts, so a `location` here is rejected with
242
+ * HTTP 400 `not_supported`. Set only by the V2 compatibility mapper.
243
+ */
244
+ location?: null | components["schemas"]["Place"];
245
+ /** @description The window bounding the break's **start**. */
246
+ time_window: components["schemas"]["BreakTimeWindow"];
247
+ /**
248
+ * @description Discriminator: always `windowed`. (enum property replaced by openapi-typescript)
249
+ * @enum {string}
250
+ */
251
+ type: "windowed";
252
+ };
253
+ /**
254
+ * @description The constraint a violation breaks or a reason names: one vocabulary for
255
+ * `routes[].violations[].code`, `routes[].stops[].violations[].code` and
256
+ * `unassigned[].reasons[].constraint`.
257
+ *
258
+ * New values may be added; clients must accept unknown values and handle
259
+ * them generically, for example by showing `message`.
260
+ *
261
+ * 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.
262
+ * @example capacity
263
+ */
264
+ ConstraintCode: string;
265
+ /**
266
+ * @description What running a vehicle costs, in the request's currency
267
+ * (`objective.currency` is only a label). `objective.costs` prices the fleet
268
+ * and `vehicles[].costs` replaces a field for one vehicle; `shifts[].costs`
269
+ * is the same without `per_used_vehicle` (schema `ShiftCosts`), and replaces
270
+ * a field for one shift. Each field resolves on its own: the shift's value,
271
+ * else the vehicle's, else the fleet's, else the default. Nothing is added
272
+ * on top of a fleet rate, and every field is reported under the same
273
+ * `score.components` key at every level. `0` means priced at zero; absent
274
+ * means inherit.
275
+ *
276
+ * Rates are rounded to the internal grid (1/100 000 of a currency unit per
277
+ * second or per metre); a nonzero rate too small to represent is rejected.
278
+ * Every value must be finite and `>= 0`.
279
+ *
280
+ * Lateness is not priced here: `objective.per_late_hour` (or a window's own
281
+ * `per_late_hour`) is the rate, because it softens a constraint rather than
282
+ * pricing a resource.
283
+ * @example {
284
+ * "per_route": 50,
285
+ * "per_route_hour": 35,
286
+ * "per_travel_km": 0.2
287
+ * }
288
+ */
289
+ Costs: {
290
+ /**
291
+ * Format: double
292
+ * @description Per hour a route finishes past its shift's `to` (possible only with
293
+ * `max_overtime_s`), reported in `score.components.overtime`, on top of
294
+ * `per_route_hour`. Default `0`: overtime is unpriced.
295
+ * @example 0
296
+ */
297
+ per_overtime_hour?: number | null;
298
+ /**
299
+ * Format: double
300
+ * @description Flat charge for each used shift (a route with at least one task),
301
+ * reported in `score.components.routes`. Default `0`. The higher it is,
302
+ * the more travel the solver accepts to avoid opening another route. It
303
+ * counts shifts, not vehicles: a vehicle that works five days pays it five
304
+ * times, so it does not prefer one vehicle on two shifts over two vehicles
305
+ * on one shift each; use `per_used_vehicle` for that.
306
+ * @example 50
307
+ */
308
+ per_route?: number | null;
309
+ /**
310
+ * Format: double
311
+ * @description Per hour of each route's wall-clock span (travel, service, waiting
312
+ * and breaks), reported in `score.components.time`. Default **35** at objective
313
+ * level; a vehicle or shift value inherits the fleet value.
314
+ * @example 35
315
+ */
316
+ per_route_hour?: number | null;
317
+ /**
318
+ * Format: double
319
+ * @description Per kilometre driven, reported in `score.components.distance`.
320
+ * Default **0.20** at objective level; a vehicle or shift value inherits the
321
+ * fleet value.
322
+ * @example 0.2
323
+ */
324
+ per_travel_km?: number | null;
325
+ /**
326
+ * Format: double
327
+ * @description Flat charge once per vehicle that serves at least one task, however
328
+ * many of its shifts it works. Reported in `score.components.vehicles`.
329
+ * Adds to `per_route`: the vehicle's first used shift pays both, later
330
+ * shifts only `per_route`. Default `0`. Use it to minimise distinct
331
+ * vehicles; use `per_route` to price each working day. Not accepted on
332
+ * `shifts[].costs`. When any vehicle has a non-zero rate and any vehicle
333
+ * has several shifts, the problem solves without decomposition.
334
+ * @example 400
335
+ */
336
+ per_used_vehicle?: number | null;
337
+ /**
338
+ * Format: double
339
+ * @description Per hour spent waiting for a time window to open, reported in
340
+ * `score.components.waiting`, on top of `per_route_hour` (the span
341
+ * includes the wait). Idle before a windowed break's window opens is
342
+ * reported in `wait_s` but not charged here. Default `0`.
343
+ * @example 0
344
+ */
345
+ per_wait_hour?: number | null;
346
+ };
347
+ /**
348
+ * @description A depot: a place a shift starts from, ends at, or reloads at mid-shift,
349
+ * referenced by `id` from `shifts[].start`, `shifts[].end` and
350
+ * `shifts[].reloads`. Each depot keeps its own handling time and reload cost.
351
+ * @example {
352
+ * "id": "gent",
353
+ * "location": [
354
+ * 3.7174,
355
+ * 51.0543
356
+ * ],
357
+ * "service_duration_s": 900
358
+ * }
359
+ */
360
+ Depot: {
361
+ /**
362
+ * @description Depot id: 1 to 128 characters, unique across `depots[]`.
363
+ * @example gent
364
+ */
365
+ id: string;
366
+ /** @description Where the depot is. */
367
+ location: components["schemas"]["Place"];
368
+ /**
369
+ * Format: double
370
+ * @description Money charged once per reload visit, in the objective's currency.
371
+ * Default 0; at most `1e9`. A shift that only starts or ends here is not
372
+ * charged.
373
+ *
374
+ * Set this when a reload has a real per-reload price the travel terms
375
+ * cannot see — typically the driver labour for the unload itself
376
+ * (`service_duration_s` × the hourly rate). Without it, a reload that
377
+ * consumes only *slack* is free in the objective: it adds no route
378
+ * duration, so the solver will happily insert one to displace time that
379
+ * `objective.costs.per_wait_hour` would otherwise charge as idle, parking
380
+ * the vehicle at a depot for no capacity benefit.
381
+ * @example 38.66
382
+ */
383
+ per_reload?: number | null;
384
+ /**
385
+ * Format: int32
386
+ * @description Handling time in seconds per visit: the load before a shift that starts
387
+ * here, the unload after a shift that ends here, and each reload. A shift
388
+ * end's own `service_duration_s` overrides it for that end. Default 0.
389
+ * The unload after a shift must finish by that shift's `to` (or
390
+ * `to + max_overtime_s`). Not scaled by `service_factor`: this is
391
+ * depot-side handling, not the driver's on-site work rate.
392
+ * @example 900
393
+ */
394
+ service_duration_s?: number | null;
395
+ };
396
+ /**
397
+ * @description Error body of every `/v3/routing/*` endpoint.
398
+ *
399
+ * `status` is the HTTP status as text, `code` says what kind of failure it
400
+ * is, `request_id` identifies the request, and `errors` holds one item per
401
+ * problem found in the request. Branch on `code`, and on `errors[].code` for
402
+ * 400s; the messages are for people.
403
+ * @example {
404
+ * "code": "invalid_request",
405
+ * "errors": [
406
+ * {
407
+ * "code": "out_of_range",
408
+ * "message": "depot 'gent': service_duration_s must be >= 0, got -60",
409
+ * "pointer": "/problem/depots/0/service_duration_s"
410
+ * }
411
+ * ],
412
+ * "message": "depot 'gent': service_duration_s must be >= 0, got -60",
413
+ * "request_id": "req_7f3a2c90d1e4b5a6",
414
+ * "status": "BAD_REQUEST"
415
+ * }
416
+ */
417
+ ErrorBody: {
418
+ /** @description What kind of failure this is. One value per HTTP status class. */
419
+ code: components["schemas"]["ErrorCode"];
420
+ /** @description One entry per problem found in the request. Empty for non-input errors. */
421
+ errors?: components["schemas"]["RequestIssue"][];
422
+ /**
423
+ * @description Human-readable summary. With exactly one item it is that item's
424
+ * message; with several, `"{n} problems in request"` (at most 100 items
425
+ * are listed, and the message says when the list is cut).
426
+ */
427
+ message: string;
428
+ /** @description The `X-Request-Id` of the request (echoed, or generated when absent). */
429
+ request_id?: string | null;
430
+ /**
431
+ * @description The HTTP status as text, e.g. `"BAD_REQUEST"` or
432
+ * `"SERVICE_UNAVAILABLE"`.
433
+ * @example BAD_REQUEST
434
+ */
435
+ status: string;
436
+ };
437
+ /**
438
+ * @description The top-level `code` of an error body.
439
+ *
440
+ * 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.
441
+ */
442
+ ErrorCode: string;
443
+ /**
444
+ * @description The `code` of one `errors[]` item. Clients should accept values they do
445
+ * not know yet.
446
+ *
447
+ * 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.
448
+ */
449
+ ErrorItemCode: string;
450
+ /** @description The gateway's own error answer on `/v3/routing/runs*`, not the `ErrorBody` shape. On `404` and `409` the `message` starts with a code (`not_found`, `run_not_finished`, `no_result`), a colon and a sentence; branch on the HTTP status and that code. The other answers carry no code. */
451
+ GatewayError: {
452
+ /**
453
+ * @description `GATEWAY_ERROR`, or the reason for a malformed `id`.
454
+ * @example GATEWAY_ERROR
455
+ */
456
+ error: string;
457
+ /**
458
+ * @description Absent on a malformed `id`.
459
+ * @example not_found: routing run d28568b1-34cc-4f89-b10b-dc24b26a8275
460
+ */
461
+ message?: string;
462
+ };
463
+ /**
464
+ * @description Keep geographically clustered tasks consecutive in a route.
465
+ *
466
+ * Two tasks are in the same **group** when they lie within `radius_m` of
467
+ * each other. The solver adds `per_entry` to the objective each time a
468
+ * route enters a group from a job outside it, the first entry included;
469
+ * entering from the shift's start or from a reload is free. Keeping each
470
+ * group in one visit minimises the "passing-waypoint" / area re-entry count
471
+ * last-mile fleets track. Presence of this object enables the feature; omit
472
+ * it to disable.
473
+ * @example {
474
+ * "distance_metric": "straight_line",
475
+ * "per_entry": 0.5,
476
+ * "radius_m": 180
477
+ * }
478
+ */
479
+ Grouping: {
480
+ /**
481
+ * @description How neighbour distance is measured. Default `"straight_line"`.
482
+ * @default straight_line
483
+ */
484
+ distance_metric?: null | components["schemas"]["GroupingDistance"];
485
+ /**
486
+ * Format: double
487
+ * @description Cost added to the objective on every entry into a group from a job
488
+ * outside it (a job that is not within `radius_m` of the entered one),
489
+ * the first entry included, in the objective's currency. Entry from the
490
+ * shift's start or from a reload is free. At most 1000 currency units: a
491
+ * larger value is rejected with HTTP 400. Higher keeps clusters together
492
+ * more aggressively at the expense of total travel.
493
+ * @example 0.5
494
+ */
495
+ per_entry: number;
496
+ /**
497
+ * Format: int32
498
+ * @description Radius defining a group, in metres. Default `180`. Must be `> 0`.
499
+ * @default 180
500
+ * @example 180
501
+ */
502
+ radius_m?: number | null;
503
+ };
504
+ /**
505
+ * @description How neighbour distance is measured for `objective.grouping`.
506
+ * @example straight_line
507
+ * @enum {string}
508
+ */
509
+ GroupingDistance: "straight_line" | "road";
510
+ /**
511
+ * @description A single-stop visit: one location served once (the `jobs[]` entry type).
512
+ * For a pickup bound to a delivery on the same vehicle, use `shipments[]`.
513
+ * @example {
514
+ * "id": "job-1",
515
+ * "location": [
516
+ * 3.725,
517
+ * 51.05
518
+ * ],
519
+ * "pickup_load": {
520
+ * "weight": 20
521
+ * },
522
+ * "required_skills": [
523
+ * {
524
+ * "name": "fridge"
525
+ * }
526
+ * ],
527
+ * "service_duration_s": 300,
528
+ * "time_windows": [
529
+ * {
530
+ * "from": "2026-07-01T09:00:00+02:00",
531
+ * "to": "2026-07-01T12:00:00+02:00"
532
+ * }
533
+ * ]
534
+ * }
535
+ */
536
+ Job: {
537
+ /**
538
+ * @description Absolute price of serving this task on a given vehicle, in the
539
+ * objective's currency. Charged once, when that vehicle (on any of its
540
+ * shifts) serves the task; unlisted vehicles cost nothing. Unlike
541
+ * `preferences`, which charges the vehicles that did NOT get the task,
542
+ * this prices the vehicle that did, so a task rated badly everywhere is
543
+ * the first one dropped when capacity runs out. It lives in the cost tier,
544
+ * below `priority`, and adds to `preferences`, `drop_cost` and travel.
545
+ * Not applied by decomposition: a problem that sets it solves monolithically.
546
+ */
547
+ assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
548
+ /**
549
+ * @description Whether a break may pause this job's service. With `true`, a `fixed`
550
+ * break, a `windowed` break or a duty-`triggered` break that falls
551
+ * inside the service pauses it: the work resumes when the break ends,
552
+ * the job departs the break's length later, and the stop reports the
553
+ * paused seconds in `break_s`. A drive-`triggered` break never pauses a
554
+ * job (it counts driving time only). Default `false`: the whole service
555
+ * moves after the break, or the break is taken before the job starts.
556
+ * @example true
557
+ */
558
+ break_interruptible?: boolean | null;
559
+ /**
560
+ * @description Quantity delivered at this visit: comes off the vehicle here, having
561
+ * been loaded at a depot. Direction is carried by the field itself, never
562
+ * by sign — `delivery_load` values are non-negative magnitudes, like `pickup_load`.
563
+ *
564
+ * Unlike a shipment, nothing is picked up for it at another stop: the
565
+ * goods are assumed already aboard from a depot, so the vehicle departs
566
+ * its trip carrying the sum of the trip's `delivery_load` quantities.
567
+ *
568
+ * Absent or empty means no delivery at this visit.
569
+ */
570
+ delivery_load?: null | components["schemas"]["Quantities"];
571
+ /**
572
+ * Format: double
573
+ * @description Drop **price** — what leaving this task unserved costs you, in the same
574
+ * currency as `objective.costs`, and the only way to make a task
575
+ * droppable. Tasks without a `drop_cost` must be served.
576
+ *
577
+ * This is money, not a priority: it enters the same cost the solver
578
+ * minimises, so the task is served only while serving it costs less than
579
+ * dropping it. Drop costs the plan chose to pay are reported in
580
+ * `score.components.drop_costs` and summed into `score.cost`.
581
+ *
582
+ * On a shipment the drop cost applies to the pair, charged once.
583
+ *
584
+ * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
585
+ * is rejected with HTTP 400 (`conflicting_fields`). Also rejected with
586
+ * HTTP 400 (`not_supported`) while a positive `objective.per_delay_workday` is set,
587
+ * since a droppable task could be dropped to avoid its delay charge.
588
+ * @example 25
589
+ */
590
+ drop_cost?: number | null;
591
+ /**
592
+ * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
593
+ * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
594
+ * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
595
+ */
596
+ eligible_vehicles?: null | components["schemas"]["VehicleEligibility"];
597
+ /**
598
+ * @description Job id: 1 to 128 characters, unique across `jobs` + `shipments`.
599
+ * @example job-1
600
+ */
601
+ id: string;
602
+ /**
603
+ * @description Where this visit happens. Omit for a "virtual" (location-less) job:
604
+ * it still has service duration, time windows, load, and skills, but
605
+ * requires no travel — the vehicle's position doesn't change when it
606
+ * serves one. Virtual and located jobs may be mixed freely in the same
607
+ * request and route. A virtual job's stop in the solution response
608
+ * reports the resolved location of its nearest real (located)
609
+ * neighbor in the route — the predecessor when there is one, otherwise
610
+ * the successor — so it is `null` only on a route that has no located
611
+ * stop at all (an all-virtual route on an open-start/open-end shift).
612
+ * A shipment's legs still require a `location`.
613
+ */
614
+ location?: null | components["schemas"]["Place"];
615
+ /**
616
+ * @description Quantity picked up at this visit: goes onto the vehicle here and stays
617
+ * aboard until the route ends or reloads. Non-negative magnitudes per
618
+ * named dimension. A swap that collects one quantity and drops off
619
+ * another at the same address is one job with both `pickup_load` and
620
+ * `delivery_load`.
621
+ */
622
+ pickup_load?: null | components["schemas"]["Quantities"];
623
+ /**
624
+ * @description Soft vehicle affinity preferences, priced. Each entry is independent:
625
+ * a job listing several preferred vehicles it doesn't get pays each
626
+ * one's `violation_cost` (compounding, the same rule as a vehicle's
627
+ * `preferred_tags`).
628
+ */
629
+ preferences?: components["schemas"]["VehiclePreference"][] | null;
630
+ /**
631
+ * Format: int32
632
+ * @description Importance of a must-serve task when not all of them fit: the solver
633
+ * maximises the summed `priority` of served tasks before any cost. `>= 1`,
634
+ * default `1` (maximise the count). A rank, not money — it never makes a
635
+ * task droppable; use `drop_cost` for that. Both set is a 400.
636
+ * @example 3
637
+ */
638
+ priority?: number | null;
639
+ /**
640
+ * @description Hard skill requirements — the assigned vehicle must provide every one,
641
+ * at or above each requirement's `min_level`. A request may use at most
642
+ * 256 distinct `(name, min_level)` pairs across all jobs and shipments
643
+ * (HTTP 400 `limit_exceeded` beyond that).
644
+ */
645
+ required_skills?: components["schemas"]["SkillRequirement"][] | null;
646
+ /**
647
+ * Format: int32
648
+ * @description On-site service time paid per job (seconds).
649
+ *
650
+ * This is the nominal figure. The serving vehicle's `service_factor`
651
+ * scales it — the time actually scheduled is
652
+ * `service_duration_s / service_factor` — so the solution's
653
+ * `stops[].service_s` may differ from what you sent here. Default `0`;
654
+ * a negative value is rejected with HTTP 400.
655
+ * @example 300
656
+ */
657
+ service_duration_s?: number | null;
658
+ /**
659
+ * @description Per-vehicle work-rate factors for this task's `service_duration_s`,
660
+ * which is DIVIDED by the factor (above `1` = faster). Each multiplies
661
+ * the serving vehicle's rate (the shift's `service_factor` if set, else
662
+ * the vehicle's): effective service time = `service_duration_s /
663
+ * (shift_or_vehicle_factor * factor)`. On a shipment the factor scales
664
+ * both legs. A vehicle not listed works at its own rate.
665
+ */
666
+ service_factors?: components["schemas"]["ServiceFactor"][] | null;
667
+ /**
668
+ * Format: int32
669
+ * @description Setup time paid once on arrival at a new location (seconds),
670
+ * distinct from `service_duration_s`. Skipped when the immediate real
671
+ * predecessor in the route already sits at this location — co-located
672
+ * stops share one setup.
673
+ *
674
+ * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
675
+ * overhead (parking, walking to the door), not the work itself.
676
+ * Default `0`; a negative value is rejected with HTTP 400.
677
+ * @example 60
678
+ */
679
+ setup_duration_s?: number | null;
680
+ /**
681
+ * @description Free-form task labels (zones/territories, relation labels).
682
+ * Used for `tag`/relation resolution and, when a shift scopes itself via
683
+ * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
684
+ * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
685
+ * `required_skills`, which requires ALL. Not capability matching on its own.
686
+ * A request may carry at most 256 distinct tags across all jobs and
687
+ * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
688
+ * lists do not count.
689
+ */
690
+ tags?: string[] | null;
691
+ /**
692
+ * @description Soft target for this task, measured at its arrival (default) or
693
+ * departure. On a shipment it is measured on the **delivery** leg.
694
+ */
695
+ target?: null | components["schemas"]["Target"];
696
+ /** @description Time windows for this visit. */
697
+ time_windows?: components["schemas"]["TimeWindow"][] | null;
698
+ };
699
+ /**
700
+ * @description Which road-network data prices travel times and distances.
701
+ *
702
+ * - `tomtom` (default): TomTom historical-typical traffic at the departure
703
+ * time.
704
+ * - `osm`: OpenStreetMap free-flow times. No traffic, so
705
+ * `travel.departure_time` is rejected with 400.
706
+ * - `tomtom_real_time`: TomTom live traffic at the moment of the request.
707
+ * **Not yet enabled: currently always rejected with 403 `feature_not_enabled`.** Once enabled:
708
+ * `travel.departure_time` is rejected; every vehicle must use the `car`
709
+ * profile; at most 100 distinct locations; up to ~25 s of matrix fetch at
710
+ * 100 locations.
711
+ * @example osm
712
+ * @enum {string}
713
+ */
714
+ MatrixEngine: "tomtom" | "osm" | "tomtom_real_time";
715
+ /**
716
+ * @description Top-level objective configuration.
717
+ *
718
+ * Plans are compared in a fixed order: first **serve the required tasks**
719
+ * (the summed `priority` of the required tasks left unassigned is
720
+ * minimised), then **minimise cost** — the `costs` rates plus every priced
721
+ * preference, reported as `score.cost`. There is no separate vehicle-count
722
+ * step: to use fewer routes, price them with `costs.per_route`
723
+ * (per used shift); to use fewer distinct vehicles when they work several
724
+ * shifts, price them with `costs.per_used_vehicle` (once per vehicle).
725
+ * @example {
726
+ * "costs": {
727
+ * "per_route_hour": 35,
728
+ * "per_travel_km": 0.2
729
+ * },
730
+ * "currency": "EUR"
731
+ * }
732
+ */
733
+ Objective: {
734
+ /**
735
+ * @description Fleet cost rates: the default for every vehicle and shift that does
736
+ * not set its own. See the `Costs` schema.
737
+ */
738
+ costs?: null | components["schemas"]["Costs"];
739
+ /**
740
+ * @description Currency label (ISO 4217, e.g. `EUR`) for every amount in the request
741
+ * and in `score`. Informational: echoed as `score.currency`, it never
742
+ * converts anything.
743
+ * @example EUR
744
+ */
745
+ currency?: string | null;
746
+ /** @description Job-proximity cluster cohesion. See the `Grouping` schema. */
747
+ grouping?: null | components["schemas"]["Grouping"];
748
+ /**
749
+ * Format: double
750
+ * @description ASAP scheduling: money charged for each served task per workday its
751
+ * shift lies after the earliest workday in the request, in the request's
752
+ * currency. A workday is a distinct calendar date, in the shift's own UTC
753
+ * offset, on which at least one shift starts; shifts on one date share a
754
+ * rank, and a date with no shift adds none. Unserved tasks pay nothing;
755
+ * the charge never outranks `priority` and cannot be combined with
756
+ * `drop_cost`. Absent or `0` = off; a single-date request is charged
757
+ * nothing. A problem that sets it, even on one date, solves without
758
+ * decomposition, like `assignment_costs`. Reported as `score.components.delay`. A positive
759
+ * rate below `0.00001` is rejected, as is a rate whose total over the
760
+ * later workdays exceeds `21474.83647` (`out_of_range`).
761
+ * @example 5
762
+ */
763
+ per_delay_workday?: number | null;
764
+ /**
765
+ * Format: double
766
+ * @description Cost per hour of lateness: the default rate for every task window
767
+ * that does not carry its own `time_windows[].per_late_hour`. Omit for
768
+ * hard windows. An explicit `0.0` is rejected as ambiguous (free
769
+ * lateness and hard windows read opposite ways, and lateness is never
770
+ * free). There is no earliness rate. It prices task windows only: a
771
+ * shift's `to` (plus `max_overtime_s` when set) stays a hard limit.
772
+ * Setting it `> 0` alongside a nonzero `time_windows[].choice_cost` anywhere in
773
+ * the request is rejected with HTTP 400.
774
+ * @example 60
775
+ */
776
+ per_late_hour?: number | null;
777
+ /** @description Spreads work across vehicles. See the `WorkloadShare` schema. */
778
+ workload_share?: null | components["schemas"]["WorkloadShare"];
779
+ };
780
+ /**
781
+ * @description The recurrence of a period limit (`limits.periods[].every`).
782
+ * @enum {string}
783
+ */
784
+ PeriodEvery: "day" | "week";
785
+ /**
786
+ * @description A cap on a vehicle's totals across every shift that starts in one period.
787
+ * Set exactly one of `every`, or `from` and `to`; and at least one maximum.
788
+ * @example {
789
+ * "every": "week",
790
+ * "max_route_duration_s": 144000,
791
+ * "max_stops": 40
792
+ * }
793
+ */
794
+ PeriodLimit: {
795
+ /** @description A recurring period: every `day`, or every `week` (weeks start Monday). */
796
+ every?: null | components["schemas"]["PeriodEvery"];
797
+ /**
798
+ * Format: date-time
799
+ * @description Start of one explicit period (RFC 3339, UTC offset required), with `to`. The window must
800
+ * hold at least one of the vehicle's shift starts; a period inside one
801
+ * shift is not supported.
802
+ * @example 2026-10-05T00:00:00+02:00
803
+ */
804
+ from?: string | null;
805
+ /**
806
+ * Format: int64
807
+ * @description Hard cap on the summed distance driven, in metres. Must be `>= 0`.
808
+ * @example 900000
809
+ */
810
+ max_distance_m?: number | null;
811
+ /**
812
+ * Format: int64
813
+ * @description Hard cap on the summed route span of the period's shifts, measured as a
814
+ * shift's `max_route_duration_s` is, in seconds. An unused shift adds
815
+ * nothing. Must be `>= 0`.
816
+ * @example 144000
817
+ */
818
+ max_route_duration_s?: number | null;
819
+ /**
820
+ * Format: int32
821
+ * @description Hard cap on served stops across the period's shifts; a job counts as
822
+ * one stop. Start, end, break and reload stops in `routes[].stops` do not
823
+ * count; a shipment counts as two stops.
824
+ * @example 40
825
+ */
826
+ max_stops?: number | null;
827
+ /**
828
+ * Format: date-time
829
+ * @description End of one explicit period (RFC 3339, UTC offset required, exclusive), with `from`.
830
+ * @example 2026-10-12T00:00:00+02:00
831
+ */
832
+ to?: string | null;
833
+ } & (unknown | unknown);
834
+ /**
835
+ * @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.
836
+ * @example [
837
+ * 3.725,
838
+ * 51.05
839
+ * ]
840
+ */
841
+ Place: number[];
842
+ /**
843
+ * @description A plan: which stops each vehicle shift serves, in order. A result's `plan`
844
+ * has exactly this shape and goes back into evaluate, suggest or a
845
+ * warm-started solve unchanged.
846
+ */
847
+ Plan: {
848
+ /** @description One entry per vehicle shift that serves something. */
849
+ routes: components["schemas"]["PlanRoute"][];
850
+ };
851
+ /**
852
+ * @description One vehicle shift's route: every trip of the shift, split by `reload` stops.
853
+ * @example {
854
+ * "shift": "mon",
855
+ * "stops": [
856
+ * {
857
+ * "id": "boiler-17",
858
+ * "type": "job"
859
+ * }
860
+ * ],
861
+ * "vehicle": "van-3"
862
+ * }
863
+ */
864
+ PlanRoute: {
865
+ /**
866
+ * Format: int32
867
+ * @description On solve, the first `locked_count` stops stay where they are (already
868
+ * dispatched). Counts every listed stop. Cannot be combined with a
869
+ * `reload` stop, and must not exceed the route's stop count — both are
870
+ * validated on every endpoint that takes a plan. Otherwise inert on
871
+ * evaluate. On suggest, no insertion lands before them.
872
+ * @example 1
873
+ */
874
+ locked_count?: number | null;
875
+ /** @description Shift id, within that vehicle. */
876
+ shift: string;
877
+ /** @description Stops in visiting order. */
878
+ stops: components["schemas"]["PlanStop"][];
879
+ /** @description Vehicle id. */
880
+ vehicle: string;
881
+ };
882
+ /**
883
+ * @description One stop of a plan route. Start, end and breaks are placed by the solver
884
+ * and are not listed.
885
+ * @example {
886
+ * "id": "parts-9:pickup",
887
+ * "type": "pickup"
888
+ * }
889
+ */
890
+ PlanStop: components["schemas"]["PlanStopJob"] | components["schemas"]["PlanStopPickup"] | components["schemas"]["PlanStopDelivery"] | components["schemas"]["PlanStopReload"];
891
+ /**
892
+ * PlanStopDelivery
893
+ * @description A shipment's delivery leg.
894
+ */
895
+ PlanStopDelivery: {
896
+ /**
897
+ * @description The leg's stop id: its own `id`, else `{shipment}:delivery`.
898
+ * @example parts-9:delivery
899
+ */
900
+ id: string;
901
+ /**
902
+ * @description Discriminator: always `delivery`. (enum property replaced by openapi-typescript)
903
+ * @enum {string}
904
+ */
905
+ type: "delivery";
906
+ };
907
+ /**
908
+ * PlanStopJob
909
+ * @description A job, by its id.
910
+ */
911
+ PlanStopJob: {
912
+ /**
913
+ * @description Job id.
914
+ * @example boiler-17
915
+ */
916
+ id: string;
917
+ /**
918
+ * @description Discriminator: always `job`. (enum property replaced by openapi-typescript)
919
+ * @enum {string}
920
+ */
921
+ type: "job";
922
+ };
923
+ /**
924
+ * PlanStopPickup
925
+ * @description A shipment's pickup leg.
926
+ */
927
+ PlanStopPickup: {
928
+ /**
929
+ * @description The leg's stop id: its own `id`, else `{shipment}:pickup`.
930
+ * @example parts-9:pickup
931
+ */
932
+ id: string;
933
+ /**
934
+ * @description Discriminator: always `pickup`. (enum property replaced by openapi-typescript)
935
+ * @enum {string}
936
+ */
937
+ type: "pickup";
938
+ };
939
+ /**
940
+ * PlanStopReload
941
+ * @description A reload at a depot: the next trip starts there.
942
+ */
943
+ PlanStopReload: {
944
+ /**
945
+ * @description A depot id from the shift's `reloads`.
946
+ * @example gent
947
+ */
948
+ depot: string;
949
+ /**
950
+ * @description Discriminator: always `reload`. (enum property replaced by openapi-typescript)
951
+ * @enum {string}
952
+ */
953
+ type: "reload";
954
+ };
955
+ /**
956
+ * @description How much road detail `routes[].polyline` carries.
957
+ *
958
+ * This is the knob that decides whether a drawn route follows the roads or
959
+ * cuts corners — **not** the polyline encoding precision, which is fixed at 5
960
+ * and is a sub-metre concern. Measured on a three-stop, 150 km route:
961
+ *
962
+ * | detail | shape points | geometry bytes | added latency |
963
+ * |--------|--------------|----------------|---------------|
964
+ * | `simplified` | 34 | ~200 | ~0 |
965
+ * | `full` | 1,728 | ~5,300 | ~0 (inside run-to-run noise) |
966
+ *
967
+ * Prefer `full` unless response size is the binding constraint: the extra
968
+ * detail is nearly free in time, and `simplified` is what makes a route look
969
+ * like straight lines between stops.
970
+ * @example full
971
+ * @enum {string}
972
+ */
973
+ PolylineDetail: "simplified" | "full";
974
+ /**
975
+ * @description The problem part of every V3 request body.
976
+ * @example {
977
+ * "depots": [
978
+ * {
979
+ * "id": "gent",
980
+ * "location": [
981
+ * 3.7174,
982
+ * 51.0543
983
+ * ]
984
+ * }
985
+ * ],
986
+ * "jobs": [
987
+ * {
988
+ * "id": "job-1",
989
+ * "location": [
990
+ * 3.725,
991
+ * 51.05
992
+ * ],
993
+ * "pickup_load": {
994
+ * "weight": 20
995
+ * },
996
+ * "service_duration_s": 300
997
+ * }
998
+ * ],
999
+ * "vehicles": [
1000
+ * {
1001
+ * "capacity": {
1002
+ * "weight": 500
1003
+ * },
1004
+ * "id": "v1",
1005
+ * "shifts": [
1006
+ * {
1007
+ * "end": {
1008
+ * "depot": "gent"
1009
+ * },
1010
+ * "from": "2026-07-01T08:00:00+02:00",
1011
+ * "id": "mon",
1012
+ * "start": {
1013
+ * "depot": "gent"
1014
+ * },
1015
+ * "to": "2026-07-01T17:00:00+02:00"
1016
+ * }
1017
+ * ]
1018
+ * }
1019
+ * ]
1020
+ * }
1021
+ */
1022
+ Problem: {
1023
+ /** @description Depots that shifts start from, end at, or reload at, by id. */
1024
+ depots?: components["schemas"]["Depot"][];
1025
+ /**
1026
+ * @description Single-stop visits to serve. At most 10,000 tasks per request, `jobs`
1027
+ * and `shipments` combined (HTTP 400 `limit_exceeded` beyond that).
1028
+ */
1029
+ jobs?: components["schemas"]["Job"][];
1030
+ /** @description Objective configuration. */
1031
+ objective?: null | components["schemas"]["Objective"];
1032
+ /** @description Stop caps shared by a set of vehicles. At most 65,535. */
1033
+ quotas?: components["schemas"]["Quota"][];
1034
+ /** @description Ordering, co-assignment and synchronization constraints. */
1035
+ relations?: components["schemas"]["Relation"][] | null;
1036
+ /**
1037
+ * @description Bound pickup→delivery shipments to serve. Counts toward the same
1038
+ * 10,000-task cap as `jobs`.
1039
+ */
1040
+ shipments?: components["schemas"]["Shipment"][];
1041
+ /** @description Where travel times and distances come from. */
1042
+ travel?: null | components["schemas"]["Travel"];
1043
+ /** @description Available vehicles: 1 to 2,000 (HTTP 400 otherwise). */
1044
+ vehicles: components["schemas"]["Vehicle"][];
1045
+ };
1046
+ /**
1047
+ * @description A vehicle's routing profile.
1048
+ * @example car
1049
+ * @enum {string}
1050
+ */
1051
+ Profile: "car" | "truck" | "bike";
1052
+ /**
1053
+ * @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).
1054
+ * @example {
1055
+ * "volume": 2,
1056
+ * "weight": 20
1057
+ * }
1058
+ */
1059
+ Quantities: {
1060
+ [key: string]: number;
1061
+ };
1062
+ /**
1063
+ * @description The unit of a violation's `excess` or a relaxation's `amount`.
1064
+ *
1065
+ * 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.
1066
+ * @example s
1067
+ */
1068
+ QuantityUnit: string;
1069
+ /**
1070
+ * @description A hard cap on how many stops of `tasks` the `vehicles` serve together
1071
+ * in a window. A stop counts when its service starts in `[from, to)`
1072
+ * (`arrival + wait_s` in the response when no windowed break is taken on
1073
+ * arrival there); without a window every stop counts.
1074
+ * Stops count as `max_stops` counts them: a job one, a shipment two. An
1075
+ * over-cap job is left unassigned. Unlike `limits.periods[]`, which counts a
1076
+ * shift by its start, a quota has no `every` recurrence and caps only stop
1077
+ * counts.
1078
+ * @example {
1079
+ * "id": "pool-install",
1080
+ * "max_stops": 2,
1081
+ * "tasks": [
1082
+ * "j1",
1083
+ * "j2",
1084
+ * "j3"
1085
+ * ],
1086
+ * "vehicles": [
1087
+ * "c0",
1088
+ * "c1"
1089
+ * ]
1090
+ * }
1091
+ */
1092
+ Quota: {
1093
+ /**
1094
+ * Format: date-time
1095
+ * @description Window start (RFC 3339, UTC offset required), with `to`. The window
1096
+ * must overlap a shift of one of `vehicles` (counting its
1097
+ * `max_overtime_s`), else the request is rejected with HTTP 400.
1098
+ * @example 2026-10-05T00:00:00+02:00
1099
+ */
1100
+ from?: string | null;
1101
+ /**
1102
+ * @description Quota id: 1 to 128 characters, unique among `quotas`; named in the
1103
+ * `/evaluate` `quota` violation.
1104
+ */
1105
+ id: string;
1106
+ /**
1107
+ * Format: int32
1108
+ * @description The cap on counted stops; a job counts as one stop.
1109
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
1110
+ * shipment counts as two stops.
1111
+ */
1112
+ max_stops: number;
1113
+ /**
1114
+ * @description Job or shipment ids whose stops count, each at most once. At least
1115
+ * one; an id that names no job or shipment is rejected with HTTP 400.
1116
+ */
1117
+ tasks: string[];
1118
+ /**
1119
+ * Format: date-time
1120
+ * @description Window end (RFC 3339, UTC offset required, exclusive), with `from`.
1121
+ * @example 2026-10-06T00:00:00+02:00
1122
+ */
1123
+ to?: string | null;
1124
+ /**
1125
+ * @description Vehicle ids that share the cap, each at most once. At least one; an id
1126
+ * that names no vehicle is rejected with HTTP 400.
1127
+ */
1128
+ vehicles: string[];
1129
+ };
1130
+ /**
1131
+ * @description A hard constraint between tasks, selected by `type`: `sequence`,
1132
+ * `tag_order`, `same_vehicle`, `same_day`, `same_route`, `synchronized`,
1133
+ * `time_lag`, `compatible_vehicles` or `all_or_none`.
1134
+ * Each type carries only its own fields; any other `type` is rejected with
1135
+ * HTTP 400.
1136
+ *
1137
+ * Members are named by `stops` (job ids, or shipment-leg stop ids where
1138
+ * the type accepts them, see below). `same_vehicle`, `same_day` and
1139
+ * `same_route` take **either** `stops` **or** a `tag`, not both. Every
1140
+ * relation is hard.
1141
+ *
1142
+ * A shipment takes part through its legs: `sequence`, `same_vehicle`,
1143
+ * `same_day` and `same_route` accept a leg's stop id (`pickup.id` /
1144
+ * `delivery.id`, by default `"{shipment}:pickup"` / `":delivery"`) and bind
1145
+ * that leg like a job. A leg coupled to other tasks by a `synchronized` or
1146
+ * `time_lag` relation (directly, or through a `sequence` with a member that
1147
+ * is) is rejected with HTTP 400, as is a `sequence` putting a delivery before
1148
+ * its pickup. A shipment's own id in `stops`, or a shipment carrying the
1149
+ * `tag` of a `same_vehicle` or `same_day` relation, is rejected with HTTP 400
1150
+ * `not_supported`: relations never silently skip a member. `same_route`,
1151
+ * `time_lag`, `compatible_vehicles`, `all_or_none` and `tag_order` reject a
1152
+ * shipment with HTTP 400 as well.
1153
+ * @example {
1154
+ * "stops": [
1155
+ * "job-1",
1156
+ * "job-2"
1157
+ * ],
1158
+ * "type": "sequence"
1159
+ * }
1160
+ */
1161
+ 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"];
1162
+ /**
1163
+ * All or none
1164
+ * @description All or none: either every member in `stops` is served, or none is.
1165
+ * Sets no timing; combine with `synchronized` or `time_lag` for when.
1166
+ * Hard. Overlapping `all_or_none` relations chain: one on A and B plus
1167
+ * one on B and C serve all three together or none of them. A group with
1168
+ * a task in a vehicle's locked prefix (`plan.routes[].locked_count`) is
1169
+ * exempt. A member that could be served but is held back because
1170
+ * another cannot reports `all_or_none` in `unassigned[].reasons`.
1171
+ *
1172
+ * Every task must also be named by a `synchronized` or `time_lag`
1173
+ * relation; a task named by neither is rejected with HTTP 400.
1174
+ */
1175
+ RelationAllOrNone: {
1176
+ /**
1177
+ * @description Job ids, at least two. A shipment's own id or a shipment-leg stop id
1178
+ * is rejected with HTTP 400.
1179
+ * @example [
1180
+ * "job-1",
1181
+ * "job-2"
1182
+ * ]
1183
+ */
1184
+ stops: string[];
1185
+ /**
1186
+ * @description Discriminator: always `all_or_none`. (enum property replaced by openapi-typescript)
1187
+ * @enum {string}
1188
+ */
1189
+ type: "all_or_none";
1190
+ };
1191
+ /**
1192
+ * Compatible vehicles
1193
+ * @description Which vehicles may serve a set of tasks together. Every two distinct
1194
+ * vehicles serving `stops` must be compatible under
1195
+ * `vehicles[].compatible_with`; with no lists it restricts nothing.
1196
+ * Tasks left unassigned impose nothing, so a group may be served
1197
+ * partially. Hard.
1198
+ *
1199
+ * Every task must also be named by a `synchronized` or `time_lag`
1200
+ * relation; a task named by neither is rejected with HTTP 400. At most
1201
+ * 16 tasks per relation.
1202
+ */
1203
+ RelationCompatibleVehicles: {
1204
+ /**
1205
+ * @description Job ids, 2 to 16. A shipment's own id or a shipment-leg stop id
1206
+ * is rejected with HTTP 400.
1207
+ * @example [
1208
+ * "job-1",
1209
+ * "job-2"
1210
+ * ]
1211
+ */
1212
+ stops: string[];
1213
+ /**
1214
+ * @description Discriminator: always `compatible_vehicles`. (enum property replaced by openapi-typescript)
1215
+ * @enum {string}
1216
+ */
1217
+ type: "compatible_vehicles";
1218
+ };
1219
+ /**
1220
+ * @description Which instant of a member a `synchronized` or `time_lag` relation is
1221
+ * measured at, named after the response stop field that reports it. There is
1222
+ * no `arrival`: a relation bounds when service happens, not when the vehicle
1223
+ * gets there.
1224
+ * @enum {string}
1225
+ */
1226
+ RelationInstant: "service_start" | "departure";
1227
+ /**
1228
+ * Same day
1229
+ * @description Same calendar day: every member that is served is served on the same
1230
+ * day. The day is the calendar date of the serving shift's `from`, read
1231
+ * in that value's own UTC offset, not the time of the stop. Like
1232
+ * `same_vehicle`, it constrains only the members that end up assigned.
1233
+ */
1234
+ RelationSameDay: {
1235
+ /**
1236
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1237
+ * exclusive with `tag`). A shipment's own id is rejected with
1238
+ * HTTP 400 `not_supported`.
1239
+ */
1240
+ stops?: string[] | null;
1241
+ /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1242
+ tag?: string | null;
1243
+ /**
1244
+ * @description Discriminator: always `same_day`. (enum property replaced by openapi-typescript)
1245
+ * @enum {string}
1246
+ */
1247
+ type: "same_day";
1248
+ } & (unknown | unknown);
1249
+ /**
1250
+ * Same route
1251
+ * @description Same route: every member that ends up assigned is served by one
1252
+ * vehicle shift (one entry of `shifts`), stricter than
1253
+ * `same_vehicle` for vehicles with several `shifts`. Reloads within
1254
+ * the shift do not split a route. Hard-only, with `same_vehicle`'s
1255
+ * partial-service semantics.
1256
+ */
1257
+ RelationSameRoute: {
1258
+ /**
1259
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1260
+ * exclusive with `tag`). A shipment's own id is rejected with HTTP
1261
+ * 400.
1262
+ */
1263
+ stops?: string[] | null;
1264
+ /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1265
+ tag?: string | null;
1266
+ /**
1267
+ * @description Discriminator: always `same_route`. (enum property replaced by openapi-typescript)
1268
+ * @enum {string}
1269
+ */
1270
+ type: "same_route";
1271
+ } & (unknown | unknown);
1272
+ /**
1273
+ * Same vehicle
1274
+ * @description Same vehicle: every member that is served is served by the same
1275
+ * vehicle, on any of its shifts.
1276
+ */
1277
+ RelationSameVehicle: {
1278
+ /**
1279
+ * @description Job ids or shipment-leg stop ids in the relation (mutually
1280
+ * exclusive with `tag`). A shipment's own id is rejected with
1281
+ * HTTP 400 `not_supported`.
1282
+ */
1283
+ stops?: string[] | null;
1284
+ /** @description Tag selecting the relation members (mutually exclusive with `stops`). */
1285
+ tag?: string | null;
1286
+ /**
1287
+ * @description Discriminator: always `same_vehicle`. (enum property replaced by openapi-typescript)
1288
+ * @enum {string}
1289
+ */
1290
+ type: "same_vehicle";
1291
+ } & (unknown | unknown);
1292
+ /**
1293
+ * Sequence
1294
+ * @description Ordering (gaps allowed). Constrains members that end up on the **same
1295
+ * route** only: members on different vehicles are unordered relative to
1296
+ * each other.
1297
+ */
1298
+ RelationSequence: {
1299
+ /**
1300
+ * @description Job ids or shipment-leg stop ids (`pickup.id` / `delivery.id`, by
1301
+ * default `"{shipment}:pickup"` / `"{shipment}:delivery"`), in the
1302
+ * order they must be served. A shipment's own id is
1303
+ * rejected with HTTP 400 `not_supported`.
1304
+ */
1305
+ stops: string[];
1306
+ /**
1307
+ * @description Discriminator: always `sequence`. (enum property replaced by openapi-typescript)
1308
+ * @enum {string}
1309
+ */
1310
+ type: "sequence";
1311
+ };
1312
+ /**
1313
+ * Synchronized
1314
+ * @description Synchronized starts (or ends) across vehicles: every member's
1315
+ * service start — or with `on: departure`, its service end — lies within
1316
+ * `max_spread_s` seconds of every other member's. Hard, checked across
1317
+ * routes; the returned schedule holds a member back where needed so
1318
+ * the bound is met (see `hold_s` on the stop). A hold waits inside the
1319
+ * regular shift only: a member is never held past its shift's `to`
1320
+ * into overtime (`max_overtime_s`); a group that could only meet the
1321
+ * bound that way is left unassigned instead.
1322
+ */
1323
+ RelationSynchronized: {
1324
+ /**
1325
+ * Format: int64
1326
+ * @description Maximum spread between the synchronized instants in seconds
1327
+ * (`0` = exact simultaneity). Required. A negative value, or one that
1328
+ * does not fit in 32 bits, is rejected with HTTP 400 `out_of_range`.
1329
+ */
1330
+ max_spread_s: number;
1331
+ /**
1332
+ * @description Which instant is synchronized: `service_start` (default) or
1333
+ * `departure` (the service end), the stop fields of the same names.
1334
+ * @default service_start
1335
+ */
1336
+ on?: null | components["schemas"]["RelationInstant"];
1337
+ /**
1338
+ * @description Participating job ids, at most 8 (HTTP 400 `limit_exceeded`
1339
+ * beyond that). A shipment-leg stop id is rejected with HTTP 400;
1340
+ * a shipment's own id with HTTP 400 `not_supported`.
1341
+ */
1342
+ stops: string[];
1343
+ /**
1344
+ * @description Discriminator: always `synchronized`. (enum property replaced by openapi-typescript)
1345
+ * @enum {string}
1346
+ */
1347
+ type: "synchronized";
1348
+ };
1349
+ /**
1350
+ * Tag order
1351
+ * @description Ordering between tags: on every route, every task carrying `tags[0]`
1352
+ * precedes every task carrying `tags[1]`, and so on. Tasks carry
1353
+ * membership via their own `tags`. At most one `tag_order` per request.
1354
+ *
1355
+ * Jobs only: if a tag named here selects a **shipment**, the request is
1356
+ * rejected with HTTP 400 (a shipment's two legs already carry their own
1357
+ * hard precedence, which tag ordering cannot compose with yet). Drop the
1358
+ * tag from the shipment.
1359
+ */
1360
+ RelationTagOrder: {
1361
+ /** @description Tag labels in precedence order. Requires at least 2 entries. */
1362
+ tags: string[];
1363
+ /**
1364
+ * @description Discriminator: always `tag_order`. (enum property replaced by openapi-typescript)
1365
+ * @enum {string}
1366
+ */
1367
+ type: "tag_order";
1368
+ };
1369
+ /**
1370
+ * Time lag
1371
+ * @description A directional time bound between two jobs on any vehicles:
1372
+ * `t(to) − t(from)` must lie in `[min_s, max_s]` seconds, each end
1373
+ * measured at the job's service start or end (`on`). "B starts at
1374
+ * least an hour after A ends" is `from: {stop: A, on: departure}, to: {stop: B},
1375
+ * min_s: 3600`; "A and B finish together" is both ends `on: departure` with
1376
+ * `min_s: 0, max_s: 0`. `min_s` defaults to `0`; an absent `max_s` is
1377
+ * unbounded; both may be negative. Hard, checked across routes like
1378
+ * `synchronized` (an unassigned end imposes nothing). A job may take
1379
+ * part in any number of `time_lag` relations; a chain is written as
1380
+ * one relation per consecutive pair. As with `synchronized`, a hold
1381
+ * never waits past the shift's regular end (`to`).
1382
+ */
1383
+ RelationTimeLag: {
1384
+ /** @description The reference end. */
1385
+ from: components["schemas"]["TimeLagMember"];
1386
+ /**
1387
+ * Format: int64
1388
+ * @description Upper bound on `t(to) − t(from)` in seconds. Absent = unbounded.
1389
+ * Must fit in 32 bits and be `>= min_s` (HTTP 400 otherwise).
1390
+ */
1391
+ max_s?: number | null;
1392
+ /**
1393
+ * Format: int64
1394
+ * @description Lower bound on `t(to) − t(from)` in seconds. Default `0`. Must fit
1395
+ * in 32 bits.
1396
+ * @default 0
1397
+ */
1398
+ min_s?: number | null;
1399
+ /** @description The bounded end. */
1400
+ to: components["schemas"]["TimeLagMember"];
1401
+ /**
1402
+ * @description Discriminator: always `time_lag`. (enum property replaced by openapi-typescript)
1403
+ * @enum {string}
1404
+ */
1405
+ type: "time_lag";
1406
+ };
1407
+ /**
1408
+ * @description A best-effort, actionable suggestion for relaxing the problem so a task can be
1409
+ * assigned — derived from the smallest constraint relaxation the solver found.
1410
+ * @example {
1411
+ * "amount": 900,
1412
+ * "message": "Extend a time window by 900s (~15 min).",
1413
+ * "op": "extend_time_window",
1414
+ * "pointer": "/problem/jobs/1/time_windows",
1415
+ * "unit": "s"
1416
+ * }
1417
+ */
1418
+ Relaxation: {
1419
+ /**
1420
+ * Format: int64
1421
+ * @description Magnitude of the change, expressed in `unit`.
1422
+ * @example 900
1423
+ */
1424
+ amount: number;
1425
+ /**
1426
+ * @description Human-readable suggestion.
1427
+ * @example Extend a time window by 900s (~15 min).
1428
+ */
1429
+ message: string;
1430
+ /** @description The kind of change suggested. */
1431
+ op: components["schemas"]["RelaxationOp"];
1432
+ /**
1433
+ * @description [RFC 6901] JSON Pointer to the request field to change, like
1434
+ * `warnings[].pointer`. For a job: `/problem/jobs/{i}/pickup_load`
1435
+ * (`/problem/jobs/{i}/delivery_load` for a job with only a
1436
+ * `delivery_load`) or `/problem/jobs/{i}/time_windows`. For a shipment:
1437
+ * `/problem/shipments/{i}/load` or `/problem/shipments/{i}/pickup/time_windows`
1438
+ * (either leg's window may be the one to extend). It may name a field the
1439
+ * request omits (a JSON Patch `add` target); its task prefix always resolves.
1440
+ *
1441
+ * [RFC 6901]: https://www.rfc-editor.org/rfc/rfc6901
1442
+ * @example /problem/jobs/1/time_windows
1443
+ */
1444
+ pointer: string;
1445
+ /** @description Unit of `amount`: `s` for `extend_time_window`, `load` for `reduce_load`. */
1446
+ unit: components["schemas"]["QuantityUnit"];
1447
+ };
1448
+ /**
1449
+ * @description The kind of change a relaxation suggests.
1450
+ *
1451
+ * 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.
1452
+ * @example extend_time_window
1453
+ */
1454
+ RelaxationOp: string;
1455
+ /** @description One problem in a request. */
1456
+ RequestIssue: {
1457
+ /**
1458
+ * Format: int64
1459
+ * @description `limit_exceeded` only: the count this request has.
1460
+ */
1461
+ actual?: number | null;
1462
+ /** @description What is wrong. */
1463
+ code: components["schemas"]["ErrorItemCode"];
1464
+ /**
1465
+ * Format: int64
1466
+ * @description `limit_exceeded` only: the published cap.
1467
+ */
1468
+ limit?: number | null;
1469
+ /** @description Human-readable description. */
1470
+ message: string;
1471
+ /**
1472
+ * @description RFC 6901 JSON Pointer into the request body, when the problem has a
1473
+ * location. It is relative to the root of the body, so a field of the
1474
+ * problem reads `/problem/...` (e.g.
1475
+ * `"/problem/vehicles/0/shifts/0/from"`).
1476
+ */
1477
+ pointer?: string | null;
1478
+ };
1479
+ /**
1480
+ * @description A single vehicle's route.
1481
+ * @example {
1482
+ * "distance_m": 8450,
1483
+ * "load_peak": {
1484
+ * "weight": 55
1485
+ * },
1486
+ * "shift": "mon",
1487
+ * "stops": [
1488
+ * {
1489
+ * "arrival": "2026-07-01T08:00:00+02:00",
1490
+ * "departure": "2026-07-01T08:00:00+02:00",
1491
+ * "depot": "gent",
1492
+ * "load_after": {
1493
+ * "weight": 0
1494
+ * },
1495
+ * "location": [
1496
+ * 3.7174,
1497
+ * 51.0543
1498
+ * ],
1499
+ * "service_s": 0,
1500
+ * "type": "start"
1501
+ * },
1502
+ * {
1503
+ * "arrival": "2026-07-01T08:10:00+02:00",
1504
+ * "departure": "2026-07-01T09:05:00+02:00",
1505
+ * "distance_m": 2600,
1506
+ * "id": "job-1",
1507
+ * "lateness_s": 0,
1508
+ * "load_after": {
1509
+ * "weight": 20
1510
+ * },
1511
+ * "location": [
1512
+ * 3.725,
1513
+ * 51.05
1514
+ * ],
1515
+ * "service_s": 300,
1516
+ * "service_start": "2026-07-01T09:00:00+02:00",
1517
+ * "travel_s": 600,
1518
+ * "type": "job",
1519
+ * "wait_s": 3000
1520
+ * },
1521
+ * {
1522
+ * "arrival": "2026-07-01T09:13:00+02:00",
1523
+ * "departure": "2026-07-01T09:23:00+02:00",
1524
+ * "distance_m": 2350,
1525
+ * "id": "job-2",
1526
+ * "lateness_s": 0,
1527
+ * "load_after": {
1528
+ * "weight": 55
1529
+ * },
1530
+ * "location": [
1531
+ * 3.71,
1532
+ * 51.06
1533
+ * ],
1534
+ * "service_s": 600,
1535
+ * "service_start": "2026-07-01T09:13:00+02:00",
1536
+ * "travel_s": 480,
1537
+ * "type": "job",
1538
+ * "wait_s": 0
1539
+ * },
1540
+ * {
1541
+ * "arrival": "2026-07-01T09:38:00+02:00",
1542
+ * "departure": "2026-07-01T09:38:00+02:00",
1543
+ * "depot": "gent",
1544
+ * "distance_m": 3500,
1545
+ * "load_after": {
1546
+ * "weight": 55
1547
+ * },
1548
+ * "location": [
1549
+ * 3.7174,
1550
+ * 51.0543
1551
+ * ],
1552
+ * "service_s": 0,
1553
+ * "travel_s": 900,
1554
+ * "type": "end",
1555
+ * "wait_s": 0
1556
+ * }
1557
+ * ],
1558
+ * "time": {
1559
+ * "break_s": 0,
1560
+ * "depot_s": 0,
1561
+ * "overtime_s": 0,
1562
+ * "service_s": 900,
1563
+ * "span_s": 5880,
1564
+ * "travel_s": 1980,
1565
+ * "wait_s": 3000
1566
+ * },
1567
+ * "vehicle": "v1"
1568
+ * }
1569
+ */
1570
+ Route: {
1571
+ /**
1572
+ * Format: int64
1573
+ * @description Total route distance, in metres.
1574
+ * @example 8450
1575
+ */
1576
+ distance_m: number;
1577
+ /** @description Peak load reached on the route, by named dimension. */
1578
+ load_peak?: null | components["schemas"]["Quantities"];
1579
+ /**
1580
+ * @description Road geometry for this route as an [encoded polyline] at precision 5
1581
+ * (~1.1 m), ready to hand to a map library. Present only when
1582
+ * `options.polyline` was set, and absent for a route whose geometry the
1583
+ * routing engine could not produce.
1584
+ *
1585
+ * Traced with this vehicle's `profile` at the solve's departure time, so
1586
+ * it is the same road path the plan was costed on — not a generic car
1587
+ * route. It is a decoration, though: `distance_m` and `time` come
1588
+ * from the solver's matrix and are authoritative if the two ever disagree.
1589
+ *
1590
+ * [encoded polyline]: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
1591
+ * @example _p~iF~ps|U_ulLnnqC_mqNvxq`@
1592
+ */
1593
+ polyline?: string | null;
1594
+ /**
1595
+ * @description The shift id (`vehicles[].shifts[].id`) this route runs on.
1596
+ * @example mon
1597
+ */
1598
+ shift: string;
1599
+ /**
1600
+ * @description Stops in time order (by `departure`), including depot bookends. A
1601
+ * windowed break taken while the vehicle is at a stop is listed just
1602
+ * before that stop and lies within that stop's `arrival` to `departure`
1603
+ * (the end stop included); drive, duty and unavailability breaks end
1604
+ * before the next stop's `arrival`.
1605
+ */
1606
+ stops: components["schemas"]["RouteStop"][];
1607
+ /**
1608
+ * @description Where this route's time goes. `time.span_s` is what the route's
1609
+ * `costs.per_route_hour` is charged on: the shift's rate, else its
1610
+ * vehicle's, else `objective.costs.per_route_hour`.
1611
+ */
1612
+ time: components["schemas"]["TimeTotals"];
1613
+ /** @description The vehicle id (`vehicle.id` from the request) serving this route. */
1614
+ vehicle: string;
1615
+ /**
1616
+ * @description Route-level constraint violations (e.g. `max_distance`, `max_route_duration`,
1617
+ * or `unreachable` for a leg whose destination is not a job stop — the
1618
+ * return to the end depot, or a leg into a reload).
1619
+ * Only populated by `POST /v3/routing/evaluate`; absent on solve responses.
1620
+ */
1621
+ violations?: components["schemas"]["Violation"][];
1622
+ };
1623
+ /**
1624
+ * @description A single stop within a route.
1625
+ *
1626
+ * One flat object for every stop `type`. `type`, `arrival` and `departure`
1627
+ * are present on every stop; every other field is present only on the stop
1628
+ * types its description names, and absent (not `null`) elsewhere:
1629
+ *
1630
+ * | `type` | fields beyond `type`, `arrival`, `departure` |
1631
+ * | --- | --- |
1632
+ * | `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 |
1633
+ * | `start` | `depot`, `location`, `service_s` (absent on an open start) |
1634
+ * | `end` | `depot`, `location`, `wait_s`, `service_s` (absent on an open end), `travel_s`, `distance_m` |
1635
+ * | `reload` | `depot`, `location`, `service_start`, `wait_s`, `service_s`, `travel_s`, `distance_m` |
1636
+ * | `break` | `id` (when the request break names one), `service_s` |
1637
+ *
1638
+ * `load_after` is on every stop when the problem declares a capacity
1639
+ * dimension, and `snapped_location` wherever there is a `location` and the
1640
+ * routing graph snapped it.
1641
+ *
1642
+ * Every stop time is RFC 3339, rendered in the UTC offset of the route's
1643
+ * shift `from` (`Z` when that `from` is UTC or has no offset): a `+02:00`
1644
+ * shift reports `2026-07-01T08:10:00+02:00`, the same instant as
1645
+ * `2026-07-01T06:10:00Z`.
1646
+ * @example {
1647
+ * "arrival": "2026-07-01T08:10:00+02:00",
1648
+ * "departure": "2026-07-01T09:05:00+02:00",
1649
+ * "distance_m": 2600,
1650
+ * "id": "job-1",
1651
+ * "lateness_s": 0,
1652
+ * "load_after": {
1653
+ * "weight": 20
1654
+ * },
1655
+ * "location": [
1656
+ * 3.725,
1657
+ * 51.05
1658
+ * ],
1659
+ * "service_s": 300,
1660
+ * "service_start": "2026-07-01T09:00:00+02:00",
1661
+ * "travel_s": 600,
1662
+ * "type": "job",
1663
+ * "wait_s": 3000
1664
+ * }
1665
+ */
1666
+ RouteStop: {
1667
+ /**
1668
+ * Format: date-time
1669
+ * @description Physical arrival, before any waiting. On `start` when the route
1670
+ * begins; on `break` when the break starts.
1671
+ * @example 2026-07-01T08:10:00+02:00
1672
+ */
1673
+ arrival: string;
1674
+ /**
1675
+ * Format: int32
1676
+ * @description Seconds of driver break taken inside this stop's service, pausing it:
1677
+ * a `fixed`, `windowed` or `triggered` break that fell mid-service on a
1678
+ * job with `break_interruptible: true`. Such a break gets no `break`
1679
+ * stop of its own; its time is counted here and in the route's
1680
+ * `time.break_s`. The stop reconciles as
1681
+ * `departure - service_start == service_s + setup + break_s`, where
1682
+ * setup is the unscaled `setup_duration_s` when paid, else 0. Present on
1683
+ * `job` stops only, when non-zero.
1684
+ * @example 3600
1685
+ */
1686
+ break_s?: number | null;
1687
+ /**
1688
+ * Format: date-time
1689
+ * @description Departure. On `end` when the route finishes, after any depot
1690
+ * handling time; on `break` when the break ends (`arrival + service_s`).
1691
+ * @example 2026-07-01T09:05:00+02:00
1692
+ */
1693
+ departure: string;
1694
+ /**
1695
+ * @description The `depots[].id` of this stop: on every `reload` stop, and on a
1696
+ * `start`/`end` stop whose shift end names a depot. Absent on a
1697
+ * `location` or open end and on task and break stops.
1698
+ * @example gent
1699
+ */
1700
+ depot?: string | null;
1701
+ /**
1702
+ * Format: int32
1703
+ * @description Travel distance from the previous stop, in metres. On task, `reload`
1704
+ * and `end` stops.
1705
+ * @example 2600
1706
+ */
1707
+ distance_m?: number | null;
1708
+ /**
1709
+ * Format: int32
1710
+ * @description The part of `wait_s` spent holding for a `synchronized` or
1711
+ * `time_lag` partner on another vehicle, beyond any wait the time
1712
+ * window already imposed. On task stops, only when non-zero.
1713
+ * @example 0
1714
+ */
1715
+ hold_s?: number | null;
1716
+ /**
1717
+ * @description On a `job` stop the job id; on `pickup`/`delivery` the leg's stop id
1718
+ * (its own `id`, else `{shipment}:pickup` / `{shipment}:delivery`); on a
1719
+ * `break` stop the `id` of the request break (`shifts[].breaks[].id`)
1720
+ * it realises, absent when that break named none. Absent on `start`,
1721
+ * `end` and `reload`.
1722
+ * @example job-1
1723
+ */
1724
+ id?: string | null;
1725
+ /**
1726
+ * Format: int32
1727
+ * @description Seconds the start of service is past the time window's `to` (`0` when
1728
+ * on time), on task stops, measured from the arrival plus any `windowed`
1729
+ * break taken on arrival at this stop (idle until that break's window
1730
+ * opens included). Measures the time window only; a soft target is
1731
+ * reported in `target_lateness_s`.
1732
+ * @example 0
1733
+ */
1734
+ lateness_s?: number | null;
1735
+ /**
1736
+ * @description Load on board after this stop, by named dimension: on `start` when
1737
+ * the vehicle leaves, on `reload` the next trip's departure stock, on
1738
+ * `break` the load after the previous stop. Absent when the problem
1739
+ * declares no capacity dimension.
1740
+ */
1741
+ load_after?: null | components["schemas"]["Quantities"];
1742
+ /**
1743
+ * @description Stop location `[longitude, latitude]` (GeoJSON order). Absent on
1744
+ * every `break` stop, including a break with a pinned location, and on
1745
+ * `start`/`end` stops for a genuinely open end (no configured
1746
+ * coordinate for that end of the shift). A virtual (location-less) job
1747
+ * has no coordinate of its own and reports its nearest located
1748
+ * neighbor's instead, so it is absent only when the whole route is
1749
+ * virtual with open depot ends.
1750
+ * @example [
1751
+ * 3.725,
1752
+ * 51.05
1753
+ * ]
1754
+ */
1755
+ location?: number[] | null;
1756
+ /**
1757
+ * Format: int32
1758
+ * @description Time spent at this stop, in seconds.
1759
+ *
1760
+ * On task stops, the **effective** on-site service time, not the
1761
+ * nominal `service_duration_s` from the request: it already has the
1762
+ * serving vehicle's `service_factor` applied. `departure -
1763
+ * service_start - service_s - break_s` is the stop's setup time: the
1764
+ * request's `setup_duration_s` (unscaled) for the first stop of a run at
1765
+ * the same location (setup is charged when the previous stop is
1766
+ * elsewhere), and 0 for a co-located successor.
1767
+ *
1768
+ * On `reload`, the depot's handling time (`departure - service_start
1769
+ * == service_s`). On `start`/`end`, the depot handling time applied
1770
+ * there (0 on a free-travel end), so `departure - arrival == service_s`
1771
+ * on a start and `departure - arrival - wait_s - Σ windowed break
1772
+ * service_s == service_s` on an end; absent on an open start or end. On `break`, the
1773
+ * break length (`departure - arrival`). `service_factor` never scales
1774
+ * depot, reload or break time.
1775
+ * @example 300
1776
+ */
1777
+ service_s?: number | null;
1778
+ /**
1779
+ * Format: date-time
1780
+ * @description When service starts: `arrival + wait_s` plus the duration of any
1781
+ * break taken on arrival here (a `windowed` one; on a
1782
+ * `break_interruptible` job also a `fixed` or duty-`triggered` one that
1783
+ * falls in the wait). On task and `reload` stops only.
1784
+ * @example 2026-07-01T09:00:00+02:00
1785
+ */
1786
+ service_start?: string | null;
1787
+ /** @description The same point snapped to the routable graph, when available. */
1788
+ snapped_location?: number[] | null;
1789
+ /**
1790
+ * Format: int32
1791
+ * @description Seconds past this task's `target.at`, measured at the stop's arrival
1792
+ * (plus any `windowed` break taken on arrival there, idle before it
1793
+ * included) or departure per `target.on`; `0` when met. Present only on a task
1794
+ * stop carrying a target. A shipment's target is measured on its
1795
+ * delivery leg, so it appears on the `:delivery` stop and never on the
1796
+ * `:pickup` stop.
1797
+ * @example 0
1798
+ */
1799
+ target_lateness_s?: number | null;
1800
+ /**
1801
+ * Format: int32
1802
+ * @description Travel time from the previous stop, in seconds. On task, `reload`
1803
+ * and `end` stops.
1804
+ * @example 600
1805
+ */
1806
+ travel_s?: number | null;
1807
+ /** @description What kind of stop this is. */
1808
+ type: components["schemas"]["StopType"];
1809
+ /**
1810
+ * @description Constraint violations detected at this task stop. Only populated by
1811
+ * `POST /v3/routing/evaluate` (imported solutions may be infeasible); a
1812
+ * solve response never emits violations, so this is absent there.
1813
+ */
1814
+ violations?: components["schemas"]["Violation"][];
1815
+ /**
1816
+ * Format: int32
1817
+ * @description Seconds spent waiting here, counted in `time.wait_s`. On task stops:
1818
+ * before service, for the time window to open and for any cross-route
1819
+ * hold (`hold_s`, included in this figure). On `reload`: before the
1820
+ * reload. On both, also the idle before a windowed break taken on
1821
+ * arrival here whose window had not opened yet, so `service_start ==
1822
+ * arrival + wait_s + Σ` those breaks' `service_s`. On `end`: idle time
1823
+ * at the end, `departure - arrival - service_s` less the `service_s` of
1824
+ * break stops taken there, clamped to be never negative. Idle before a
1825
+ * break is not charged by `per_wait_hour`. Absent on `start` (a start
1826
+ * never waits) and `break`.
1827
+ * @example 3000
1828
+ */
1829
+ wait_s?: number | null;
1830
+ };
1831
+ /** @description One async run. */
1832
+ Run: {
1833
+ /**
1834
+ * Format: uuid
1835
+ * @description The run id. Use it in the paths of the other endpoints.
1836
+ * @example d28568b1-34cc-4f89-b10b-dc24b26a8275
1837
+ */
1838
+ id: string;
1839
+ status: components["schemas"]["RunStatus"];
1840
+ links: components["schemas"]["RunLinks"];
1841
+ /** @description Present when `status` is `failed`. */
1842
+ error?: components["schemas"]["RunError"];
1843
+ /**
1844
+ * Format: date-time
1845
+ * @description When a worker claimed the run, in UTC. Absent while the run is `queued`.
1846
+ * @example 2026-10-15T07:40:59Z
1847
+ */
1848
+ started_at?: string;
1849
+ /**
1850
+ * Format: date-time
1851
+ * @description When the run reached a final state, in UTC. Absent before then.
1852
+ * @example 2026-10-15T07:41:00Z
1853
+ */
1854
+ finished_at?: string;
1855
+ /**
1856
+ * Format: date-time
1857
+ * @description When the run and its plan are deleted: `finished_at` plus 365 days. Absent before the run is final.
1858
+ * @example 2027-10-15T07:41:00Z
1859
+ */
1860
+ expires_at?: string;
1861
+ };
1862
+ /** @description Why a run `failed`, in the `ErrorBody` shape. */
1863
+ RunError: {
1864
+ /**
1865
+ * @description The HTTP status as text.
1866
+ * @example INTERNAL_SERVER_ERROR
1867
+ */
1868
+ status: string;
1869
+ /**
1870
+ * @description `invalid_request`, `travel_provider_error`, `internal` or `worker_lost`. `worker_lost`: the worker stopped before it finished, or the run exceeded 6,000 s.
1871
+ * @example worker_lost
1872
+ */
1873
+ code: string;
1874
+ /**
1875
+ * @description Human-readable summary.
1876
+ * @example the worker stopped before finishing
1877
+ */
1878
+ message: string;
1879
+ /** @description The `X-Request-Id` of the request that submitted the run. */
1880
+ request_id?: string | null;
1881
+ /** @description One entry per problem found in the request, as in `ErrorBody`. */
1882
+ errors?: components["schemas"]["RequestIssue"][];
1883
+ };
1884
+ /** @description Paths of the run, relative to the API host. */
1885
+ RunLinks: {
1886
+ /**
1887
+ * @description `GET` it to poll the run.
1888
+ * @example /v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275
1889
+ */
1890
+ self: string;
1891
+ /**
1892
+ * @description `GET` it for the plan once the run `succeeded`.
1893
+ * @example /v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275/result
1894
+ */
1895
+ result: string;
1896
+ };
1897
+ /**
1898
+ * @description Solve options.
1899
+ * @example {
1900
+ * "polyline": "full",
1901
+ * "seed": 42,
1902
+ * "time_limit_s": 5
1903
+ * }
1904
+ */
1905
+ RunOptions: {
1906
+ /**
1907
+ * @description Return road geometry for each route as `routes[].polyline`:
1908
+ * `simplified` or `full`. Omitted → no geometry (the default). One value
1909
+ * for the whole request, named like the response field it fills.
1910
+ */
1911
+ polyline?: null | components["schemas"]["PolylineDetail"];
1912
+ /**
1913
+ * Format: int64
1914
+ * @description Random seed for the search. Default `42`: omitting it is the same as
1915
+ * sending `42`, so send different values to explore different plans.
1916
+ * Repeated runs on one machine usually return an identical plan; a
1917
+ * materially faster or slower machine can differ.
1918
+ * @default 42
1919
+ * @example 42
1920
+ */
1921
+ seed?: number | null;
1922
+ /**
1923
+ * Format: double
1924
+ * @description Search time budget in seconds, fractions allowed. Default when omitted:
1925
+ * 150 ms plus 4 ms per task (jobs and shipments combined), so 100 tasks
1926
+ * search for 0.55 s. Maximum 3600: a larger value is rejected with HTTP 400.
1927
+ * A value below 0.1 is raised to a 100 ms floor. Pure search time:
1928
+ * fetching travel times and waiting for capacity are not deducted from it,
1929
+ * so the request takes longer than this value.
1930
+ * @example 2.5
1931
+ */
1932
+ time_limit_s?: number | null;
1933
+ /**
1934
+ * @description What to do when travel times cannot be fetched from Solvice Maps:
1935
+ * `estimate` (the default) solves on estimated travel and sets
1936
+ * `summary.travel_estimated`; `fail` returns the 502/503 instead.
1937
+ * Locations that Maps rejects for spanning more than one region are a 400.
1938
+ * @default estimate
1939
+ */
1940
+ travel_fallback?: null | components["schemas"]["TravelFallback"];
1941
+ };
1942
+ /**
1943
+ * @description Request body for `POST /v3/routing/runs`: the `POST /v3/routing/solve` body, with a longer `options.time_limit_s`.
1944
+ * @example {
1945
+ * "options": {
1946
+ * "seed": 42,
1947
+ * "time_limit_s": 5
1948
+ * },
1949
+ * "problem": {
1950
+ * "depots": [
1951
+ * {
1952
+ * "id": "gent",
1953
+ * "location": [
1954
+ * 3.7174,
1955
+ * 51.0543
1956
+ * ]
1957
+ * }
1958
+ * ],
1959
+ * "jobs": [
1960
+ * {
1961
+ * "id": "job-1",
1962
+ * "location": [
1963
+ * 3.725,
1964
+ * 51.05
1965
+ * ],
1966
+ * "pickup_load": {
1967
+ * "weight": 20
1968
+ * },
1969
+ * "required_skills": [
1970
+ * {
1971
+ * "name": "fridge"
1972
+ * }
1973
+ * ],
1974
+ * "service_duration_s": 300,
1975
+ * "time_windows": [
1976
+ * {
1977
+ * "from": "2026-07-01T09:00:00+02:00",
1978
+ * "to": "2026-07-01T12:00:00+02:00"
1979
+ * }
1980
+ * ]
1981
+ * },
1982
+ * {
1983
+ * "id": "job-2",
1984
+ * "location": [
1985
+ * 3.71,
1986
+ * 51.06
1987
+ * ],
1988
+ * "pickup_load": {
1989
+ * "weight": 35
1990
+ * },
1991
+ * "service_duration_s": 600
1992
+ * }
1993
+ * ],
1994
+ * "objective": {
1995
+ * "costs": {
1996
+ * "per_route_hour": 35,
1997
+ * "per_travel_km": 0.2
1998
+ * },
1999
+ * "currency": "EUR"
2000
+ * },
2001
+ * "vehicles": [
2002
+ * {
2003
+ * "capacity": {
2004
+ * "weight": 500
2005
+ * },
2006
+ * "id": "v1",
2007
+ * "profile": "car",
2008
+ * "shifts": [
2009
+ * {
2010
+ * "end": {
2011
+ * "depot": "gent"
2012
+ * },
2013
+ * "from": "2026-07-01T08:00:00+02:00",
2014
+ * "id": "mon",
2015
+ * "start": {
2016
+ * "depot": "gent"
2017
+ * },
2018
+ * "to": "2026-07-01T17:00:00+02:00"
2019
+ * }
2020
+ * ],
2021
+ * "skills": [
2022
+ * {
2023
+ * "name": "fridge"
2024
+ * }
2025
+ * ]
2026
+ * }
2027
+ * ]
2028
+ * }
2029
+ * }
2030
+ */
2031
+ RunRequest: {
2032
+ /** @description Solve options. */
2033
+ options?: null | components["schemas"]["RunOptions"];
2034
+ /**
2035
+ * @description Warm start: the plan the search starts from instead of constructing
2036
+ * from scratch (re-optimization). A result's `plan` goes in as it stands.
2037
+ * See `plan.routes[].locked_count` for freezing a dispatched prefix.
2038
+ *
2039
+ * A **hint, not a guarantee**: an unlocked stop that violates a hard
2040
+ * constraint (e.g. capacity, skills, eligibility, `limits.*`, or a time
2041
+ * window with no `per_late_hour` set) is left unassigned and the
2042
+ * search reinserts it wherever it legitimately fits, or it surfaces in
2043
+ * `unassigned[]` with a typed reason. An infeasible locked stop is a 400.
2044
+ */
2045
+ plan?: null | components["schemas"]["Plan"];
2046
+ /** @description The problem: tasks, fleet, depots, relations, objective, travel. */
2047
+ problem: components["schemas"]["Problem"];
2048
+ };
2049
+ /**
2050
+ * @description Where a run is. `queued` until a worker claims it, then `running`. `succeeded`, `failed` and `cancelled` are final.
2051
+ * @enum {string}
2052
+ */
2053
+ RunStatus: "queued" | "running" | "succeeded" | "failed" | "cancelled";
2054
+ /**
2055
+ * @description How good a plan is. Plans compare in order: fewer `violation_count`
2056
+ * first, then less `unassigned_priority`, then less `cost`.
2057
+ * @example {
2058
+ * "components": {
2059
+ * "assignment": 0,
2060
+ * "delay": 0,
2061
+ * "distance": 1.69,
2062
+ * "drop_costs": 0,
2063
+ * "grouping": 0,
2064
+ * "lateness": 0,
2065
+ * "overtime": 0,
2066
+ * "preferences": 0,
2067
+ * "reloads": 0,
2068
+ * "routes": 0,
2069
+ * "tag_preference": 0,
2070
+ * "target": 0,
2071
+ * "time": 57.1536,
2072
+ * "vehicles": 0,
2073
+ * "waiting": 0,
2074
+ * "window_choice": 0,
2075
+ * "workload_share": 0
2076
+ * },
2077
+ * "cost": 58.8436,
2078
+ * "currency": "EUR",
2079
+ * "unassigned_priority": 0,
2080
+ * "violation_count": 0
2081
+ * }
2082
+ */
2083
+ Score: {
2084
+ /** @description The money of each objective term. */
2085
+ components: components["schemas"]["ScoreComponents"];
2086
+ /**
2087
+ * Format: double
2088
+ * @description Total cost, in the objective's currency: the sum of `components`.
2089
+ * @example 58.8436
2090
+ */
2091
+ cost: number;
2092
+ /**
2093
+ * @description Informational currency label, echoed from `objective.currency`.
2094
+ * @example EUR
2095
+ */
2096
+ currency?: string | null;
2097
+ /**
2098
+ * Format: int64
2099
+ * @description Summed `priority` of the required tasks left unassigned (a task that
2100
+ * priced a `drop_cost` counts in `components.drop_costs` instead).
2101
+ * @example 0
2102
+ */
2103
+ unassigned_priority: number;
2104
+ /**
2105
+ * Format: int32
2106
+ * @description How many hard-constraint violations the plan has (the `violations`
2107
+ * arrays on routes and stops list them). Always `0` on a solve result.
2108
+ * @example 0
2109
+ */
2110
+ violation_count: number;
2111
+ };
2112
+ /**
2113
+ * @description The money of each objective term, in the objective's currency. The
2114
+ * components always sum to `score.cost` exactly: every term the solver
2115
+ * charges lands in exactly one of them.
2116
+ * @example {
2117
+ * "assignment": 0,
2118
+ * "delay": 0,
2119
+ * "distance": 1.69,
2120
+ * "drop_costs": 0,
2121
+ * "grouping": 0,
2122
+ * "lateness": 0,
2123
+ * "overtime": 0,
2124
+ * "preferences": 0,
2125
+ * "reloads": 0,
2126
+ * "routes": 0,
2127
+ * "tag_preference": 0,
2128
+ * "target": 0,
2129
+ * "time": 57.1536,
2130
+ * "vehicles": 0,
2131
+ * "waiting": 0,
2132
+ * "window_choice": 0,
2133
+ * "workload_share": 0
2134
+ * }
2135
+ */
2136
+ ScoreComponents: {
2137
+ /**
2138
+ * Format: double
2139
+ * @description Cost of the serving vehicle's `assignment_costs[].cost` (or the task's
2140
+ * default assignment cost), in currency units.
2141
+ */
2142
+ assignment: number;
2143
+ /**
2144
+ * Format: double
2145
+ * @description Cost of delay, in currency units (`objective.per_delay_workday`): each
2146
+ * served task pays the rate once per workday its shift lies after the
2147
+ * earliest workday in the request.
2148
+ */
2149
+ delay: number;
2150
+ /**
2151
+ * Format: double
2152
+ * @description Distance cost, in currency units: each route's distance priced at
2153
+ * its `costs.per_travel_km` (shift, vehicle or fleet).
2154
+ */
2155
+ distance: number;
2156
+ /**
2157
+ * Format: double
2158
+ * @description The summed `drop_cost` of the tasks left unassigned, in currency units.
2159
+ */
2160
+ drop_costs: number;
2161
+ /**
2162
+ * Format: double
2163
+ * @description Cost of splitting close tasks across routes, in currency units
2164
+ * (`objective.grouping`).
2165
+ */
2166
+ grouping: number;
2167
+ /**
2168
+ * Format: double
2169
+ * @description Cost of priced lateness past a time window, in currency units
2170
+ * (`objective.per_late_hour` or `time_windows[].per_late_hour`).
2171
+ */
2172
+ lateness: number;
2173
+ /**
2174
+ * Format: double
2175
+ * @description Cost of work past a soft shift end, in currency units: priced at the
2176
+ * route's `costs.per_overtime_hour`.
2177
+ */
2178
+ overtime: number;
2179
+ /**
2180
+ * Format: double
2181
+ * @description Cost of `preferences[].violation_cost`, in currency units: paid for
2182
+ * each listed vehicle that did not serve the task. Tag preferences are
2183
+ * `tag_preference`.
2184
+ */
2185
+ preferences: number;
2186
+ /**
2187
+ * Format: double
2188
+ * @description Cost of reload visits, in currency units (`depots[].per_reload`).
2189
+ */
2190
+ reloads: number;
2191
+ /**
2192
+ * Format: double
2193
+ * @description Shift cost, in currency units: `costs.per_route` once per used shift,
2194
+ * at the shift's, vehicle's or fleet's rate.
2195
+ */
2196
+ routes: number;
2197
+ /**
2198
+ * Format: double
2199
+ * @description Cost of serving tasks outside a vehicle's `preferred_tags`, in
2200
+ * currency units.
2201
+ */
2202
+ tag_preference: number;
2203
+ /**
2204
+ * Format: double
2205
+ * @description Cost of missing tasks' `target` times, in currency units
2206
+ * (`target.per_late_hour`).
2207
+ */
2208
+ target: number;
2209
+ /**
2210
+ * Format: double
2211
+ * @description Time cost, in currency units: each route's span priced at its
2212
+ * `costs.per_route_hour` (shift, vehicle or fleet).
2213
+ */
2214
+ time: number;
2215
+ /**
2216
+ * Format: double
2217
+ * @description Vehicle cost, in currency units: `costs.per_used_vehicle` once per
2218
+ * vehicle that serves a task, however many of its shifts it works, at the
2219
+ * vehicle's or fleet's rate.
2220
+ */
2221
+ vehicles: number;
2222
+ /**
2223
+ * Format: double
2224
+ * @description Cost of waiting for time windows to open, in currency units: each
2225
+ * route's wait priced at its `costs.per_wait_hour`. Idle before a
2226
+ * windowed break opens is in `time.wait_s` but not priced here.
2227
+ */
2228
+ waiting: number;
2229
+ /**
2230
+ * Format: double
2231
+ * @description The price of the time window each task was served in, in currency
2232
+ * units (`time_windows[].cost`).
2233
+ */
2234
+ window_choice: number;
2235
+ /**
2236
+ * Format: double
2237
+ * @description Workload outside the equal-share band, in currency units
2238
+ * (`objective.workload_share`).
2239
+ */
2240
+ workload_share: number;
2241
+ };
2242
+ /** @description How the search behind a plan ended. */
2243
+ SearchInfo: {
2244
+ /**
2245
+ * Format: int64
2246
+ * @description Search iterations performed. `0` when nothing was searched.
2247
+ * @example 48210
2248
+ */
2249
+ iterations: number;
2250
+ /** @description How the search ended. */
2251
+ termination: components["schemas"]["SearchTermination"];
2252
+ };
2253
+ /**
2254
+ * @description One point of `search_progress`: the best plan's score `elapsed_ms` into
2255
+ * the search. `unassigned_priority` and `cost` mean what they mean in
2256
+ * `summary.score`; the best plan has the lowest `unassigned_priority`, then the
2257
+ * lowest `cost`, so `cost` can rise when more tasks get served.
2258
+ * @example {
2259
+ * "cost": 58.8436,
2260
+ * "elapsed_ms": 180,
2261
+ * "unassigned_priority": 0
2262
+ * }
2263
+ */
2264
+ SearchProgressPoint: {
2265
+ /**
2266
+ * Format: double
2267
+ * @description Total cost, in the objective's currency.
2268
+ */
2269
+ cost: number;
2270
+ /**
2271
+ * Format: int64
2272
+ * @description Milliseconds since the search started (the clock of
2273
+ * `summary.timings.search_ms`).
2274
+ */
2275
+ elapsed_ms: number;
2276
+ /**
2277
+ * Format: int64
2278
+ * @description Summed `priority` of the required tasks left unassigned.
2279
+ */
2280
+ unassigned_priority: number;
2281
+ };
2282
+ /**
2283
+ * @description How the search ended. New values may be added; clients must accept
2284
+ * unknown values.
2285
+ *
2286
+ * 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.
2287
+ */
2288
+ SearchTermination: string;
2289
+ /**
2290
+ * @description Per-vehicle work-rate override for one task's `service_duration_s`.
2291
+ * @example {
2292
+ * "factor": 1.25,
2293
+ * "vehicle": "v1"
2294
+ * }
2295
+ */
2296
+ ServiceFactor: {
2297
+ /**
2298
+ * Format: double
2299
+ * @description Work-rate factor of `vehicle` on this task. Service time is DIVIDED by
2300
+ * it: above `1` the vehicle works faster here, below `1` slower; `1.0` is a
2301
+ * no-op. It multiplies the vehicle's own rate (the shift's
2302
+ * `service_factor` if set, else the vehicle's): effective service time =
2303
+ * `service_duration_s / (shift_or_vehicle_factor * factor)`. Same
2304
+ * direction and `[0.001, 5]` range as `vehicles[].service_factor`. V2's
2305
+ * `proficiency.durationModifier` multiplied duration instead; the V2
2306
+ * compatibility layer sends its inverse (`1 / durationModifier`) here.
2307
+ * @example 1.25
2308
+ */
2309
+ factor: number;
2310
+ /**
2311
+ * @description Vehicle id; applies to every shift of that vehicle.
2312
+ * @example v1
2313
+ */
2314
+ vehicle: string;
2315
+ };
2316
+ /**
2317
+ * @description One working shift for a vehicle.
2318
+ * @example {
2319
+ * "end": {
2320
+ * "location": [
2321
+ * 3.7174,
2322
+ * 51.0543
2323
+ * ]
2324
+ * },
2325
+ * "from": "2026-07-01T08:00:00+02:00",
2326
+ * "id": "mon",
2327
+ * "start": {
2328
+ * "location": [
2329
+ * 3.7174,
2330
+ * 51.0543
2331
+ * ]
2332
+ * },
2333
+ * "to": "2026-07-01T17:00:00+02:00"
2334
+ * }
2335
+ */
2336
+ Shift: {
2337
+ /**
2338
+ * @description Scheduled driver breaks within this shift — see the `Break` schema for
2339
+ * the supported forms. Injected breaks appear as `break` stops in the
2340
+ * response routes.
2341
+ */
2342
+ breaks?: components["schemas"]["Break"][] | null;
2343
+ /**
2344
+ * @description Capacity for this shift only. Each dimension named here replaces the
2345
+ * vehicle's value for that dimension; dimensions not named keep the
2346
+ * vehicle's `capacity`.
2347
+ */
2348
+ capacity?: null | components["schemas"]["Quantities"];
2349
+ /**
2350
+ * @description Costs for this shift only. Each field set here replaces the same
2351
+ * field of the vehicle's `costs` (or, when the vehicle does not set it,
2352
+ * of `objective.costs`) for this shift; fields not set keep that value.
2353
+ * `per_used_vehicle` is not accepted here: it prices the vehicle, not a
2354
+ * shift.
2355
+ */
2356
+ costs?: null | components["schemas"]["ShiftCosts"];
2357
+ /** @description Where the shift ends. Absent = open end. */
2358
+ end?: null | components["schemas"]["ShiftPlace"];
2359
+ /**
2360
+ * @description Symmetric to `free_start_travel` for travel from the last task to
2361
+ * `end`; `true` without `end` is a 400.
2362
+ * @example false
2363
+ */
2364
+ free_end_travel?: boolean | null;
2365
+ /**
2366
+ * @description When `true`, travel from `start` to the first task is free: it takes
2367
+ * no time and costs nothing, and is left out of the route's distance
2368
+ * and duration. The depot is still reported (a real stop, snapped
2369
+ * coordinate, departure time). Distinct from omitting `start` (an open
2370
+ * route, which drops the depot entirely). `true` without `start` is
2371
+ * rejected with HTTP 400 `conflicting_fields`. Default `false`.
2372
+ * @example false
2373
+ */
2374
+ free_start_travel?: boolean | null;
2375
+ /**
2376
+ * Format: date-time
2377
+ * @description Shift start (RFC 3339 instant, UTC offset required).
2378
+ * @example 2026-07-01T08:00:00+02:00
2379
+ */
2380
+ from: string;
2381
+ /**
2382
+ * @description Shift id: 1 to 128 characters, unique within this vehicle.
2383
+ * @example mon
2384
+ */
2385
+ id: string;
2386
+ /**
2387
+ * @description Load already on the vehicle at shift start (pre-loaded), per
2388
+ * dimension. Occupies capacity on the first trip only — flushed at the
2389
+ * first reload — so it reduces first-trip room per dimension, enforced
2390
+ * by the per-trip capacity constraint. Not validated against
2391
+ * `capacity` at request time: a value at or beyond capacity is
2392
+ * accepted and surfaces as a solve-time result (jobs left unassigned,
2393
+ * or deferred until the vehicle's first reload flushes it), not an
2394
+ * HTTP 400. A dimension named here but absent from `capacity` behaves
2395
+ * the same as capacity `0` in that dimension.
2396
+ */
2397
+ initial_load?: null | components["schemas"]["Quantities"];
2398
+ /**
2399
+ * @description Limits for this shift only. Each field set here replaces the
2400
+ * vehicle's `limits` value; fields not set keep it.
2401
+ */
2402
+ limits?: null | components["schemas"]["ShiftLimits"];
2403
+ /**
2404
+ * Format: int32
2405
+ * @description Maximum allowed overtime beyond `to` in seconds. Overtime is reached
2406
+ * by working late, never by waiting: a `synchronized` or `time_lag`
2407
+ * hold stops at `to`. Default: none (`to` is hard). Must be `>= 0`.
2408
+ * @example 1800
2409
+ */
2410
+ max_overtime_s?: number | null;
2411
+ /**
2412
+ * Format: int32
2413
+ * @description Maximum trips (depot legs) in this shift, across all reload depots.
2414
+ * Counts trips, not reloads: `trips = reloads_used + 1`. `max_trips: 1`
2415
+ * means a single trip — reloads are permitted in `reloads` but the cap
2416
+ * prevents ever using one. `reloads` present with `max_trips` absent
2417
+ * means unlimited trips. A single reload depot can only be
2418
+ * revisited up to 8 times per shift regardless of `max_trips`;
2419
+ * a `max_trips` beyond that against one depot
2420
+ * is accepted but the extra headroom is unreachable — list more than
2421
+ * one reload depot to raise the practical ceiling. `0` is rejected with
2422
+ * HTTP 400 (the first trip already counts as trip 1).
2423
+ * @example 2
2424
+ */
2425
+ max_trips?: number | null;
2426
+ /**
2427
+ * @description Depots (by `depots[].id`, each at most once) the vehicle may return to
2428
+ * mid-shift to reload and start a fresh trip. Each visit takes that
2429
+ * depot's `service_duration_s` and `per_reload`. Cap trips with
2430
+ * `max_trips`.
2431
+ */
2432
+ reloads?: string[] | null;
2433
+ /**
2434
+ * @description Hard tag scope: when set (non-empty), this shift
2435
+ * serves only tasks carrying at least one of these tags. Untagged tasks
2436
+ * remain serveable by every shift. Absent or empty = serves everything.
2437
+ */
2438
+ serves_tags?: string[] | null;
2439
+ /**
2440
+ * Format: double
2441
+ * @description Work-rate factor for this shift only. It REPLACES
2442
+ * `vehicles[].service_factor` for the shift when set (absent = inherit the
2443
+ * vehicle's value, which itself defaults to 1.0); a task's
2444
+ * `service_factors[].factor` for this vehicle multiplies it.
2445
+ *
2446
+ * Same meaning, direction, and `[0.001, 5]` range as the vehicle-level
2447
+ * field: service time is DIVIDED by it, effective service time =
2448
+ * `service_duration_s / service_factor`, so above `1` is faster. Use it
2449
+ * when the same driver works at a different rate on different days — a
2450
+ * measured per-day efficiency, a trainee shift, a two-person crew on
2451
+ * Fridays — instead of collapsing those days into one vehicle-level mean.
2452
+ *
2453
+ * Scope is identical to the vehicle-level field: task
2454
+ * `service_duration_s` only, never `setup_duration_s`, depot handling
2455
+ * (`depots[].service_duration_s`, `start`/`end.service_duration_s`),
2456
+ * waiting, or breaks.
2457
+ */
2458
+ service_factor?: number | null;
2459
+ /**
2460
+ * @description Capabilities this shift provides, replacing the vehicle's `skills`
2461
+ * for this shift only (a technician covering another region on one
2462
+ * day, a crew that only carries a certification on some shifts). A
2463
+ * job's `required_skills` must all appear in the skills of the shift that
2464
+ * serves it, at a level of at least the job's `min_level`. Same entry
2465
+ * shape as `vehicles[].skills`. Absent = the vehicle's `skills`; `[]` =
2466
+ * this shift provides none.
2467
+ */
2468
+ skills?: components["schemas"]["VehicleSkill"][] | null;
2469
+ /** @description Where the shift starts. Absent = open start. */
2470
+ start?: null | components["schemas"]["ShiftPlace"];
2471
+ /**
2472
+ * Format: date-time
2473
+ * @description Shift end (RFC 3339 instant, UTC offset required; hard unless `max_overtime_s` set). The
2474
+ * route must be finished by then, end-depot unload included.
2475
+ * @example 2026-07-01T17:00:00+02:00
2476
+ */
2477
+ to: string;
2478
+ };
2479
+ /**
2480
+ * @description The `Costs` fields for one shift, minus `per_used_vehicle`. A shift is one
2481
+ * of a vehicle's days, so a charge for using the vehicle at all is set on the
2482
+ * vehicle (or the fleet), where it applies once across its shifts. A field
2483
+ * set here replaces the vehicle's value (else the fleet's) for this shift
2484
+ * only; the `Costs` schema says what each field prices.
2485
+ * @example {
2486
+ * "per_route": 50,
2487
+ * "per_travel_km": 0.3
2488
+ * }
2489
+ */
2490
+ ShiftCosts: {
2491
+ /**
2492
+ * Format: double
2493
+ * @description Per hour this route finishes past the shift's `to`, as
2494
+ * `Costs.per_overtime_hour`.
2495
+ * @example 0
2496
+ */
2497
+ per_overtime_hour?: number | null;
2498
+ /**
2499
+ * Format: double
2500
+ * @description Flat charge for this used shift, as `Costs.per_route`.
2501
+ * @example 50
2502
+ */
2503
+ per_route?: number | null;
2504
+ /**
2505
+ * Format: double
2506
+ * @description Per hour of this route's wall-clock span, as `Costs.per_route_hour`.
2507
+ * @example 35
2508
+ */
2509
+ per_route_hour?: number | null;
2510
+ /**
2511
+ * Format: double
2512
+ * @description Per kilometre driven on this shift, as `Costs.per_travel_km`.
2513
+ * @example 0.2
2514
+ */
2515
+ per_travel_km?: number | null;
2516
+ /**
2517
+ * Format: double
2518
+ * @description Per hour spent waiting for a time window to open on this shift, as
2519
+ * `Costs.per_wait_hour`.
2520
+ * @example 0
2521
+ */
2522
+ per_wait_hour?: number | null;
2523
+ };
2524
+ /**
2525
+ * @description Per-shift limits: the route-level `limits` fields a shift may override.
2526
+ * Period limits apply across shifts, so they stay on the vehicle.
2527
+ * @example {
2528
+ * "max_stops": 12
2529
+ * }
2530
+ */
2531
+ ShiftLimits: {
2532
+ /**
2533
+ * Format: int64
2534
+ * @description Hard cap on this shift's route distance, in metres. `0` to
2535
+ * `2147483647`, as on the vehicle.
2536
+ * @example 200000
2537
+ */
2538
+ max_distance_m?: number | null;
2539
+ /**
2540
+ * Format: int64
2541
+ * @description Hard cap on this shift's route span, in seconds. `0` to
2542
+ * `2147483647`, as on the vehicle.
2543
+ * @example 32400
2544
+ */
2545
+ max_route_duration_s?: number | null;
2546
+ /**
2547
+ * Format: int32
2548
+ * @description Maximum stops served in this shift; a job counts as one stop.
2549
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
2550
+ * shipment counts as two stops.
2551
+ * @example 50
2552
+ */
2553
+ max_stops?: number | null;
2554
+ };
2555
+ /**
2556
+ * @description Where a shift starts or ends: exactly one of `location` or `depot`.
2557
+ * @example {
2558
+ * "depot": "gent"
2559
+ * }
2560
+ */
2561
+ ShiftPlace: {
2562
+ /**
2563
+ * @description A `depots[].id`. Excludes `location`.
2564
+ * @example gent
2565
+ */
2566
+ depot?: string | null;
2567
+ /** @description An inline place. Excludes `depot`. */
2568
+ location?: null | components["schemas"]["Place"];
2569
+ /**
2570
+ * Format: int32
2571
+ * @description Handling time in seconds at this end: the morning load at `start`, the
2572
+ * evening unload at `end`. Overrides the depot's `service_duration_s`;
2573
+ * default: the depot's value, or 0 for a `location` end. Not applied on
2574
+ * free travel (`free_start_travel`/`free_end_travel`). Not scaled by
2575
+ * `service_factor`.
2576
+ *
2577
+ * The unload must finish by the shift's `to` (or `to + max_overtime_s`):
2578
+ * a route whose unload would run past it is infeasible. A shift whose
2579
+ * load and unload alone exceed it is rejected with HTTP 400.
2580
+ * @example 600
2581
+ */
2582
+ service_duration_s?: number | null;
2583
+ } & (unknown | unknown);
2584
+ /**
2585
+ * @description A bound pickup→delivery shipment (the `shipments[]` entry type).
2586
+ *
2587
+ * Two stops served by one vehicle, pickup strictly before delivery, with
2588
+ * `load` carried on the vehicle between the two legs.
2589
+ *
2590
+ * `drop_cost` and vehicle eligibility (`eligible_vehicles`, allow
2591
+ * **and** exclude, any length) are fully supported and applied to both legs — a
2592
+ * shipment's pickup and delivery share one droppability/eligibility decision,
2593
+ * since one vehicle must serve both.
2594
+ * @example {
2595
+ * "delivery": {
2596
+ * "location": [
2597
+ * 3.71,
2598
+ * 51.06
2599
+ * ],
2600
+ * "service_duration_s": 300
2601
+ * },
2602
+ * "id": "ship-1",
2603
+ * "load": {
2604
+ * "weight": 20
2605
+ * },
2606
+ * "pickup": {
2607
+ * "location": [
2608
+ * 3.725,
2609
+ * 51.05
2610
+ * ],
2611
+ * "service_duration_s": 300
2612
+ * }
2613
+ * }
2614
+ */
2615
+ Shipment: {
2616
+ /**
2617
+ * @description Absolute price of serving this task on a given vehicle, in the
2618
+ * objective's currency. Charged once, when that vehicle (on any of its
2619
+ * shifts) serves the task; unlisted vehicles cost nothing. Unlike
2620
+ * `preferences`, which charges the vehicles that did NOT get the task,
2621
+ * this prices the vehicle that did, so a task rated badly everywhere is
2622
+ * the first one dropped when capacity runs out. It lives in the cost tier,
2623
+ * below `priority`, and adds to `preferences`, `drop_cost` and travel.
2624
+ * Not applied by decomposition: a problem that sets it solves monolithically.
2625
+ */
2626
+ assignment_costs?: components["schemas"]["AssignmentCost"][] | null;
2627
+ /** @description Delivery leg (load off). */
2628
+ delivery: components["schemas"]["ShipmentStop"];
2629
+ /**
2630
+ * Format: double
2631
+ * @description Drop **price** — what leaving this task unserved costs you, in the same
2632
+ * currency as `objective.costs`, and the only way to make a task
2633
+ * droppable. Tasks without a `drop_cost` must be served.
2634
+ *
2635
+ * This is money, not a priority: it enters the same cost the solver
2636
+ * minimises, so the task is served only while serving it costs less than
2637
+ * dropping it. Drop costs the plan chose to pay are reported in
2638
+ * `score.components.drop_costs` and summed into `score.cost`.
2639
+ *
2640
+ * On a shipment the drop cost applies to the pair, charged once.
2641
+ *
2642
+ * Must be finite, `>= 0` and at most `1e9`; combined with `priority` it
2643
+ * is rejected with HTTP 400 (`conflicting_fields`). Also rejected with
2644
+ * HTTP 400 (`not_supported`) while a positive `objective.per_delay_workday` is set,
2645
+ * since a droppable task could be dropped to avoid its delay charge.
2646
+ * @example 25
2647
+ */
2648
+ drop_cost?: number | null;
2649
+ /**
2650
+ * @description Hard vehicle allow/exclude. A request may use at most 256 distinct
2651
+ * permitted-vehicle sets (after resolving `allowed`/`excluded`) across
2652
+ * all jobs and shipments (HTTP 400 `limit_exceeded` beyond that).
2653
+ */
2654
+ eligible_vehicles?: null | components["schemas"]["VehicleEligibility"];
2655
+ /**
2656
+ * @description Shipment id: 1 to 128 characters, unique across `jobs` + `shipments`.
2657
+ * @example ship-1
2658
+ */
2659
+ id: string;
2660
+ /**
2661
+ * @description Load carried from the pickup to the delivery: picked up at one leg and
2662
+ * the same quantity dropped off at the other. Non-negative magnitudes
2663
+ * per named dimension.
2664
+ */
2665
+ load?: null | components["schemas"]["Quantities"];
2666
+ /** @description Pickup leg (load on). */
2667
+ pickup: components["schemas"]["ShipmentStop"];
2668
+ /**
2669
+ * @description Soft vehicle affinity preferences, priced. Each entry is independent:
2670
+ * a job listing several preferred vehicles it doesn't get pays each
2671
+ * one's `violation_cost` (compounding, the same rule as a vehicle's
2672
+ * `preferred_tags`).
2673
+ */
2674
+ preferences?: components["schemas"]["VehiclePreference"][] | null;
2675
+ /**
2676
+ * Format: int32
2677
+ * @description Importance of a must-serve task when not all of them fit: the solver
2678
+ * maximises the summed `priority` of served tasks before any cost. `>= 1`,
2679
+ * default `1` (maximise the count). A rank, not money — it never makes a
2680
+ * task droppable; use `drop_cost` for that. Both set is a 400.
2681
+ * @example 3
2682
+ */
2683
+ priority?: number | null;
2684
+ /**
2685
+ * @description Hard skill requirements — the assigned vehicle must provide every one,
2686
+ * at or above each requirement's `min_level`. A request may use at most
2687
+ * 256 distinct `(name, min_level)` pairs across all jobs and shipments
2688
+ * (HTTP 400 `limit_exceeded` beyond that).
2689
+ */
2690
+ required_skills?: components["schemas"]["SkillRequirement"][] | null;
2691
+ /**
2692
+ * @description Per-vehicle work-rate factors for this task's `service_duration_s`,
2693
+ * which is DIVIDED by the factor (above `1` = faster). Each multiplies
2694
+ * the serving vehicle's rate (the shift's `service_factor` if set, else
2695
+ * the vehicle's): effective service time = `service_duration_s /
2696
+ * (shift_or_vehicle_factor * factor)`. On a shipment the factor scales
2697
+ * both legs. A vehicle not listed works at its own rate.
2698
+ */
2699
+ service_factors?: components["schemas"]["ServiceFactor"][] | null;
2700
+ /**
2701
+ * @description Free-form task labels (zones/territories, relation labels).
2702
+ * Used for `tag`/relation resolution and, when a shift scopes itself via
2703
+ * `serves_tags` (hard ANY-overlap) or a vehicle prices them via
2704
+ * `preferred_tags` (soft), for tag matching. ANY-overlap — contrast with
2705
+ * `required_skills`, which requires ALL. Not capability matching on its own.
2706
+ * A request may carry at most 256 distinct tags across all jobs and
2707
+ * shipments (HTTP 400 `limit_exceeded` beyond that); vehicle-side tag
2708
+ * lists do not count.
2709
+ */
2710
+ tags?: string[] | null;
2711
+ /**
2712
+ * @description Soft target for this task, measured at its arrival (default) or
2713
+ * departure. On a shipment it is measured on the **delivery** leg.
2714
+ */
2715
+ target?: null | components["schemas"]["Target"];
2716
+ };
2717
+ /**
2718
+ * @description One leg of a shipment (pickup or delivery).
2719
+ * @example {
2720
+ * "id": "ship-1:pickup",
2721
+ * "location": [
2722
+ * 3.725,
2723
+ * 51.05
2724
+ * ],
2725
+ * "service_duration_s": 300,
2726
+ * "setup_duration_s": 60,
2727
+ * "time_windows": [
2728
+ * {
2729
+ * "from": "2026-07-01T09:00:00+02:00",
2730
+ * "to": "2026-07-01T12:00:00+02:00"
2731
+ * }
2732
+ * ]
2733
+ * }
2734
+ */
2735
+ ShipmentStop: {
2736
+ /**
2737
+ * @description Stop id: 1 to 128 characters when set. Defaults to
2738
+ * `"{shipment}:pickup"` / `"{shipment}:delivery"`. The effective id
2739
+ * (custom or default) must be unique across all job, shipment, and stop
2740
+ * ids — a collision is rejected with HTTP 400.
2741
+ * @example ship-1:pickup
2742
+ */
2743
+ id?: string | null;
2744
+ /** @description Where this stop happens. */
2745
+ location: components["schemas"]["Place"];
2746
+ /**
2747
+ * Format: int32
2748
+ * @description On-site service time paid per job (seconds).
2749
+ *
2750
+ * This is the nominal figure. The serving vehicle's `service_factor`
2751
+ * scales it — the time actually scheduled is
2752
+ * `service_duration_s / service_factor` — so the solution's
2753
+ * `stops[].service_s` may differ from what you sent here. Default `0`;
2754
+ * a negative value is rejected with HTTP 400.
2755
+ * @example 300
2756
+ */
2757
+ service_duration_s?: number | null;
2758
+ /**
2759
+ * Format: int32
2760
+ * @description Setup time paid once on arrival at a new location (seconds),
2761
+ * distinct from `service_duration_s`. Skipped when the immediate real
2762
+ * predecessor in the route already sits at this location — co-located
2763
+ * stops share one setup.
2764
+ *
2765
+ * Not scaled by the vehicle's `service_factor`: setup is fixed arrival
2766
+ * overhead (parking, walking to the door), not the work itself.
2767
+ * Default `0`; a negative value is rejected with HTTP 400.
2768
+ * @example 60
2769
+ */
2770
+ setup_duration_s?: number | null;
2771
+ /** @description Time windows for this stop. */
2772
+ time_windows?: components["schemas"]["TimeWindow"][] | null;
2773
+ };
2774
+ /**
2775
+ * @description A hard skill requirement — the assigned vehicle must provide it.
2776
+ * @example {
2777
+ * "name": "fridge"
2778
+ * }
2779
+ */
2780
+ SkillRequirement: {
2781
+ /**
2782
+ * Format: int32
2783
+ * @description Minimum level the serving vehicle must hold for this skill (`>= 1`).
2784
+ * Absent = 1. A vehicle skill with no `level` holds level 1.
2785
+ * @example 2
2786
+ */
2787
+ min_level?: number | null;
2788
+ /**
2789
+ * @description Skill name the assigned vehicle must provide.
2790
+ * @example fridge
2791
+ */
2792
+ name: string;
2793
+ };
2794
+ /**
2795
+ * @description The result of `POST /v3/routing/solve` and `POST /v3/routing/evaluate`:
2796
+ * one shape for a plan the solver built and a plan it was given to score.
2797
+ * @example {
2798
+ * "plan": {
2799
+ * "routes": [
2800
+ * {
2801
+ * "shift": "mon",
2802
+ * "stops": [
2803
+ * {
2804
+ * "id": "job-1",
2805
+ * "type": "job"
2806
+ * },
2807
+ * {
2808
+ * "id": "job-2",
2809
+ * "type": "job"
2810
+ * }
2811
+ * ],
2812
+ * "vehicle": "v1"
2813
+ * }
2814
+ * ]
2815
+ * },
2816
+ * "routes": [
2817
+ * {
2818
+ * "distance_m": 8450,
2819
+ * "load_peak": {
2820
+ * "weight": 55
2821
+ * },
2822
+ * "shift": "mon",
2823
+ * "stops": [
2824
+ * {
2825
+ * "arrival": "2026-07-01T08:00:00+02:00",
2826
+ * "departure": "2026-07-01T08:00:00+02:00",
2827
+ * "depot": "gent",
2828
+ * "load_after": {
2829
+ * "weight": 0
2830
+ * },
2831
+ * "location": [
2832
+ * 3.7174,
2833
+ * 51.0543
2834
+ * ],
2835
+ * "service_s": 0,
2836
+ * "type": "start"
2837
+ * },
2838
+ * {
2839
+ * "arrival": "2026-07-01T08:10:00+02:00",
2840
+ * "departure": "2026-07-01T09:05:00+02:00",
2841
+ * "distance_m": 2600,
2842
+ * "id": "job-1",
2843
+ * "lateness_s": 0,
2844
+ * "load_after": {
2845
+ * "weight": 20
2846
+ * },
2847
+ * "location": [
2848
+ * 3.725,
2849
+ * 51.05
2850
+ * ],
2851
+ * "service_s": 300,
2852
+ * "service_start": "2026-07-01T09:00:00+02:00",
2853
+ * "travel_s": 600,
2854
+ * "type": "job",
2855
+ * "wait_s": 3000
2856
+ * },
2857
+ * {
2858
+ * "arrival": "2026-07-01T09:13:00+02:00",
2859
+ * "departure": "2026-07-01T09:23:00+02:00",
2860
+ * "distance_m": 2350,
2861
+ * "id": "job-2",
2862
+ * "lateness_s": 0,
2863
+ * "load_after": {
2864
+ * "weight": 55
2865
+ * },
2866
+ * "location": [
2867
+ * 3.71,
2868
+ * 51.06
2869
+ * ],
2870
+ * "service_s": 600,
2871
+ * "service_start": "2026-07-01T09:13:00+02:00",
2872
+ * "travel_s": 480,
2873
+ * "type": "job",
2874
+ * "wait_s": 0
2875
+ * },
2876
+ * {
2877
+ * "arrival": "2026-07-01T09:38:00+02:00",
2878
+ * "departure": "2026-07-01T09:38:00+02:00",
2879
+ * "depot": "gent",
2880
+ * "distance_m": 3500,
2881
+ * "load_after": {
2882
+ * "weight": 55
2883
+ * },
2884
+ * "location": [
2885
+ * 3.7174,
2886
+ * 51.0543
2887
+ * ],
2888
+ * "service_s": 0,
2889
+ * "travel_s": 900,
2890
+ * "type": "end",
2891
+ * "wait_s": 0
2892
+ * }
2893
+ * ],
2894
+ * "time": {
2895
+ * "break_s": 0,
2896
+ * "depot_s": 0,
2897
+ * "overtime_s": 0,
2898
+ * "service_s": 900,
2899
+ * "span_s": 5880,
2900
+ * "travel_s": 1980,
2901
+ * "wait_s": 3000
2902
+ * },
2903
+ * "vehicle": "v1"
2904
+ * }
2905
+ * ],
2906
+ * "summary": {
2907
+ * "distance_m": 8450,
2908
+ * "score": {
2909
+ * "components": {
2910
+ * "assignment": 0,
2911
+ * "delay": 0,
2912
+ * "distance": 1.69,
2913
+ * "drop_costs": 0,
2914
+ * "grouping": 0,
2915
+ * "lateness": 0,
2916
+ * "overtime": 0,
2917
+ * "preferences": 0,
2918
+ * "reloads": 0,
2919
+ * "routes": 0,
2920
+ * "tag_preference": 0,
2921
+ * "target": 0,
2922
+ * "time": 57.1536,
2923
+ * "vehicles": 0,
2924
+ * "waiting": 0,
2925
+ * "window_choice": 0,
2926
+ * "workload_share": 0
2927
+ * },
2928
+ * "cost": 58.8436,
2929
+ * "currency": "EUR",
2930
+ * "unassigned_priority": 0,
2931
+ * "violation_count": 0
2932
+ * },
2933
+ * "search": {
2934
+ * "iterations": 48210,
2935
+ * "termination": "time_limit"
2936
+ * },
2937
+ * "shifts_used": 1,
2938
+ * "tasks": {
2939
+ * "served": 2,
2940
+ * "unassigned": 0,
2941
+ * "unassigned_required": 0
2942
+ * },
2943
+ * "time": {
2944
+ * "break_s": 0,
2945
+ * "depot_s": 0,
2946
+ * "overtime_s": 0,
2947
+ * "service_s": 900,
2948
+ * "span_s": 5880,
2949
+ * "travel_s": 1980,
2950
+ * "wait_s": 3000
2951
+ * },
2952
+ * "timings": {
2953
+ * "search_ms": 100,
2954
+ * "total_ms": 142
2955
+ * },
2956
+ * "vehicles_used": 1
2957
+ * },
2958
+ * "unassigned": [],
2959
+ * "warnings": []
2960
+ * }
2961
+ */
2962
+ SolveResponse: {
2963
+ /**
2964
+ * @description The plan these routes follow, in the request's vocabulary: valid input
2965
+ * to evaluate, suggest or a warm-started solve as it stands.
2966
+ */
2967
+ plan: components["schemas"]["Plan"];
2968
+ /** @description One entry per non-empty route. */
2969
+ routes: components["schemas"]["Route"][];
2970
+ /**
2971
+ * @description How the best plan improved during the search, oldest first: the
2972
+ * starting plan, every improvement (thinned to at most 500 entries), and
2973
+ * the final plan, which equals `summary.score` (it can equal, or after
2974
+ * the final repair be slightly worse than, the entry before it). Present on
2975
+ * every solve; absent on evaluate, which does not search. A large solve
2976
+ * the solver splits into clusters has the final entry alone.
2977
+ */
2978
+ search_progress?: components["schemas"]["SearchProgressPoint"][] | null;
2979
+ /** @description Aggregate statistics for the solve run. */
2980
+ summary: components["schemas"]["Summary"];
2981
+ /** @description Tasks that could not be feasibly assigned. */
2982
+ unassigned: components["schemas"]["UnassignedTask"][];
2983
+ /**
2984
+ * @description Inputs the request carried that changed nothing. Always present,
2985
+ * empty when there are none (no input produces one today); at most 100
2986
+ * are returned. Each item has a `code`, a `pointer` to the field and a
2987
+ * `message`. Accept codes you do not know.
2988
+ */
2989
+ warnings: components["schemas"]["RequestIssue"][];
2990
+ };
2991
+ /**
2992
+ * @description The kind of a stop in a route.
2993
+ *
2994
+ * Every route has one `start` and one `end`. A served job is `job`, and a
2995
+ * shipment's legs are `pickup` and `delivery`. A driver break is `break`,
2996
+ * and a mid-shift reload at a depot is `reload`.
2997
+ *
2998
+ * 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.
2999
+ * @example job
3000
+ */
3001
+ StopType: string;
3002
+ /**
3003
+ * @description The plan in numbers: its score, what it serves and what it takes.
3004
+ * @example {
3005
+ * "distance_m": 8450,
3006
+ * "score": {
3007
+ * "components": {
3008
+ * "assignment": 0,
3009
+ * "delay": 0,
3010
+ * "distance": 1.69,
3011
+ * "drop_costs": 0,
3012
+ * "grouping": 0,
3013
+ * "lateness": 0,
3014
+ * "overtime": 0,
3015
+ * "preferences": 0,
3016
+ * "reloads": 0,
3017
+ * "routes": 0,
3018
+ * "tag_preference": 0,
3019
+ * "target": 0,
3020
+ * "time": 57.1536,
3021
+ * "vehicles": 0,
3022
+ * "waiting": 0,
3023
+ * "window_choice": 0,
3024
+ * "workload_share": 0
3025
+ * },
3026
+ * "cost": 58.8436,
3027
+ * "currency": "EUR",
3028
+ * "unassigned_priority": 0,
3029
+ * "violation_count": 0
3030
+ * },
3031
+ * "search": {
3032
+ * "iterations": 48210,
3033
+ * "termination": "time_limit"
3034
+ * },
3035
+ * "shifts_used": 1,
3036
+ * "tasks": {
3037
+ * "served": 2,
3038
+ * "unassigned": 0,
3039
+ * "unassigned_required": 0
3040
+ * },
3041
+ * "time": {
3042
+ * "break_s": 0,
3043
+ * "depot_s": 0,
3044
+ * "overtime_s": 0,
3045
+ * "service_s": 900,
3046
+ * "span_s": 5880,
3047
+ * "travel_s": 1980,
3048
+ * "wait_s": 3000
3049
+ * },
3050
+ * "timings": {
3051
+ * "search_ms": 100,
3052
+ * "total_ms": 142
3053
+ * },
3054
+ * "vehicles_used": 1
3055
+ * }
3056
+ */
3057
+ Summary: {
3058
+ /**
3059
+ * Format: int64
3060
+ * @description Sum of all route distances, in metres.
3061
+ * @example 8450
3062
+ */
3063
+ distance_m: number;
3064
+ /**
3065
+ * @description How good the plan is. On `/solve`, `score.violation_count` is always 0; on
3066
+ * `/evaluate` it counts the constraints the given plan breaks.
3067
+ */
3068
+ score: components["schemas"]["Score"];
3069
+ /** @description How the search ended. */
3070
+ search: components["schemas"]["SearchInfo"];
3071
+ /**
3072
+ * Format: int32
3073
+ * @description Routes with at least one task stop: one per used shift.
3074
+ * @example 1
3075
+ */
3076
+ shifts_used: number;
3077
+ /** @description Tasks served and left out. */
3078
+ tasks: components["schemas"]["TaskCounts"];
3079
+ /** @description Where the fleet's time goes, summed over routes. */
3080
+ time: components["schemas"]["TimeTotals"];
3081
+ /** @description Where the request's time went. */
3082
+ timings: components["schemas"]["Timings"];
3083
+ /**
3084
+ * @description `true` when travel times could not be fetched and the plan was costed
3085
+ * on estimated travel: straight-line distance × a detour factor, at a
3086
+ * typical speed for the profile. No one-way streets or traffic, so it
3087
+ * can be tens of percent off: the plan, `unassigned[].reasons` and
3088
+ * `score.violation_count` hold only against it, and no `routes[].polyline`
3089
+ * is returned. Solve again once Maps is back if the plan must hold on the
3090
+ * road; on a solve, `options.travel_fallback: "fail"` returns the error
3091
+ * instead. Absent when travel is road-routed.
3092
+ */
3093
+ travel_estimated?: boolean;
3094
+ /**
3095
+ * Format: int32
3096
+ * @description Distinct vehicles with at least one route.
3097
+ * @example 1
3098
+ */
3099
+ vehicles_used: number;
3100
+ };
3101
+ /**
3102
+ * @description A soft tag preference, priced.
3103
+ * @example {
3104
+ * "tag": "north",
3105
+ * "violation_cost": 25
3106
+ * }
3107
+ */
3108
+ TagPreference: {
3109
+ /**
3110
+ * @description Preferred tag.
3111
+ * @example north
3112
+ */
3113
+ tag: string;
3114
+ /**
3115
+ * Format: double
3116
+ * @description Cost, in the objective's currency, incurred when a task without this
3117
+ * tag is served. Must be finite and `>= 0`.
3118
+ * @example 25
3119
+ */
3120
+ violation_cost: number;
3121
+ };
3122
+ /**
3123
+ * @description Soft target: reaching the task's `on` instant after `at` is allowed but
3124
+ * priced. Distinct from a hard time window — a target is a point, never
3125
+ * causes infeasibility, and (unlike a window's `from`) never forces the
3126
+ * vehicle to wait when it is early.
3127
+ * @example {
3128
+ * "at": "2026-07-01T10:00:00+02:00",
3129
+ * "on": "arrival",
3130
+ * "per_late_hour": 60
3131
+ * }
3132
+ */
3133
+ Target: {
3134
+ /**
3135
+ * Format: date-time
3136
+ * @description Target instant (RFC 3339, UTC offset required) the `on` instant is measured against.
3137
+ * @example 2026-07-01T10:00:00+02:00
3138
+ */
3139
+ at: string;
3140
+ /**
3141
+ * @description Which instant of the task is compared to `at`: `arrival` (default) or
3142
+ * `departure`, the stop fields of the same names.
3143
+ * @default arrival
3144
+ */
3145
+ on?: null | components["schemas"]["TargetInstant"];
3146
+ /**
3147
+ * Format: double
3148
+ * @description Cost, in the objective's currency, per hour of `on` beyond `at`
3149
+ * (linear, prorated per second). Must be `> 0`; independent of
3150
+ * `objective.per_late_hour` (which prices *time-window* lateness,
3151
+ * not a target point).
3152
+ * @example 60
3153
+ */
3154
+ per_late_hour: number;
3155
+ };
3156
+ /**
3157
+ * @description Which instant of a task a `target` is measured at, named after the
3158
+ * response stop field that reports it.
3159
+ * @enum {string}
3160
+ */
3161
+ TargetInstant: "arrival" | "departure";
3162
+ /**
3163
+ * @description How many tasks the plan serves. A job is one task; a shipment (pickup
3164
+ * plus delivery) is one task.
3165
+ * @example {
3166
+ * "served": 2,
3167
+ * "unassigned": 0,
3168
+ * "unassigned_required": 0
3169
+ * }
3170
+ */
3171
+ TaskCounts: {
3172
+ /**
3173
+ * Format: int32
3174
+ * @description Tasks on a route.
3175
+ */
3176
+ served: number;
3177
+ /**
3178
+ * Format: int32
3179
+ * @description Tasks on no route: the length of `unassigned`.
3180
+ */
3181
+ unassigned: number;
3182
+ /**
3183
+ * Format: int32
3184
+ * @description The unassigned tasks that carry no `drop_cost`: tasks the plan was
3185
+ * required to serve and did not.
3186
+ */
3187
+ unassigned_required: number;
3188
+ };
3189
+ /**
3190
+ * @description One end of a `time_lag` relation.
3191
+ * @example {
3192
+ * "on": "departure",
3193
+ * "stop": "job-1"
3194
+ * }
3195
+ */
3196
+ TimeLagMember: {
3197
+ /**
3198
+ * @description Which instant of the job the bound is measured at: `service_start`
3199
+ * (default) or `departure`, the stop fields of the same names.
3200
+ * @default service_start
3201
+ */
3202
+ on?: null | components["schemas"]["RelationInstant"];
3203
+ /**
3204
+ * @description The stop: a job id. A shipment's own id or a shipment-leg stop id is
3205
+ * rejected with HTTP 400.
3206
+ * @example job-1
3207
+ */
3208
+ stop: string;
3209
+ };
3210
+ /**
3211
+ * @description Where a route's time goes, in seconds. On the summary: the sum over
3212
+ * routes.
3213
+ *
3214
+ * `span_s` is the wall-clock span, from the start stop's `arrival` to the
3215
+ * end stop's `departure`; it is what `per_route_hour` is charged on. The
3216
+ * other fields break it down and sum to `span_s`, with two exceptions:
3217
+ * setup time (`setup_duration_s`) is inside the span with no field of its
3218
+ * own, and a `fixed` break that begins while the vehicle is driving
3219
+ * overlaps that drive: the overlap is in both `travel_s` and `break_s`, so
3220
+ * on such a route the parts can exceed `span_s`.
3221
+ * @example {
3222
+ * "break_s": 0,
3223
+ * "depot_s": 0,
3224
+ * "overtime_s": 0,
3225
+ * "service_s": 900,
3226
+ * "span_s": 5880,
3227
+ * "travel_s": 1980,
3228
+ * "wait_s": 3000
3229
+ * }
3230
+ */
3231
+ TimeTotals: {
3232
+ /**
3233
+ * Format: int64
3234
+ * @description Time on driver breaks: the `break` stops plus the breaks that paused
3235
+ * a job's service (the job stops' `break_s`).
3236
+ */
3237
+ break_s: number;
3238
+ /**
3239
+ * Format: int64
3240
+ * @description Handling time at start, end and reload stops.
3241
+ */
3242
+ depot_s: number;
3243
+ /**
3244
+ * Format: int64
3245
+ * @description The part of the span after the shift's `to` (possible only with
3246
+ * `max_overtime_s`).
3247
+ */
3248
+ overtime_s: number;
3249
+ /**
3250
+ * Format: int64
3251
+ * @description On-site service time at job, pickup and delivery stops.
3252
+ */
3253
+ service_s: number;
3254
+ /**
3255
+ * Format: int64
3256
+ * @description Wall-clock span: travel, service, setup, depot handling, waiting and
3257
+ * breaks.
3258
+ */
3259
+ span_s: number;
3260
+ /**
3261
+ * Format: int64
3262
+ * @description Driving time: the sum of the stops' `travel_s`.
3263
+ */
3264
+ travel_s: number;
3265
+ /**
3266
+ * Format: int64
3267
+ * @description Waiting before service, cross-route holds included, plus the idle
3268
+ * before a windowed break's window opens, at any stop. It is the sum of
3269
+ * the stops' `wait_s`, so it can exceed `score.components.waiting` and
3270
+ * what `per_wait_hour` charges for: that idle is priced only through
3271
+ * the span.
3272
+ */
3273
+ wait_s: number;
3274
+ };
3275
+ /**
3276
+ * @description A time window. Hard unless it (or `objective.per_late_hour`, for
3277
+ * every window) prices lateness.
3278
+ * @example {
3279
+ * "choice_cost": 15,
3280
+ * "from": "2026-07-01T09:00:00+02:00",
3281
+ * "to": "2026-07-01T12:00:00+02:00"
3282
+ * }
3283
+ */
3284
+ TimeWindow: {
3285
+ /**
3286
+ * Format: double
3287
+ * @description Optional flat cost, in the objective's currency, added when this
3288
+ * job/stop is served within THIS window rather than a free/cheaper
3289
+ * alternative window on the same task. Absent = 0 (no charge). Every
3290
+ * window in the list remains individually hard — a job must still land
3291
+ * in *some* window — this only grades preference among the hard
3292
+ * alternatives; it does not soften time-window feasibility. Must be
3293
+ * finite and `>= 0`, and requires at least 2 windows on the task. Once
3294
+ * any window on the task carries a *nonzero* cost, that task's windows
3295
+ * must also be pairwise non-overlapping, and windows that only touch
3296
+ * count as overlapping (a task whose costs are all
3297
+ * `0`/absent has its overlapping windows merged).
3298
+ *
3299
+ * **Cannot be combined with `objective.per_late_hour > 0`** — a
3300
+ * nonzero `choice_cost` anywhere in the request alongside priced lateness
3301
+ * is rejected with HTTP 400 (the two read opposite ways about which
3302
+ * window was paid for). Choose one: priced alternative windows, or priced
3303
+ * lateness.
3304
+ */
3305
+ choice_cost?: number | null;
3306
+ /**
3307
+ * Format: date-time
3308
+ * @description Earliest allowed start of service (RFC 3339 instant, UTC offset
3309
+ * required). A vehicle that arrives earlier waits.
3310
+ * @example 2026-07-01T09:00:00+02:00
3311
+ */
3312
+ from: string;
3313
+ /**
3314
+ * Format: double
3315
+ * @description Makes this window soft on its late side: arriving after `to` is
3316
+ * allowed and priced at this rate, in the objective's currency per hour
3317
+ * late, in place of `objective.per_late_hour` (and whether or not
3318
+ * that is set, so hard and soft windows can share one request). Must be
3319
+ * `> 0`; omit it for a hard window. Only on a
3320
+ * task with exactly one window. Arriving early still waits for `from`.
3321
+ * @example 60
3322
+ */
3323
+ per_late_hour?: number | null;
3324
+ /**
3325
+ * Format: date-time
3326
+ * @description Latest allowed start of service (RFC 3339 instant, UTC offset
3327
+ * required), measured from arrival plus any windowed break taken first
3328
+ * (#1750 D1). Hard unless `per_late_hour` prices lateness.
3329
+ * @example 2026-07-01T12:00:00+02:00
3330
+ */
3331
+ to: string;
3332
+ };
3333
+ /**
3334
+ * @description Where the request's wall-clock time went, in milliseconds.
3335
+ * @example {
3336
+ * "search_ms": 100,
3337
+ * "total_ms": 142
3338
+ * }
3339
+ */
3340
+ Timings: {
3341
+ /**
3342
+ * Format: int64
3343
+ * @description Time spent in the search. Absent on `/evaluate`, which runs none, and
3344
+ * on `/suggest`, which has no separate search figure.
3345
+ */
3346
+ search_ms?: number | null;
3347
+ /**
3348
+ * Format: int64
3349
+ * @description From the request's arrival to the end of the search (of the scoring,
3350
+ * on `/evaluate`; of the suggestion search, on `/suggest`): fetching
3351
+ * travel times and waiting for capacity included, building the response
3352
+ * not.
3353
+ */
3354
+ total_ms: number;
3355
+ };
3356
+ /**
3357
+ * @description Where travel times and distances come from.
3358
+ *
3359
+ * Matrices are traffic-aware (historical-typical traffic); by default travel
3360
+ * times reflect traffic at the moment the request is processed. Set
3361
+ * `departure_time` to plan against another instant — e.g. tomorrow's 08:00
3362
+ * routes with morning-rush travel times, or a replay of a past run under its
3363
+ * original conditions.
3364
+ * @example {
3365
+ * "departure_time": "2026-07-01T08:00:00+02:00",
3366
+ * "engine": "tomtom"
3367
+ * }
3368
+ */
3369
+ Travel: {
3370
+ /**
3371
+ * Format: date-time
3372
+ * @description Departure time for the traffic lookup (RFC 3339 instant, any offset).
3373
+ * Omitted → traffic at solve time. An explicit departure time bypasses
3374
+ * the server-side matrix cache.
3375
+ * @example 2026-07-01T08:00:00+02:00
3376
+ */
3377
+ departure_time?: string | null;
3378
+ /**
3379
+ * @description Road-network data behind travel times and distances. Omitted →
3380
+ * `tomtom`.
3381
+ */
3382
+ engine?: null | components["schemas"]["MatrixEngine"];
3383
+ };
3384
+ /**
3385
+ * @description `options.travel_fallback`: what a solve does when travel times cannot be
3386
+ * fetched. `/evaluate` and `/suggest` always estimate.
3387
+ * @example estimate
3388
+ * @enum {string}
3389
+ */
3390
+ TravelFallback: "estimate" | "fail";
3391
+ /**
3392
+ * @description What a break trigger accumulates since the last break: `drive` counts
3393
+ * driving time only; `duty` counts travel, service and setup time, but not
3394
+ * waiting (for a time window to open or for a coupled task).
3395
+ * @example drive
3396
+ * @enum {string}
3397
+ */
3398
+ TriggerAfter: "drive" | "duty";
3399
+ /**
3400
+ * @description Which kind of "unassigned" a task is.
3401
+ *
3402
+ * 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.
3403
+ * @example priced_out
3404
+ */
3405
+ UnassignedCategory: string;
3406
+ /**
3407
+ * @description A machine-readable reason a task could not be assigned: the
3408
+ * `constraint` to blame, when one is, and a sentence.
3409
+ * @example {
3410
+ * "constraint": "time_window",
3411
+ * "message": "A route cannot reach this task within its time window"
3412
+ * }
3413
+ */
3414
+ UnassignedReason: {
3415
+ /**
3416
+ * @description The constraint that refused the task on at least one vehicle (or
3417
+ * `all_or_none`, for a task its group holds back), in the vocabulary of
3418
+ * the evaluate violations' `code`. A task lists one reason
3419
+ * per constraint, once each, in [`ConstraintCode`] order. Absent on the
3420
+ * single reason of a `time_limit` or `priced_out` task, which names no
3421
+ * constraint.
3422
+ */
3423
+ constraint?: null | components["schemas"]["ConstraintCode"];
3424
+ /**
3425
+ * @description Human-readable explanation.
3426
+ * @example A route cannot reach this task within its time window
3427
+ */
3428
+ message: string;
3429
+ };
3430
+ /**
3431
+ * @description A task the plan leaves unassigned.
3432
+ * @example {
3433
+ * "category": "blocked",
3434
+ * "reasons": [
3435
+ * {
3436
+ * "constraint": "time_window",
3437
+ * "message": "A route cannot reach this task within its time window"
3438
+ * }
3439
+ * ],
3440
+ * "relaxations": [
3441
+ * {
3442
+ * "amount": 900,
3443
+ * "message": "Extend a time window by 900s (~15 min).",
3444
+ * "op": "extend_time_window",
3445
+ * "pointer": "/problem/jobs/1/time_windows",
3446
+ * "unit": "s"
3447
+ * }
3448
+ * ],
3449
+ * "task": "job-2"
3450
+ * }
3451
+ */
3452
+ UnassignedTask: {
3453
+ /** @description Which kind of "unassigned" this is. */
3454
+ category: components["schemas"]["UnassignedCategory"];
3455
+ /**
3456
+ * @description Never empty. When `category` is `impossible` or `blocked` there is
3457
+ * one reason per constraint that refused the task on at least one
3458
+ * vehicle, named in `constraint`, once each, `unreachable` first
3459
+ * (`unknown` when no constraint was recorded); a task that fits but
3460
+ * whose `all_or_none` group holds it back has the one reason
3461
+ * `all_or_none`. Otherwise there is one reason with no `constraint`.
3462
+ */
3463
+ reasons: components["schemas"]["UnassignedReason"][];
3464
+ /**
3465
+ * @description Best-effort, actionable relaxation suggestions. Empty when no simple
3466
+ * relaxation exists (e.g. a skills mismatch).
3467
+ */
3468
+ relaxations: components["schemas"]["Relaxation"][];
3469
+ /**
3470
+ * @description The unassigned task: a job id or a shipment id.
3471
+ * @example job-2
3472
+ */
3473
+ task: string;
3474
+ };
3475
+ /**
3476
+ * @description A vehicle type available to serve tasks.
3477
+ * @example {
3478
+ * "capacity": {
3479
+ * "volume": 20,
3480
+ * "weight": 500
3481
+ * },
3482
+ * "id": "v1",
3483
+ * "profile": "car",
3484
+ * "shifts": [
3485
+ * {
3486
+ * "end": {
3487
+ * "location": [
3488
+ * 3.7174,
3489
+ * 51.0543
3490
+ * ]
3491
+ * },
3492
+ * "from": "2026-07-01T08:00:00+02:00",
3493
+ * "id": "mon",
3494
+ * "start": {
3495
+ * "location": [
3496
+ * 3.7174,
3497
+ * 51.0543
3498
+ * ]
3499
+ * },
3500
+ * "to": "2026-07-01T17:00:00+02:00"
3501
+ * }
3502
+ * ],
3503
+ * "skills": [
3504
+ * {
3505
+ * "name": "fridge"
3506
+ * }
3507
+ * ]
3508
+ * }
3509
+ */
3510
+ Vehicle: {
3511
+ /** @description Named capacity dimensions. */
3512
+ capacity?: null | components["schemas"]["Quantities"];
3513
+ /**
3514
+ * @description Vehicles this one may serve a `compatible_vehicles` relation's tasks
3515
+ * together with, by id. Absent: any vehicle. A list is a veto, so a
3516
+ * one-sided list still binds both vehicles: two vehicles may share a
3517
+ * relation only if neither's list excludes the other. A vehicle always
3518
+ * pairs with itself and all its shifts count as one vehicle; to pair a
3519
+ * vehicle with no other, list only its own id. An empty list is rejected
3520
+ * with HTTP 400 (it would read as "everyone" in a client that drops empty
3521
+ * arrays), and so is an id that names no vehicle. Inert unless a
3522
+ * `compatible_vehicles` relation names tasks.
3523
+ * @example [
3524
+ * "v2",
3525
+ * "v3"
3526
+ * ]
3527
+ */
3528
+ compatible_with?: string[] | null;
3529
+ /**
3530
+ * @description This vehicle's costs. Each field set here replaces the same field of
3531
+ * `objective.costs` for this vehicle; fields not set keep the fleet
3532
+ * value. A shift's own `costs` replace these per field in turn.
3533
+ */
3534
+ costs?: null | components["schemas"]["Costs"];
3535
+ /**
3536
+ * @description Vehicle id: 1 to 128 characters, unique across `vehicles[]`; echoed as
3537
+ * `routes[].vehicle`.
3538
+ * @example v1
3539
+ */
3540
+ id: string;
3541
+ /** @description Hard operating limits. */
3542
+ limits?: null | components["schemas"]["VehicleLimits"];
3543
+ /**
3544
+ * @description Soft tag preferences. Serving a task that does not
3545
+ * carry a preferred tag incurs that entry's `violation_cost`. Entries
3546
+ * apply independently: a task lacking several preferred tags incurs each
3547
+ * cost.
3548
+ */
3549
+ preferred_tags?: components["schemas"]["TagPreference"][] | null;
3550
+ /**
3551
+ * @description Routing profile: `car` (default), `truck` or `bike` — selects the road
3552
+ * network and speeds behind this vehicle's travel times and distances.
3553
+ * Any other value is rejected with HTTP 400.
3554
+ */
3555
+ profile?: null | components["schemas"]["Profile"];
3556
+ /**
3557
+ * Format: double
3558
+ * @description Work-rate multiplier for service time at stops (1.0 = base rate).
3559
+ *
3560
+ * Same direction as `speed_factor`: effective service time =
3561
+ * `service_duration_s / service_factor`, so values > 1.0 model a driver who
3562
+ * works FASTER and spends less time at each stop, and < 1.0 one who is
3563
+ * slower. Use it for crew size, equipment, or experience — how quickly the
3564
+ * work gets done, as distinct from how fast the vehicle drives.
3565
+ *
3566
+ * Applies to job/stop `service_duration_s` only. Deliberately NOT applied
3567
+ * to `setup_duration_s` (fixed arrival overhead such as parking),
3568
+ * depot handling (`depots[].service_duration_s`,
3569
+ * `start`/`end.service_duration_s`), waiting time, or break durations.
3570
+ *
3571
+ * Must be in `[0.001, 5]`. Default 1.0. A shift's own `service_factor`
3572
+ * replaces it for that shift; a task's `service_factors[].factor` for
3573
+ * this vehicle multiplies whichever applies: effective service time =
3574
+ * `service_duration_s / (shift_or_vehicle_factor * task_factor)`.
3575
+ *
3576
+ * V2's `durationModifier` went the other way (it MULTIPLIED duration,
3577
+ * `0.8` = 20% faster); the V2 compatibility layer inverts it and sends it
3578
+ * as the task's `service_factors[].factor = 1 / durationModifier`.
3579
+ * @default 1
3580
+ */
3581
+ service_factor?: number | null;
3582
+ /**
3583
+ * @description One or more working shifts. A vehicle without shifts is rejected with
3584
+ * HTTP 400.
3585
+ */
3586
+ shifts: components["schemas"]["Shift"][];
3587
+ /**
3588
+ * @description Capabilities the vehicle provides. A job's `required_skills` must all appear
3589
+ * here at a level of at least the job's `min_level`. Each entry is an
3590
+ * object `{ "name": ..., "level": N }` (`level` optional, default 1);
3591
+ * a bare string is rejected. A skill may appear once per list. Omitting
3592
+ * the field is the same as `[]`: the vehicle can only serve jobs that
3593
+ * require no skills.
3594
+ */
3595
+ skills?: components["schemas"]["VehicleSkill"][] | null;
3596
+ /**
3597
+ * Format: double
3598
+ * @description Travel-speed multiplier (1.0 = base speed). Effective travel time =
3599
+ * `base travel time / speed_factor`, so values > 1.0 model a faster
3600
+ * vehicle and < 1.0 a slower one. Must be in `[0.001, 5]`. Default 1.0.
3601
+ *
3602
+ * Covers driving only. Its companion `service_factor` scales the
3603
+ * work done at stops; the two are independent and share this direction and
3604
+ * range.
3605
+ * @default 1
3606
+ */
3607
+ speed_factor?: number | null;
3608
+ /**
3609
+ * Format: double
3610
+ * @description Share of the work this vehicle carries under `objective.workload_share`,
3611
+ * relative to the other vehicles. Default `1`; `0.5` carries half as much;
3612
+ * `0` leaves the vehicle out of the balancing. `0` to `1000000`
3613
+ * (HTTP 400 `out_of_range` outside that). Ignored when
3614
+ * `objective.workload_share` is not set.
3615
+ * @example 0.5
3616
+ */
3617
+ workload_weight?: number | null;
3618
+ };
3619
+ /**
3620
+ * @description Hard vehicle eligibility: whitelist or blacklist (mutually exclusive).
3621
+ * @example {
3622
+ * "allowed": [
3623
+ * "v1",
3624
+ * "v2"
3625
+ * ]
3626
+ * }
3627
+ */
3628
+ VehicleEligibility: {
3629
+ /**
3630
+ * @description Hard whitelist of vehicle ids. Omit = all vehicles allowed. An empty
3631
+ * list, or an id that names no vehicle, is rejected with HTTP 400.
3632
+ */
3633
+ allowed?: string[] | null;
3634
+ /**
3635
+ * @description Hard blacklist of vehicle ids. Mutually exclusive with `allowed`. An
3636
+ * id that names no vehicle is rejected with HTTP 400.
3637
+ */
3638
+ excluded?: string[] | null;
3639
+ };
3640
+ /**
3641
+ * @description Vehicle distance/time limits.
3642
+ * @example {
3643
+ * "max_distance_m": 200000,
3644
+ * "max_route_duration_s": 32400
3645
+ * }
3646
+ */
3647
+ VehicleLimits: {
3648
+ /**
3649
+ * Format: int64
3650
+ * @description Hard maximum distance in metres. `0` to `2147483647`; a value
3651
+ * outside that range is rejected with HTTP 400 `out_of_range`.
3652
+ * @example 200000
3653
+ */
3654
+ max_distance_m?: number | null;
3655
+ /**
3656
+ * Format: int64
3657
+ * @description Hard cap in seconds on any single travel leg of this vehicle's routes:
3658
+ * the `travel_s` reported on each stop, start-to-first-task and
3659
+ * last-task-to-`end` included. Travel only: setup, service and wait do
3660
+ * not count, and `speed_factor` applies first. A leg made free by
3661
+ * `free_start_travel`/`free_end_travel`, or absent on an open start or
3662
+ * end, is exempt. Absent = no cap. Must be > 0: `0` would make every
3663
+ * leg too long rather than mean "no cap", so it is rejected with HTTP
3664
+ * 400 `out_of_range`, as is a value that does not fit in 32 bits. A
3665
+ * breach is reported as `max_leg_travel`.
3666
+ * @example 3600
3667
+ */
3668
+ max_leg_travel_s?: number | null;
3669
+ /**
3670
+ * Format: int64
3671
+ * @description Hard maximum route duration in seconds: the whole-route span —
3672
+ * travel, service, and wait all count, depot load and unload included.
3673
+ * The same quantity as the response's `routes[].time.span_s`. `0` to
3674
+ * `2147483647`; a value outside that range is rejected with HTTP 400
3675
+ * `out_of_range`.
3676
+ * @example 32400
3677
+ */
3678
+ max_route_duration_s?: number | null;
3679
+ /**
3680
+ * Format: int32
3681
+ * @description Maximum stops served per shift; a job counts as one stop.
3682
+ * Start, end, break and reload stops in `routes[].stops` do not count; a
3683
+ * shipment counts as two stops.
3684
+ * @example 50
3685
+ */
3686
+ max_stops?: number | null;
3687
+ /**
3688
+ * @description Hard caps on this vehicle's totals across all of its shifts in a day,
3689
+ * a week or an explicit window. Each shift counts toward the one
3690
+ * period that contains its `from`, read in that shift's own UTC offset.
3691
+ * A recurring period with none of the vehicle's shifts is skipped; an
3692
+ * explicit window with no shift start is a 400.
3693
+ */
3694
+ periods?: components["schemas"]["PeriodLimit"][];
3695
+ };
3696
+ /**
3697
+ * @description A soft vehicle affinity preference, priced.
3698
+ * @example {
3699
+ * "vehicle": "v1",
3700
+ * "violation_cost": 50
3701
+ * }
3702
+ */
3703
+ VehiclePreference: {
3704
+ /**
3705
+ * @description Preferred vehicle id. An id that names no vehicle, or a vehicle listed
3706
+ * twice in one task's `preferences`, is rejected with HTTP 400.
3707
+ * @example v1
3708
+ */
3709
+ vehicle: string;
3710
+ /**
3711
+ * Format: double
3712
+ * @description Cost, in the objective's currency, incurred when a different vehicle
3713
+ * serves the job. Must be finite and `>= 0`.
3714
+ * @example 50
3715
+ */
3716
+ violation_cost: number;
3717
+ };
3718
+ /**
3719
+ * @description A capability a vehicle or shift provides, at a proficiency level:
3720
+ * `{ "name": "gas", "level": 3 }`. Always an object; a bare string is
3721
+ * rejected at parse.
3722
+ * @example {
3723
+ * "level": 3,
3724
+ * "name": "gas"
3725
+ * }
3726
+ */
3727
+ VehicleSkill: {
3728
+ /**
3729
+ * Format: int32
3730
+ * @description Proficiency level, `>= 1`; absent = 1. Satisfies every job
3731
+ * requirement of this skill whose `min_level` is at most this value.
3732
+ * @example 3
3733
+ */
3734
+ level?: number | null;
3735
+ /**
3736
+ * @description Skill name.
3737
+ * @example gas
3738
+ */
3739
+ name: string;
3740
+ };
3741
+ /**
3742
+ * @description A single constraint violation detected while evaluating an imported solution.
3743
+ *
3744
+ * Reported on stops (`routes[].stops[].violations`) and on routes
3745
+ * (`routes[].violations`) in the `POST /v3/routing/evaluate` response.
3746
+ * @example {
3747
+ * "code": "capacity",
3748
+ * "dimension": "weight",
3749
+ * "excess": 15,
3750
+ * "message": "Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)",
3751
+ * "unit": "load"
3752
+ * }
3753
+ */
3754
+ Violation: {
3755
+ /**
3756
+ * @description The constraint broken. `max_stops`, `break`, `multi_trip`,
3757
+ * `period_limit` and `quota` are route-level; `sequence` and `shipment`
3758
+ * are on the stop; `unreachable`, `max_leg_travel` and `capacity` can be
3759
+ * either. `unknown`
3760
+ * means the insertion check refused a stop without naming a constraint
3761
+ * (not expected in practice).
3762
+ */
3763
+ code: components["schemas"]["ConstraintCode"];
3764
+ /**
3765
+ * @description The capacity dimension over its limit. Only on `capacity`.
3766
+ * @example weight
3767
+ */
3768
+ dimension?: string | null;
3769
+ /**
3770
+ * Format: int64
3771
+ * @description How far over the limit, in `unit`. On `capacity`, `time_window` (the
3772
+ * seconds late), `shift_end`, `max_distance`, `max_route_duration` and
3773
+ * `quota`.
3774
+ * @example 15
3775
+ */
3776
+ excess?: number | null;
3777
+ /**
3778
+ * @description Human-readable description of what was violated.
3779
+ * @example Cumulative load 30 exceeds vehicle capacity 15 (dimension weight)
3780
+ */
3781
+ message: string;
3782
+ /** @description Unit of `excess`; present exactly when `excess` is. */
3783
+ unit?: null | components["schemas"]["QuantityUnit"];
3784
+ };
3785
+ /**
3786
+ * @description Spreads work across vehicles: each vehicle's scheduled service time is
3787
+ * compared with its share of all the work, and the part outside a tolerance
3788
+ * band is charged.
3789
+ *
3790
+ * The balanced quantity is **service time only**: every served task's
3791
+ * `service_duration_s`, scaled by the vehicle's `service_factor`. Travel,
3792
+ * `setup_duration_s`, waiting and breaks are not counted, and a task-level
3793
+ * `service_factors` entry scales the measure but not the target. Shares are
3794
+ * fixed when the request is read: every task counts towards the total,
3795
+ * served or not, so with many unassigned tasks every vehicle sits under its
3796
+ * share and the term pulls work in without ordering the routes between them;
3797
+ * balancing pressure appears once routes enter their band. A vehicle with
3798
+ * several shifts has its share split across them by the work each shift can
3799
+ * reach (the service time of the tasks whose windows overlap it), weighted
3800
+ * by shift length, so a day with no tasks carries none of the share; each
3801
+ * shift is charged on its own part. An empty, non-exempt shift pays for its whole share, so pair the
3802
+ * term with `costs.per_route` or `per_used_vehicle` only when both are meant.
3803
+ * See `vehicles[].workload_weight` to give a part-time vehicle a smaller
3804
+ * share. A problem that sets the term solves without decomposition, like
3805
+ * `assignment_costs`.
3806
+ */
3807
+ WorkloadShare: {
3808
+ /**
3809
+ * Format: double
3810
+ * @description Money per hour a vehicle's service time is outside the band, in the
3811
+ * request's currency. Greater than 0 and at least 0.036 (the internal
3812
+ * resolution); omit `workload_share` to switch the term off.
3813
+ * @example 35
3814
+ */
3815
+ per_imbalance_hour: number;
3816
+ /**
3817
+ * Format: double
3818
+ * @description Half-width of the band as a fraction of the vehicle's share, `0` up to
3819
+ * but not including `1`. Default `0.1`: a vehicle within 10% of its share
3820
+ * is not charged. The charge grows from the band edge.
3821
+ * @example 0.1
3822
+ */
3823
+ tolerance?: number | null;
3824
+ };
3825
+ };
3826
+ responses: never;
3827
+ parameters: never;
3828
+ requestBodies: never;
3829
+ headers: never;
3830
+ pathItems: never;
3831
+ }
3832
+ export type $defs = Record<string, never>;
3833
+ export interface operations {
3834
+ submitRoutingRun: {
3835
+ parameters: {
3836
+ query?: never;
3837
+ header?: never;
3838
+ path?: never;
3839
+ cookie?: never;
3840
+ };
3841
+ requestBody: {
3842
+ content: {
3843
+ "application/json": components["schemas"]["RunRequest"];
3844
+ };
3845
+ };
3846
+ responses: {
3847
+ /** @description Run accepted. It is `queued` until a worker starts it. */
3848
+ 202: {
3849
+ headers: {
3850
+ /** @description The request's `X-Request-Id`, echoed, or a generated `req_…` id. */
3851
+ "x-request-id"?: string;
3852
+ [name: string]: unknown;
3853
+ };
3854
+ content: {
3855
+ /**
3856
+ * @example {
3857
+ * "id": "d28568b1-34cc-4f89-b10b-dc24b26a8275",
3858
+ * "status": "queued",
3859
+ * "links": {
3860
+ * "self": "/v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275",
3861
+ * "result": "/v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275/result"
3862
+ * }
3863
+ * }
3864
+ */
3865
+ "application/json": components["schemas"]["Run"];
3866
+ };
3867
+ };
3868
+ /** @description The request is invalid: the same `ErrorBody` as `POST /v3/routing/solve`. A `callback` field is `not_supported` at `/callback`. */
3869
+ 400: {
3870
+ headers: {
3871
+ [name: string]: unknown;
3872
+ };
3873
+ content: {
3874
+ "application/json": components["schemas"]["ErrorBody"];
3875
+ };
3876
+ };
3877
+ /** @description Missing or invalid API key. Returned by the API gateway, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
3878
+ 401: {
3879
+ headers: {
3880
+ [name: string]: unknown;
3881
+ };
3882
+ content?: never;
3883
+ };
3884
+ /** @description The request uses a feature this account does not have (`code: feature_not_enabled`). */
3885
+ 403: {
3886
+ headers: {
3887
+ [name: string]: unknown;
3888
+ };
3889
+ content: {
3890
+ "application/json": components["schemas"]["ErrorBody"];
3891
+ };
3892
+ };
3893
+ /** @description Request body larger than 10 MiB (`code: payload_too_large`). */
3894
+ 413: {
3895
+ headers: {
3896
+ [name: string]: unknown;
3897
+ };
3898
+ content: {
3899
+ "application/json": components["schemas"]["ErrorBody"];
3900
+ };
3901
+ };
3902
+ /** @description Request `Content-Type` is not `application/json` (`code: unsupported_media_type`). */
3903
+ 415: {
3904
+ headers: {
3905
+ [name: string]: unknown;
3906
+ };
3907
+ content: {
3908
+ "application/json": components["schemas"]["ErrorBody"];
3909
+ };
3910
+ };
3911
+ /** @description Rate limited, or this account already has 10 queued or running runs (a cancelled run still counts until its worker stops). Returned by the API gateway, so it does not use the `ErrorBody` shape. Wait for the `Retry-After` header, then retry. */
3912
+ 429: {
3913
+ headers: {
3914
+ /** @description Seconds to wait before retrying. `30` when the cap of 10 runs is the cause. */
3915
+ "Retry-After"?: number;
3916
+ [name: string]: unknown;
3917
+ };
3918
+ content?: never;
3919
+ };
3920
+ /** @description The solver or the worker platform could not take the run. Nothing was started; submit again. */
3921
+ 503: {
3922
+ headers: {
3923
+ [name: string]: unknown;
3924
+ };
3925
+ content: {
3926
+ /**
3927
+ * @example {
3928
+ * "message": "Failed to launch routing run",
3929
+ * "error": "GATEWAY_ERROR"
3930
+ * }
3931
+ */
3932
+ "application/json": components["schemas"]["GatewayError"];
3933
+ };
3934
+ };
3935
+ };
3936
+ };
3937
+ getRoutingRunStatus: {
3938
+ parameters: {
3939
+ query?: never;
3940
+ header?: never;
3941
+ path: {
3942
+ /** @description The run id returned by `POST /v3/routing/runs`. */
3943
+ id: string;
3944
+ };
3945
+ cookie?: never;
3946
+ };
3947
+ requestBody?: never;
3948
+ responses: {
3949
+ /** @description The run. */
3950
+ 200: {
3951
+ headers: {
3952
+ [name: string]: unknown;
3953
+ };
3954
+ content: {
3955
+ "application/json": components["schemas"]["Run"];
3956
+ };
3957
+ };
3958
+ /** @description `id` is not a UUID. Body: `{"error": "Invalid UUID string: …"}`. */
3959
+ 400: {
3960
+ headers: {
3961
+ [name: string]: unknown;
3962
+ };
3963
+ content: {
3964
+ /**
3965
+ * @example {
3966
+ * "error": "Invalid UUID string: not-a-uuid"
3967
+ * }
3968
+ */
3969
+ "application/json": components["schemas"]["GatewayError"];
3970
+ };
3971
+ };
3972
+ /** @description Missing or invalid API key. Returned by the API gateway, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
3973
+ 401: {
3974
+ headers: {
3975
+ [name: string]: unknown;
3976
+ };
3977
+ content?: never;
3978
+ };
3979
+ /** @description No run with this id on your account. Runs of other accounts are also `404`. */
3980
+ 404: {
3981
+ headers: {
3982
+ [name: string]: unknown;
3983
+ };
3984
+ content: {
3985
+ /**
3986
+ * @example {
3987
+ * "message": "not_found: routing run d28568b1-34cc-4f89-b10b-dc24b26a8275",
3988
+ * "error": "GATEWAY_ERROR"
3989
+ * }
3990
+ */
3991
+ "application/json": components["schemas"]["GatewayError"];
3992
+ };
3993
+ };
3994
+ };
3995
+ };
3996
+ getRoutingRunResult: {
3997
+ parameters: {
3998
+ query?: never;
3999
+ header?: never;
4000
+ path: {
4001
+ /** @description The run id returned by `POST /v3/routing/runs`. */
4002
+ id: string;
4003
+ };
4004
+ cookie?: never;
4005
+ };
4006
+ requestBody?: never;
4007
+ responses: {
4008
+ /** @description The plan. */
4009
+ 200: {
4010
+ headers: {
4011
+ [name: string]: unknown;
4012
+ };
4013
+ content: {
4014
+ "application/json": components["schemas"]["SolveResponse"];
4015
+ };
4016
+ };
4017
+ /** @description `id` is not a UUID. Body: `{"error": "Invalid UUID string: …"}`. */
4018
+ 400: {
4019
+ headers: {
4020
+ [name: string]: unknown;
4021
+ };
4022
+ content: {
4023
+ /**
4024
+ * @example {
4025
+ * "error": "Invalid UUID string: not-a-uuid"
4026
+ * }
4027
+ */
4028
+ "application/json": components["schemas"]["GatewayError"];
4029
+ };
4030
+ };
4031
+ /** @description Missing or invalid API key. Returned by the API gateway, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
4032
+ 401: {
4033
+ headers: {
4034
+ [name: string]: unknown;
4035
+ };
4036
+ content?: never;
4037
+ };
4038
+ /** @description No run with this id on your account. Runs of other accounts are also `404`. */
4039
+ 404: {
4040
+ headers: {
4041
+ [name: string]: unknown;
4042
+ };
4043
+ content: {
4044
+ /**
4045
+ * @example {
4046
+ * "message": "not_found: routing run d28568b1-34cc-4f89-b10b-dc24b26a8275",
4047
+ * "error": "GATEWAY_ERROR"
4048
+ * }
4049
+ */
4050
+ "application/json": components["schemas"]["GatewayError"];
4051
+ };
4052
+ };
4053
+ /** @description The run has no plan to return. `message` starts with `run_not_finished` while the run is `queued` or `running`, and with `no_result` when it `failed` or was `cancelled`. */
4054
+ 409: {
4055
+ headers: {
4056
+ [name: string]: unknown;
4057
+ };
4058
+ content: {
4059
+ /**
4060
+ * @example {
4061
+ * "message": "run_not_finished: run d28568b1-34cc-4f89-b10b-dc24b26a8275 is queued",
4062
+ * "error": "GATEWAY_ERROR"
4063
+ * }
4064
+ */
4065
+ "application/json": components["schemas"]["GatewayError"];
4066
+ };
4067
+ };
4068
+ };
4069
+ };
4070
+ cancelRoutingRun: {
4071
+ parameters: {
4072
+ query?: never;
4073
+ header?: never;
4074
+ path: {
4075
+ /** @description The run id returned by `POST /v3/routing/runs`. */
4076
+ id: string;
4077
+ };
4078
+ cookie?: never;
4079
+ };
4080
+ requestBody?: never;
4081
+ responses: {
4082
+ /** @description The run, `cancelled`, or in its final state when it had already finished. */
4083
+ 200: {
4084
+ headers: {
4085
+ [name: string]: unknown;
4086
+ };
4087
+ content: {
4088
+ /**
4089
+ * @example {
4090
+ * "id": "d28568b1-34cc-4f89-b10b-dc24b26a8275",
4091
+ * "status": "cancelled",
4092
+ * "links": {
4093
+ * "self": "/v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275",
4094
+ * "result": "/v3/routing/runs/d28568b1-34cc-4f89-b10b-dc24b26a8275/result"
4095
+ * },
4096
+ * "finished_at": "2026-10-15T07:41:22Z",
4097
+ * "expires_at": "2027-10-15T07:41:22Z"
4098
+ * }
4099
+ */
4100
+ "application/json": components["schemas"]["Run"];
4101
+ };
4102
+ };
4103
+ /** @description `id` is not a UUID. Body: `{"error": "Invalid UUID string: …"}`. */
4104
+ 400: {
4105
+ headers: {
4106
+ [name: string]: unknown;
4107
+ };
4108
+ content: {
4109
+ /**
4110
+ * @example {
4111
+ * "error": "Invalid UUID string: not-a-uuid"
4112
+ * }
4113
+ */
4114
+ "application/json": components["schemas"]["GatewayError"];
4115
+ };
4116
+ };
4117
+ /** @description Missing or invalid API key. Returned by the API gateway, so it does not use the `ErrorBody` shape and can have an empty body. Branch on the HTTP status. */
4118
+ 401: {
4119
+ headers: {
4120
+ [name: string]: unknown;
4121
+ };
4122
+ content?: never;
4123
+ };
4124
+ /** @description No run with this id on your account. Runs of other accounts are also `404`. */
4125
+ 404: {
4126
+ headers: {
4127
+ [name: string]: unknown;
4128
+ };
4129
+ content: {
4130
+ /**
4131
+ * @example {
4132
+ * "message": "not_found: routing run d28568b1-34cc-4f89-b10b-dc24b26a8275",
4133
+ * "error": "GATEWAY_ERROR"
4134
+ * }
4135
+ */
4136
+ "application/json": components["schemas"]["GatewayError"];
4137
+ };
4138
+ };
4139
+ };
4140
+ };
4141
+ }