Real-time planning: no show
| This guide details the currently supported real-time planning features. If you are using the Patch (preview) feature, please see Real-time planning with patches |
There are many situations where Real-time planning is necessary.
Sometimes customers are not available at the scheduled time.
When Carl arrives at his first stop of the day, the customer isn’t there. Carl lets head office know, and they start re-planning the stops for his shift.
Carl waits for 10 minutes at the customer location, but the customer doesn’t show up. The real-time plan is published and Carl goes to his next stop.
This guide explains real-time planning: no shows with the following:
1. Batch schedule: no show
Learn how to configure an API Key to run the examples in this guide:
In the examples, replace |
Carl’s original schedule was generated from the following input dataset during the regular batch scheduling:
-
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": "Original shift plan: no show example"
}
},
"modelInput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.77284, -84.42989],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T13:30:00Z"
}
]
}
],
"jobs": [
{
"id": "Job 1",
"stops": [
{
"id": "Stop A",
"name": "Stop A",
"location": [33.74648, -84.46461],
"duration": "PT30M"
},
{
"id": "Stop B",
"name": "Stop B",
"location": [33.65207, -84.46496],
"duration": "PT30M"
}
]
},
{
"id": "Job 2",
"stops": [
{
"id": "Stop C",
"name": "Stop C",
"location": [33.77911, -84.49644],
"duration": "PT30M"
},
{
"id": "Stop D",
"name": "Stop D",
"location": [33.65979, -84.46366],
"duration": "PT30M"
}
]
},
{
"id": "Job 3",
"stops": [
{
"id": "Stop E",
"name": "Stop E",
"location": [ 33.78468, -84.48469],
"duration": "PT30M"
},
{
"id": "Stop F",
"name": "Stop F",
"location": [ 33.67966, -84.30062 ],
"duration": "PT30M"
}
]
}
]
}
}
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": "Original shift plan: no show example",
"submitDateTime": "2026-04-10T09:48:00.417874+02:00",
"startDateTime": "2026-04-10T09:48:00.478676+02:00",
"activeDateTime": "2026-04-10T09:48:00.479147+02:00",
"completeDateTime": "2026-04-10T09:48:30.483707+02:00",
"shutdownDateTime": "2026-04-10T09:48:30.483709+02:00",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-3815soft",
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Stop E",
"arrivalTime": "2027-02-01T09:06:17Z",
"startServiceTime": "2027-02-01T09:06:17Z",
"departureTime": "2027-02-01T09:36:17Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT6M17S",
"travelDistanceMetersFromPreviousStandstill": 5233,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop C",
"arrivalTime": "2027-02-01T09:37:47Z",
"startServiceTime": "2027-02-01T09:37:47Z",
"departureTime": "2027-02-01T10:07:47Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT1M30S",
"travelDistanceMetersFromPreviousStandstill": 1250,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop A",
"arrivalTime": "2027-02-01T10:13:23Z",
"startServiceTime": "2027-02-01T10:13:23Z",
"departureTime": "2027-02-01T10:43:23Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT5M36S",
"travelDistanceMetersFromPreviousStandstill": 4671,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop D",
"arrivalTime": "2027-02-01T10:54:57Z",
"startServiceTime": "2027-02-01T10:54:57Z",
"departureTime": "2027-02-01T11:24:57Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT11M34S",
"travelDistanceMetersFromPreviousStandstill": 9640,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop B",
"arrivalTime": "2027-02-01T11:25:59Z",
"startServiceTime": "2027-02-01T11:25:59Z",
"departureTime": "2027-02-01T11:55:59Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT1M2S",
"travelDistanceMetersFromPreviousStandstill": 867,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop F",
"arrivalTime": "2027-02-01T12:14:36Z",
"startServiceTime": "2027-02-01T12:14:36Z",
"departureTime": "2027-02-01T12:44:36Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT18M37S",
"travelDistanceMetersFromPreviousStandstill": 15515,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"kind": "STOP"
}
],
"metrics": {
"totalTravelTime": "PT1H3M35S",
"travelTimeFromStartLocationToFirstStop": "PT6M17S",
"travelTimeBetweenStops": "PT38M19S",
"travelTimeFromLastStopToEndLocation": "PT18M59S",
"totalTravelDistanceMeters": 52996,
"travelDistanceFromStartLocationToFirstStopMeters": 5233,
"travelDistanceBetweenStopsMeters": 31943,
"travelDistanceFromLastStopToEndLocationMeters": 15820,
"endLocationArrivalTime": "2027-02-01T13:03:35Z"
}
}
]
}
],
"unassignedJobs": []
},
"inputMetrics": {
"jobs": 3,
"stops": 6,
"drivers": 1,
"driverShifts": 1,
"pinnedStops": 0
},
"kpis": {
"totalTravelTime": "PT1H3M35S",
"totalTravelDistanceMeters": 52996,
"totalActivatedDrivers": 1,
"totalUnassignedJobs": 0,
"totalAssignedJobs": 3,
"assignedMandatoryJobs": 3,
"totalUnassignedStops": 0,
"totalAssignedStops": 6,
"assignedMandatoryStops": 6,
"travelTimeFromStartLocationToFirstStop": "PT6M17S",
"travelTimeBetweenStops": "PT38M19S",
"travelTimeFromLastStopToEndLocation": "PT18M59S",
"travelDistanceFromStartLocationToFirstStopMeters": 5233,
"travelDistanceBetweenStopsMeters": 31943,
"travelDistanceFromLastStopToEndLocationMeters": 15820
}
}
modelOutput contains Carl’s shift itinerary.
2. Real-time planning update: no show
Carl reported the customer of his first job was not present when he arrived, so he waited at the pick-up location.
Update the duration for Stop E from 30 minutes to 10 minutes.
As Carl hasn’t picked up the order, the delivery stop (Stop F) for this job should be removed from the dataset.
|
The customer was not present and the work wasn’t completed. Assuming the customer still wants the work completed, the whole job will need to be rescheduled for a later time. |
Add the minStartTravelTime from the most recent planning output dataset (batch or real-time) to each stop:
{
"jobs": [
{
"id": "Job 1",
"stops": [
{
"id": "Stop A",
"name": "Stop A",
"location": [33.74648, -84.46461],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Stop B",
"name": "Stop B",
"location": [33.65207, -84.46496],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
},
{
"id": "Job 2",
"stops": [
{
"id": "Stop C",
"name": "Stop C",
"location": [33.77911, -84.49644],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Stop D",
"name": "Stop D",
"location": [33.65979, -84.46366],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
},
{
"id": "Job 3",
"stops": [
{
"id": "Stop E",
"name": "Stop E",
"location": [ 33.78468, -84.48469],
"duration": "PT10M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
}
]
}
Add the itinerary to Carl’s shifts with Stop E, Stop C, Stop A, Stop D and Stop B including the stop IDs and the stop kind. Stop F is removed from the itinerary as it was the delivery stop for the job that was not completed:
| In case, the job has a demand, the demand should also be updated to reflect the fact that the job was not completed. |
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.77284, -84.42989],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T13:30:00Z",
"itinerary": [
{
"id": "Stop E",
"kind": "STOP"
},
{
"id": "Stop C",
"kind": "STOP"
},
{
"id": "Stop A",
"kind": "STOP"
},
{
"id": "Stop D",
"kind": "STOP"
},
{
"id": "Stop B",
"kind": "STOP"
}
]
}
]
}
Freeze the departure times for stops that have already occurred and that drivers have begun traveling to by adding freezeTime:
{
"modelInput": {
"freezeTime": "2027-02-01T09:15:00Z"
}
}
Carl arrived at Stop E at 09:06 and waited 10 minutes.
freezeTime is set to 09:15 so that his next stops can be rescheduled, and he can travel to the next location.
Submit the updated input dataset to generate the new real-time plan.
-
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": "Original shift plan: no show example"
}
},
"modelInput": {
"freezeTime": "2027-02-01T09:15:00Z",
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startLocation": [33.77284, -84.42989],
"minStartTime": "2027-02-01T09:00:00Z",
"maxEndTime": "2027-02-01T13:30:00Z",
"itinerary": [
{
"id": "Stop E",
"kind": "STOP"
},
{
"id": "Stop C",
"kind": "STOP"
},
{
"id": "Stop A",
"kind": "STOP"
},
{
"id": "Stop D",
"kind": "STOP"
},
{
"id": "Stop B",
"kind": "STOP"
}
]
}
]
}
],
"jobs": [
{
"id": "Job 1",
"stops": [
{
"id": "Stop A",
"name": "Stop A",
"location": [33.74648, -84.46461],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Stop B",
"name": "Stop B",
"location": [33.65207, -84.46496],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
},
{
"id": "Job 2",
"stops": [
{
"id": "Stop C",
"name": "Stop C",
"location": [33.77911, -84.49644],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
},
{
"id": "Stop D",
"name": "Stop D",
"location": [33.65979, -84.46366],
"duration": "PT30M",
"minStartTravelTime": "2027-02-01T00:00:00Z"
}
]
},
{
"id": "Job 3",
"stops": [
{
"id": "Stop E",
"name": "Stop E",
"location": [ 33.78468, -84.48469],
"duration": "PT10M",
"minStartTravelTime": "2027-02-01T00: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": "Original shift plan: no show example",
"submitDateTime": "2026-04-10T10:39:47.865413+02:00",
"startDateTime": "2026-04-10T10:39:47.934356+02:00",
"activeDateTime": "2026-04-10T10:39:47.935839+02:00",
"completeDateTime": "2026-04-10T10:40:17.951177+02:00",
"shutdownDateTime": "2026-04-10T10:40:17.95118+02:00",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-2554soft",
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"drivers": [
{
"id": "Carl",
"shifts": [
{
"id": "Carl Mon",
"startTime": "2027-02-01T09:00:00Z",
"itinerary": [
{
"id": "Stop E",
"arrivalTime": "2027-02-01T09:06:17Z",
"startServiceTime": "2027-02-01T09:06:17Z",
"departureTime": "2027-02-01T09:16:17Z",
"effectiveServiceDuration": "PT10M",
"travelTimeFromPreviousStandstill": "PT6M17S",
"travelDistanceMetersFromPreviousStandstill": 5233,
"minStartTravelTime": "2027-02-01T00:00:00Z",
"load": [],
"pinned": true,
"kind": "STOP"
},
{
"id": "Stop C",
"arrivalTime": "2027-02-01T09:17:47Z",
"startServiceTime": "2027-02-01T09:17:47Z",
"departureTime": "2027-02-01T09:47:47Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT1M30S",
"travelDistanceMetersFromPreviousStandstill": 1250,
"minStartTravelTime": "2027-02-01T09:15:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop A",
"arrivalTime": "2027-02-01T09:53:23Z",
"startServiceTime": "2027-02-01T09:53:23Z",
"departureTime": "2027-02-01T10:23:23Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT5M36S",
"travelDistanceMetersFromPreviousStandstill": 4671,
"minStartTravelTime": "2027-02-01T09:15:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop D",
"arrivalTime": "2027-02-01T10:34:57Z",
"startServiceTime": "2027-02-01T10:34:57Z",
"departureTime": "2027-02-01T11:04:57Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT11M34S",
"travelDistanceMetersFromPreviousStandstill": 9640,
"minStartTravelTime": "2027-02-01T09:15:00Z",
"load": [],
"kind": "STOP"
},
{
"id": "Stop B",
"arrivalTime": "2027-02-01T11:05:59Z",
"startServiceTime": "2027-02-01T11:05:59Z",
"departureTime": "2027-02-01T11:35:59Z",
"effectiveServiceDuration": "PT30M",
"travelTimeFromPreviousStandstill": "PT1M2S",
"travelDistanceMetersFromPreviousStandstill": 867,
"minStartTravelTime": "2027-02-01T09:15:00Z",
"load": [],
"kind": "STOP"
}
],
"metrics": {
"totalTravelTime": "PT42M34S",
"travelTimeFromStartLocationToFirstStop": "PT6M17S",
"travelTimeBetweenStops": "PT19M42S",
"travelTimeFromLastStopToEndLocation": "PT16M35S",
"totalTravelDistanceMeters": 35476,
"travelDistanceFromStartLocationToFirstStopMeters": 5233,
"travelDistanceBetweenStopsMeters": 16428,
"travelDistanceFromLastStopToEndLocationMeters": 13815,
"endLocationArrivalTime": "2027-02-01T11:52:34Z"
}
}
]
}
],
"unassignedJobs": []
},
"inputMetrics": {
"jobs": 3,
"stops": 5,
"drivers": 1,
"driverShifts": 1,
"pinnedStops": 1
},
"kpis": {
"totalTravelTime": "PT42M34S",
"totalTravelDistanceMeters": 35476,
"totalActivatedDrivers": 1,
"totalUnassignedJobs": 0,
"totalAssignedJobs": 3,
"assignedMandatoryJobs": 3,
"totalUnassignedStops": 0,
"totalAssignedStops": 5,
"assignedMandatoryStops": 5,
"travelTimeFromStartLocationToFirstStop": "PT6M17S",
"travelTimeBetweenStops": "PT19M42S",
"travelTimeFromLastStopToEndLocation": "PT16M35S",
"travelDistanceFromStartLocationToFirstStopMeters": 5233,
"travelDistanceBetweenStopsMeters": 16428,
"travelDistanceFromLastStopToEndLocationMeters": 13815
}
}
modelOutput contains Carl’s updated shift itinerary.
Stop E was a no show, so Stop C, Stop A, Stop D and Stop B are rescheduled for earlier in the day. Stop F was removed from the itinerary as it was the delivery stop for the job that wasn’t completed.
Next
-
See the full API spec or try the online API.
-
Learn about real-time planning.
-
Real-time planning with pinned stops.
-
Real-time planning with extended stops.