@solvice/routing 0.17.2-beta.0 → 0.17.4-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/README.md +32 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +25 -1
- package/dist/runs.d.ts +4141 -0
- package/dist/runs.js +5 -0
- package/dist/v3.d.ts +66 -8
- package/package.json +2 -2
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
|
+
}
|