Priority jobs and optional jobs
The urgency of jobs varies.
Some jobs are high priority while others are low. You can give individual jobs priority levels to specify the importance of assigning one job instead of another job.
When you are planning in pick-up and delivery routing, you can introduce mandatory jobs and optional jobs to help prioritize which jobs should be assigned as soon as possible and which jobs can wait until later.
Mandatory jobs are penalized with a medium-level penalty when they are left unassigned. This means assigning a mandatory job will always take precedence over satisfying soft constraints.
Optional jobs are penalized with a soft-level penalty when they are left unassigned. This means assigning an optional job will compete with all other soft constraints, so an optional job may be left unassigned in favor of satisfying other soft constraints, such as matching job or driver preferences.
This guide explains how to manage resource-limited planning with the following examples:
1. Job priorities
There are ten built-in mandatory priorities.
1 is the highest priority, and 10 is the lowest priority.
The priority also defines if jobs are considered mandatory (default) or optional.
There are also ten built-in optional priorities.
opt-1 is the highest priority for optional jobs, and opt-10 is the lowest priority.
The default built-in priority is 6.
These built-in priorities use exponential penalty weights, where priority 1 is ten times more important than priority 2, priority 2 is ten times more important than priority 3 and so on.
Optionally, you can override these weights or define custom priorities in the model input priorityWeights attribute:
{
"modelInput": {
"priorityWeights": [
{
"priority": "HIGH",
"weight": 10000
},
{
"priority": "LOW",
"weight": 10,
"assignment": "OPTIONAL"
}
]
}
}
2. Mandatory and optional jobs example
Learn how to configure an API Key to run the examples in this guide:
In the examples, replace |
The job’s priority defines if the job is considered mandatory (default if priority not specified) or optional.
In the following example, there are two jobs:
Job A defines priority 1 which makes it a mandatory job.
Mandatory jobs are penalized with a medium-level penalty when they are left unassigned.
Job B defines priority opt-1, making this an optional job.
Optional jobs are penalized with a soft-level penalty when they are left unassigned.
The Require scheduling mandatory stops medium constraint adds a medium penalty to solutions that have mandatory jobs with stops that are left unassigned.
{
"jobs": [
{
"id": "Job A",
"priority": "1",
"stops": [
{
"id": "A1",
"location": [33.78592, -84.46136],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "A2",
"location": [33.72757, -83.96354],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobA_dep1",
"precedingStop": "A1"
}
]
}
]
},
{
"id": "Job B",
"priority": "opt-1",
"stops": [
{
"id": "B1",
"location": [34.11110, -84.43002],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-02T17:00:00Z"
}
]
},
{
"id": "B2",
"location": [33.48594, -84.26560],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-02T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobB_dep1",
"precedingStop": "B1"
}
]
}
]
}
]
}
Carl is working between 09:00 and 13:00 and only has time to complete one job.
Job A is a mandatory job and is assigned to Carl. Because Job B is an optional job and is left unassigned.
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans [email protected]
{
"config": {
"run": {
"name": "Assign mandatory and optional jobs example"
}
},
"modelInput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.68786, -84.18487],
"endLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T13:00:00Z"
}
]
}
],
"jobs": [
{
"id": "Job A",
"priority": "1",
"stops": [
{
"id": "A1",
"location": [33.78592, -84.46136],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "A2",
"location": [33.72757, -83.96354],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobA_dep1",
"precedingStop": "A1"
}
]
}
]
},
{
"id": "Job B",
"priority": "opt-1",
"stops": [
{
"id": "B1",
"location": [34.11110, -84.43002],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "B2",
"location": [33.48594, -84.26560],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobB_dep1",
"precedingStop": "B1"
}
]
}
]
}
],
"planningWindow": {
"startDate": "2027-02-01T00:00:00Z",
"endDate": "2027-02-02T00:00:00Z"
}
}
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
|
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans/<ID>
{
"metadata": {
"id": "ID",
"originId": "ID",
"name": "Assign mandatory and optional jobs example",
"submitDateTime": "2025-11-07T21:34:01.088550366+01:00",
"startDateTime": "2025-11-07T21:34:01.325779948+01:00",
"activeDateTime": "2025-11-07T21:34:01.328985773+01:00",
"completeDateTime": "2025-11-07T21:34:31.451704108+01:00",
"shutdownDateTime": "2025-11-07T21:34:31.451715727+01:00",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-2000006855soft",
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "A1",
"arrivalTime": "2027-02-01T09:33:21Z",
"startServiceTime": "2027-02-01T09:33:21Z",
"departureTime": "2027-02-01T09:53:21Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT33M21S",
"travelDistanceMetersFromPreviousStandstill": 27795
},
{
"id": "A2",
"arrivalTime": "2027-02-01T10:49:07Z",
"startServiceTime": "2027-02-01T10:49:07Z",
"departureTime": "2027-02-01T11:09:07Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT55M46S",
"travelDistanceMetersFromPreviousStandstill": 46477
}
],
"metrics": {
"totalTravelTime": "PT1H54M15S",
"travelTimeFromStartLocationToFirstStop": "PT33M21S",
"travelTimeBetweenStops": "PT55M46S",
"travelTimeFromLastStopToEndLocation": "PT25M8S",
"totalTravelDistanceMeters": 95216,
"travelDistanceFromStartLocationToFirstStopMeters": 27795,
"travelDistanceBetweenStopsMeters": 46477,
"travelDistanceFromLastStopToEndLocationMeters": 20944,
"endLocationArrivalTime": "2027-02-01T11:34:15Z",
"overtime": "PT0S"
}
}
]
}
]
},
"inputMetrics": {
"jobs": 2,
"stops": 4,
"drivers": 1,
"driverShifts": 1
},
"kpis": {
"totalTravelTime": "PT1H54M15S",
"totalTravelDistanceMeters": 95216,
"totalActivatedDrivers": 1,
"totalUnassignedJobs": 1,
"totalAssignedJobs": 1,
"assignedMandatoryJobs": 1,
"assignedOptionalJobs": 0,
"totalUnassignedStops": 2,
"totalAssignedStops": 2,
"assignedMandatoryStops": 2,
"assignedOptionalStops": 0,
"totalOvertime": "PT0S",
"travelTimeFromStartLocationToFirstStop": "PT33M21S",
"travelTimeBetweenStops": "PT55M46S",
"travelTimeFromLastStopToEndLocation": "PT25M8S",
"travelDistanceFromStartLocationToFirstStopMeters": 27795,
"travelDistanceBetweenStopsMeters": 46477,
"travelDistanceFromLastStopToEndLocationMeters": 20944
}
}
3. Too many mandatory jobs
When there are too many mandatory jobs to assign during the planning window, mandatory jobs will be left unassigned, and a medium penalty will be applied to the dataset score.
From the original example, Job B’s priority has been changed from opt-1 to 1, making it a mandatory job.
{
"planningWindow": {
"startDate": "2027-02-01T00:00:00Z",
"endDate": "2027-02-02T00:00:00Z"
},
"jobs": [
{
"id": "Job B",
"priority": "1",
"stops": [
{
"id": "B1",
"location": [34.11110, -84.43002],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "B2",
"location": [33.48594, -84.26560],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobB_dep1",
"precedingStop": "B1"
}
]
}
]
}
]
}
Mandatory Job A is assigned while mandatory Job B is unassigned.
This time, the medium score includes the penalty (-2000medium) for leaving one mandatory job (with two stops) unassigned.
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans [email protected]
{
"config": {
"run": {
"name": "Assign too many mandatory jobs example"
}
},
"modelInput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.68786, -84.18487],
"endLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T13:00:00Z"
}
]
}
],
"jobs": [
{
"id": "Job A",
"priority": "1",
"stops": [
{
"id": "A1",
"location": [33.78592, -84.46136],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "A2",
"location": [33.72757, -83.96354],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobA_dep1",
"precedingStop": "A1"
}
]
}
]
},
{
"id": "Job B",
"priority": "1",
"stops": [
{
"id": "B1",
"location": [34.11110, -84.43002],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "B2",
"location": [33.48594, -84.26560],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobB_dep1",
"precedingStop": "B1"
}
]
}
]
}
],
"planningWindow": {
"startDate": "2027-02-01T00:00:00Z",
"endDate": "2027-02-02T00:00:00Z"
}
}
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
|
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans/<ID>
{
"metadata": {
"id": "ID",
"originId": "ID",
"name": "Assign too many mandatory jobs example",
"submitDateTime": "2025-11-07T21:39:55.717524976+01:00",
"startDateTime": "2025-11-07T21:39:55.740454259+01:00",
"activeDateTime": "2025-11-07T21:39:55.741069272+01:00",
"completeDateTime": "2025-11-07T21:40:25.765007594+01:00",
"shutdownDateTime": "2025-11-07T21:40:25.765013306+01:00",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-2000000000medium/-6855soft",
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "A1",
"arrivalTime": "2027-02-01T09:33:21Z",
"startServiceTime": "2027-02-01T09:33:21Z",
"departureTime": "2027-02-01T09:53:21Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT33M21S",
"travelDistanceMetersFromPreviousStandstill": 27795
},
{
"id": "A2",
"arrivalTime": "2027-02-01T10:49:07Z",
"startServiceTime": "2027-02-01T10:49:07Z",
"departureTime": "2027-02-01T11:09:07Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT55M46S",
"travelDistanceMetersFromPreviousStandstill": 46477
}
],
"metrics": {
"totalTravelTime": "PT1H54M15S",
"travelTimeFromStartLocationToFirstStop": "PT33M21S",
"travelTimeBetweenStops": "PT55M46S",
"travelTimeFromLastStopToEndLocation": "PT25M8S",
"totalTravelDistanceMeters": 95216,
"travelDistanceFromStartLocationToFirstStopMeters": 27795,
"travelDistanceBetweenStopsMeters": 46477,
"travelDistanceFromLastStopToEndLocationMeters": 20944,
"endLocationArrivalTime": "2027-02-01T11:34:15Z",
"overtime": "PT0S"
}
}
]
}
]
},
"inputMetrics": {
"jobs": 2,
"stops": 4,
"drivers": 1,
"driverShifts": 1
},
"kpis": {
"totalTravelTime": "PT1H54M15S",
"totalTravelDistanceMeters": 95216,
"totalActivatedDrivers": 1,
"totalUnassignedJobs": 1,
"totalAssignedJobs": 1,
"assignedMandatoryJobs": 1,
"totalUnassignedStops": 2,
"totalAssignedStops": 2,
"assignedMandatoryStops": 2,
"totalOvertime": "PT0S",
"travelTimeFromStartLocationToFirstStop": "PT33M21S",
"travelTimeBetweenStops": "PT55M46S",
"travelTimeFromLastStopToEndLocation": "PT25M8S",
"travelDistanceFromStartLocationToFirstStopMeters": 27795,
"travelDistanceBetweenStopsMeters": 46477,
"travelDistanceFromLastStopToEndLocationMeters": 20944
}
}
4. Scheduling optional jobs
The Prefer scheduling optional stops soft constraint applies a soft score penalty to the dataset score for every stop that is not assigned, incentivizing time to schedule as many optional jobs as it can.
|
Soft constraints compete with each other as the solver optimizes the final solution. That means this constraint may leave jobs unassigned in favor of jobs with different soft constraints. Every soft constraint has a weight that can be configured to change the relative importance of the constraint compared to other constraints. Learn about constraint weights. |
4.1. Scheduling optional jobs example
In the following example, there are five jobs. One job (Job A) is mandatory, and the other four jobs are optional.
The mandatory job and three of the optional jobs are assigned. One optional job is left unassigned and a soft score penalty is applied to the data set score.
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans [email protected]
{
"config": {
"run": {
"name": "Assign optional jobs example"
}
},
"modelInput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.68786, -84.18487],
"endLocation": [33.68786, -84.18487],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
}
],
"jobs": [
{
"id": "Job A",
"priority": "5",
"prohibitJobPooling": true,
"stops": [
{
"id": "A1",
"location": [33.70592, -84.26136],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "A2",
"location": [33.72757, -83.96354],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobA_dep1",
"precedingStop": "A1"
}
]
}
]
},
{
"id": "Job B",
"priority": "opt-2",
"prohibitJobPooling": true,
"stops": [
{
"id": "B1",
"location": [33.75757, -83.76354],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "B2",
"location": [33.95594, -83.26560],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobB_dep1",
"precedingStop": "B1"
}
]
}
]
},
{
"id": "Job C",
"priority": "opt-2",
"prohibitJobPooling": true,
"stops": [
{
"id": "C1",
"location": [34.01, -83.563],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "C2",
"location": [33.978, -83.860],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobC_dep1",
"precedingStop": "C1"
}
]
}
]
},
{
"id": "Job D",
"priority": "opt-2",
"prohibitJobPooling": true,
"stops": [
{
"id": "D1",
"location": [33.901, -83.990],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "D2",
"location": [33.955, -83.650],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobD_dep1",
"precedingStop": "D1"
}
]
}
]
},
{
"id": "Job E",
"priority": "opt-2",
"prohibitJobPooling": true,
"stops": [
{
"id": "E1",
"location": [33.695, -83.950],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
]
},
{
"id": "E2",
"location": [33.698, -83.650],
"duration": "PT20M",
"timeWindows": [
{
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T17:00:00Z"
}
],
"stopDependencies": [
{
"id": "jobE_dep1",
"precedingStop": "E1"
}
]
}
]
}
]
}
}
To request the solution, locate the ID from the response to the post operation and append it to the following API call:
|
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/pickup-delivery-routing/v1/route-plans/<ID>
{
"metadata": {
"id": "ID",
"originId": "ID",
"name": "Assign optional jobs example",
"submitDateTime": "2025-12-15T08:22:12.393845749Z",
"startDateTime": "2025-12-15T08:22:30.51558286Z",
"activeDateTime": "2025-12-15T08:22:30.592648357Z",
"completeDateTime": "2025-12-15T08:23:01.180386428Z",
"shutdownDateTime": "2025-12-15T08:23:01.180390857Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-200017662soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "A1",
"arrivalTime": "2027-02-01T09:13:31Z",
"startServiceTime": "2027-02-01T09:13:31Z",
"departureTime": "2027-02-01T09:33:31Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT13M31S",
"travelDistanceMetersFromPreviousStandstill": 8699
},
{
"id": "A2",
"arrivalTime": "2027-02-01T10:11:08Z",
"startServiceTime": "2027-02-01T10:11:08Z",
"departureTime": "2027-02-01T10:31:08Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT37M37S",
"travelDistanceMetersFromPreviousStandstill": 38485
},
{
"id": "E1",
"arrivalTime": "2027-02-01T10:38:24Z",
"startServiceTime": "2027-02-01T10:38:24Z",
"departureTime": "2027-02-01T10:58:24Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT7M16S",
"travelDistanceMetersFromPreviousStandstill": 4443
},
{
"id": "E2",
"arrivalTime": "2027-02-01T11:41:17Z",
"startServiceTime": "2027-02-01T11:41:17Z",
"departureTime": "2027-02-01T12:01:17Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT42M53S",
"travelDistanceMetersFromPreviousStandstill": 41069
},
{
"id": "D1",
"arrivalTime": "2027-02-01T12:54:03Z",
"startServiceTime": "2027-02-01T12:54:03Z",
"departureTime": "2027-02-01T13:14:03Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT52M46S",
"travelDistanceMetersFromPreviousStandstill": 47720
},
{
"id": "D2",
"arrivalTime": "2027-02-01T13:48:26Z",
"startServiceTime": "2027-02-01T13:48:26Z",
"departureTime": "2027-02-01T14:08:26Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT34M23S",
"travelDistanceMetersFromPreviousStandstill": 38523
},
{
"id": "C1",
"arrivalTime": "2027-02-01T14:25:19Z",
"startServiceTime": "2027-02-01T14:25:19Z",
"departureTime": "2027-02-01T14:45:19Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT16M53S",
"travelDistanceMetersFromPreviousStandstill": 16686
},
{
"id": "C2",
"arrivalTime": "2027-02-01T15:16:33Z",
"startServiceTime": "2027-02-01T15:16:33Z",
"departureTime": "2027-02-01T15:36:33Z",
"effectiveServiceDuration": "PT20M",
"kind": "STOP",
"travelTimeFromPreviousStandstill": "PT31M14S",
"travelDistanceMetersFromPreviousStandstill": 35417
}
],
"metrics": {
"totalTravelTime": "PT4H54M22S",
"travelTimeFromStartLocationToFirstStop": "PT13M31S",
"travelTimeBetweenStops": "PT3H43M2S",
"travelTimeFromLastStopToEndLocation": "PT57M49S",
"totalTravelDistanceMeters": 299904,
"travelDistanceFromStartLocationToFirstStopMeters": 8699,
"travelDistanceBetweenStopsMeters": 222343,
"travelDistanceFromLastStopToEndLocationMeters": 68862,
"endLocationArrivalTime": "2027-02-01T16:34:22Z"
}
}
]
}
]
},
"inputMetrics": {
"jobs": 5,
"stops": 10,
"drivers": 1,
"driverShifts": 1
},
"kpis": {
"totalTravelTime": "PT4H54M22S",
"totalTravelDistanceMeters": 299904,
"totalActivatedDrivers": 1,
"totalUnassignedJobs": 1,
"totalAssignedJobs": 4,
"assignedMandatoryJobs": 1,
"assignedOptionalJobs": 3,
"totalUnassignedStops": 2,
"totalAssignedStops": 8,
"assignedMandatoryStops": 2,
"assignedOptionalStops": 6,
"travelTimeFromStartLocationToFirstStop": "PT13M31S",
"travelTimeBetweenStops": "PT3H43M2S",
"travelTimeFromLastStopToEndLocation": "PT57M49S",
"travelDistanceFromStartLocationToFirstStopMeters": 8699,
"travelDistanceBetweenStopsMeters": 222343,
"travelDistanceFromLastStopToEndLocationMeters": 68862
},
"run": {
"id": "ID",
"originId": "ID",
"name": "Assign optional jobs example",
"submitDateTime": "2025-12-15T08:22:12.393845749Z",
"startDateTime": "2025-12-15T08:22:30.51558286Z",
"activeDateTime": "2025-12-15T08:22:30.592648357Z",
"completeDateTime": "2025-12-15T08:23:01.180386428Z",
"shutdownDateTime": "2025-12-15T08:23:01.180390857Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-200017662soft",
"tags": [
"system.type:from-request",
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
}
}
Next
-
See the full API spec or try the online API.