Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
  • Platform
Try models
  • Pick-up and Delivery Routing
  • Real-time planning
  • Real-time planning: driver ill

Pick-up and Delivery Routing

    • Introduction
    • Getting started: Hello world
    • User guide
      • Terminology
      • Use case guide
      • Planning AI concepts
      • Integration
      • Constraints
      • Understanding the API
      • Demo datasets
      • Input datasets
        • Model configuration
        • Model input
        • Planning window
      • Input validation
      • Output datasets
        • Metadata
        • Model output
        • Input metrics
        • Key performance indicators (KPIs)
      • Routing with Timefold’s maps service
      • Metrics and optimization goals
    • Driver resource constraints
      • Lunch breaks and personal appointments
      • Route optimization
      • Shift hours and overtime
      • Driver capacity
    • Job service constraints
      • Time windows and opening hours
      • Skills
      • Multi-day schedules and movable stops
      • Dependencies between stops
      • Priority jobs and optional jobs
      • Stop service level agreement (SLA)
      • Job requirements and tags
        • Job required drivers
        • Job pooling
        • Prohibit job combinations
        • Maximum time burden
        • Tags
    • Recommendations
      • Job time window recommendations
      • Stop time window recommendations
    • Real-time planning
      • Real-time planning: pinning stops
      • Real-time planning: extended stop
      • Real-time planning: reassignment
      • Real-time planning: no show
      • Real-time planning: driver ill
    • Real-time planning with patches
      • Real-time planning: pinning stops (using patches)
      • Real-time planning: extended stop (using patches)
      • Real-time planning: reassignment (using patches)
      • Real-time planning: no show (using patches)
      • Real-time planning: driver ill (using patches)
    • Changelog
    • Upgrading to the latest versions
    • Feature requests

Real-time planning: driver ill

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 drivers become ill and must take the day off or, if they have already started work, go home part way through a shift.

Consider the following shift schedule:

Ann has three jobs assigned with two stops each: Stop E, Stop C, Stop A, Stop B, Stop D and Stop F. Carl has one job assigned with two stops: Stop G and Stop H.

If Ann calls in sick before the shift starts or goes home part way through the day due to illness, her stops must be reassigned to another driver or rescheduled for another day.

This guide explains real-time planning: driver ill with the following:

  • 1. Batch schedule: driver ill
  • 2. Real-time planning update: driver ill
  • 3. Real-time planning update: driver becomes ill

1. Batch schedule: driver ill

Learn how to configure an API Key to run the examples in this guide:
  1. Log in to Timefold Platform: app.timefold.ai

  2. From the Dashboard, click your tenant, and from the drop-down menu select Manage tenant, then choose API Keys.

  3. Create a new API key or use an existing one. Ensure the list of models for the API key contains the Pick-up and Delivery Routing model.

In the examples, replace <API_KEY> with the API Key you just copied.

The 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: driver ill 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"
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startLocation": [33.79426, -84.330114],
            "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"
          }
        ]
      },
      {
        "id": "Job 4",
        "stops": [
          {
            "id": "Stop G",
            "name": "Stop G",
            "location": [ 33.73698, -84.34712 ],
            "duration": "PT30M"
          },
          {
            "id": "Stop H",
            "name": "Stop H",
            "location": [ 33.74661, -84.47359 ],
            "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: driver ill example",
    "submitDateTime": "2026-04-09T17:06:00.955838+02:00",
    "startDateTime": "2026-04-09T17:06:01.006547+02:00",
    "activeDateTime": "2026-04-09T17:06:01.008361+02:00",
    "completeDateTime": "2026-04-09T17:06:31.02371+02:00",
    "shutdownDateTime": "2026-04-09T17:06:31.023713+02:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-6136soft",
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "drivers": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl Mon",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Stop G",
                "arrivalTime": "2027-02-01T09:10:21Z",
                "startServiceTime": "2027-02-01T09:10:21Z",
                "departureTime": "2027-02-01T09:40:21Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT10M21S",
                "travelDistanceMetersFromPreviousStandstill": 8629,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop H",
                "arrivalTime": "2027-02-01T09:54:26Z",
                "startServiceTime": "2027-02-01T09:54:26Z",
                "departureTime": "2027-02-01T10:24:26Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT14M5S",
                "travelDistanceMetersFromPreviousStandstill": 11743,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT30M25S",
              "travelTimeFromStartLocationToFirstStop": "PT10M21S",
              "travelTimeBetweenStops": "PT14M5S",
              "travelTimeFromLastStopToEndLocation": "PT5M59S",
              "totalTravelDistanceMeters": 25355,
              "travelDistanceFromStartLocationToFirstStopMeters": 8629,
              "travelDistanceBetweenStopsMeters": 11743,
              "travelDistanceFromLastStopToEndLocationMeters": 4983,
              "endLocationArrivalTime": "2027-02-01T10:30:25Z"
            }
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Stop E",
                "arrivalTime": "2027-02-01T09:17:11Z",
                "startServiceTime": "2027-02-01T09:17:11Z",
                "departureTime": "2027-02-01T09:47:11Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT17M11S",
                "travelDistanceMetersFromPreviousStandstill": 14324,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop C",
                "arrivalTime": "2027-02-01T09:48:41Z",
                "startServiceTime": "2027-02-01T09:48:41Z",
                "departureTime": "2027-02-01T10:18:41Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT1M30S",
                "travelDistanceMetersFromPreviousStandstill": 1250,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop A",
                "arrivalTime": "2027-02-01T10:24:17Z",
                "startServiceTime": "2027-02-01T10:24:17Z",
                "departureTime": "2027-02-01T10:54:17Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT5M36S",
                "travelDistanceMetersFromPreviousStandstill": 4671,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop B",
                "arrivalTime": "2027-02-01T11:06:53Z",
                "startServiceTime": "2027-02-01T11:06:53Z",
                "departureTime": "2027-02-01T11:36:53Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT12M36S",
                "travelDistanceMetersFromPreviousStandstill": 10498,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop D",
                "arrivalTime": "2027-02-01T11:37:55Z",
                "startServiceTime": "2027-02-01T11:37:55Z",
                "departureTime": "2027-02-01T12:07:55Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT1M2S",
                "travelDistanceMetersFromPreviousStandstill": 867,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop F",
                "arrivalTime": "2027-02-01T12:26:13Z",
                "startServiceTime": "2027-02-01T12:26:13Z",
                "departureTime": "2027-02-01T12:56:13Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT18M18S",
                "travelDistanceMetersFromPreviousStandstill": 15249,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H11M51S",
              "travelTimeFromStartLocationToFirstStop": "PT17M11S",
              "travelTimeBetweenStops": "PT39M2S",
              "travelTimeFromLastStopToEndLocation": "PT15M38S",
              "totalTravelDistanceMeters": 59891,
              "travelDistanceFromStartLocationToFirstStopMeters": 14324,
              "travelDistanceBetweenStopsMeters": 32535,
              "travelDistanceFromLastStopToEndLocationMeters": 13032,
              "endLocationArrivalTime": "2027-02-01T13:11:51Z"
            }
          }
        ]
      }
    ],
    "unassignedJobs": []
  },
  "inputMetrics": {
    "jobs": 4,
    "stops": 8,
    "drivers": 2,
    "driverShifts": 2,
    "pinnedStops": 0
  },
  "kpis": {
    "totalTravelTime": "PT1H42M16S",
    "totalTravelDistanceMeters": 85246,
    "totalActivatedDrivers": 2,
    "totalUnassignedJobs": 0,
    "totalAssignedJobs": 4,
    "assignedMandatoryJobs": 4,
    "totalUnassignedStops": 0,
    "totalAssignedStops": 8,
    "assignedMandatoryStops": 8,
    "travelTimeFromStartLocationToFirstStop": "PT27M32S",
    "travelTimeBetweenStops": "PT53M7S",
    "travelTimeFromLastStopToEndLocation": "PT21M37S",
    "travelDistanceFromStartLocationToFirstStopMeters": 22953,
    "travelDistanceBetweenStopsMeters": 44278,
    "travelDistanceFromLastStopToEndLocationMeters": 18015
  }
}

modelOutput contains Carl’s and Ann’s shift itinerary.

2. Real-time planning update: driver ill

When a driver becomes ill before a shift has started, they can be removed from the input dataset and the dataset can be resubmitted.

Timefold will reassign jobs that can be reassigned and leave any remaining jobs unassigned to be rescheduled for another day.

  • 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: driver ill 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"
          }
        ]
      },
      {
        "id": "Job 4",
        "stops": [
          {
            "id": "Stop G",
            "name": "Stop G",
            "location": [ 33.73698, -84.34712 ],
            "duration": "PT30M"
          },
          {
            "id": "Stop H",
            "name": "Stop H",
            "location": [ 33.74661, -84.47359 ],
            "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: driver ill example",
    "submitDateTime": "2026-04-09T17:09:04.242218+02:00",
    "startDateTime": "2026-04-09T17:09:04.39681+02:00",
    "activeDateTime": "2026-04-09T17:09:04.398884+02:00",
    "completeDateTime": "2026-04-09T17:09:34.414763+02:00",
    "shutdownDateTime": "2026-04-09T17:09:34.414766+02:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-20000medium/-5073soft",
    "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 F",
                "arrivalTime": "2027-02-01T10:01:03Z",
                "startServiceTime": "2027-02-01T10:01:03Z",
                "departureTime": "2027-02-01T10:31:03Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT24M46S",
                "travelDistanceMetersFromPreviousStandstill": 20642,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop G",
                "arrivalTime": "2027-02-01T10:40:17Z",
                "startServiceTime": "2027-02-01T10:40:17Z",
                "departureTime": "2027-02-01T11:10:17Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT9M14S",
                "travelDistanceMetersFromPreviousStandstill": 7689,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop H",
                "arrivalTime": "2027-02-01T11:24:22Z",
                "startServiceTime": "2027-02-01T11:24:22Z",
                "departureTime": "2027-02-01T11:54:22Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT14M5S",
                "travelDistanceMetersFromPreviousStandstill": 11743,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop A",
                "arrivalTime": "2027-02-01T11:55:22Z",
                "startServiceTime": "2027-02-01T11:55:22Z",
                "departureTime": "2027-02-01T12:25:22Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT1M",
                "travelDistanceMetersFromPreviousStandstill": 830,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop B",
                "arrivalTime": "2027-02-01T12:37:58Z",
                "startServiceTime": "2027-02-01T12:37:58Z",
                "departureTime": "2027-02-01T13:07:58Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT12M36S",
                "travelDistanceMetersFromPreviousStandstill": 10498,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "kind": "STOP"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H24M33S",
              "travelTimeFromStartLocationToFirstStop": "PT6M17S",
              "travelTimeBetweenStops": "PT1H1M41S",
              "travelTimeFromLastStopToEndLocation": "PT16M35S",
              "totalTravelDistanceMeters": 70450,
              "travelDistanceFromStartLocationToFirstStopMeters": 5233,
              "travelDistanceBetweenStopsMeters": 51402,
              "travelDistanceFromLastStopToEndLocationMeters": 13815,
              "endLocationArrivalTime": "2027-02-01T13:24:33Z"
            }
          }
        ]
      }
    ],
    "unassignedJobs": [
      {
        "id": "Job 2",
        "unassignedStops": [
          "Stop C",
          "Stop D"
        ]
      }
    ]
  },
  "inputMetrics": {
    "jobs": 4,
    "stops": 8,
    "drivers": 1,
    "driverShifts": 1,
    "pinnedStops": 0
  },
  "kpis": {
    "totalTravelTime": "PT1H24M33S",
    "totalTravelDistanceMeters": 70450,
    "totalActivatedDrivers": 1,
    "totalUnassignedJobs": 1,
    "totalAssignedJobs": 3,
    "assignedMandatoryJobs": 3,
    "totalUnassignedStops": 2,
    "totalAssignedStops": 6,
    "assignedMandatoryStops": 6,
    "travelTimeFromStartLocationToFirstStop": "PT6M17S",
    "travelTimeBetweenStops": "PT1H1M41S",
    "travelTimeFromLastStopToEndLocation": "PT16M35S",
    "travelDistanceFromStartLocationToFirstStopMeters": 5233,
    "travelDistanceBetweenStopsMeters": 51402,
    "travelDistanceFromLastStopToEndLocationMeters": 13815
  }
}

modelOutput contains Carl’s updated shift itinerary.

Jobs 1 and 3 were reassigned from Ann to Carl. Job 2 was left unassigned.

3. Real-time planning update: driver becomes ill

In this example, Ann becomes ill after starting her work day. After picking up her first job (Stop E), Ann realizes that she is ill and needs to go home. Instead of continuing with her remaining jobs, she delivers the first job (Stop F) and then goes home.

The plan must be updated part way through the day.

Include the itineraries for both Ann and Carl. As Ann will only complete her first job (Stop E and Stop F), her itinerary will only include that job. Ann’s itinerary should also be pinned to ensure that it isn’t changed during the real-time planning update. Carl’s itinerary should include all of his previously assigned jobs:

{
  "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 G",
              "kind": "STOP"
            },
            {
              "id": "STOP H",
              "kind": "STOP"
            }
          ]
        }
      ]
    },
    {
      "id": "Ann",
      "shifts": [
        {
          "id": "Ann Mon",
          "startLocation": [33.79426, -84.330114],
          "minStartTime": "2027-02-01T09:00:00Z",
          "maxEndTime": "2027-02-01T13:30:00Z",
          "itinerary": [
            {
              "id": "STOP E",
              "kind": "STOP"
            },
            {
              "id": "STOP F",
              "kind": "STOP"
            }
          ],
          "pinned": true
        }
      ]
    }
  ]
}

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": "PT30M",
          "minStartTravelTime": "2027-02-01T00:00:00Z"
        },
        {
          "id": "Stop F",
          "name": "Stop F",
          "location": [ 33.67966, -84.30062 ],
          "duration": "PT30M",
          "minStartTravelTime": "2027-02-01T00:00:00Z"
        }
      ]
    },
    {
      "id": "Job 4",
      "stops": [
        {
          "id": "Stop G",
          "name": "Stop G",
          "location": [ 33.73698, -84.34712 ],
          "duration": "PT30M",
          "minStartTravelTime": "2027-02-01T00:00:00Z"
        },
        {
          "id": "Stop H",
          "name": "Stop H",
          "location": [ 33.74661, -84.47359 ],
          "duration": "PT30M",
          "minStartTravelTime": "2027-02-01T00:00:00Z"
        }
      ]
    }
  ]
}

Freeze the departure times for stops that have already occurred and that drivers have begun traveling to by adding freezeTime. Ann finished Stop E at 09:47 when she realized that she was ill and needed to go home, so the freezeTime can be set to 09:47.

{
  "modelInput": {
    "freezeTime": "2027-02-01T09:47:00Z"
  }
}

Submit the 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: driver ill example"
    }
  },
  "modelInput": {
    "freezeTime": "2027-02-01T09:47: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 G",
                "kind": "STOP"
              },
              {
                "id": "Stop H",
                "kind": "STOP"
              }
            ]
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startLocation": [33.79426, -84.330114],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T13:30:00Z",
            "itinerary": [
              {
                "id": "Stop E",
                "kind": "STOP"
              },
              {
                "id": "Stop F",
                "kind": "STOP"
              }
            ],
            "pinned": true
          }
        ]
      }
    ],
    "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": "PT30M",
            "minStartTravelTime": "2027-02-01T00:00:00Z"
          },
          {
            "id": "Stop F",
            "name": "Stop F",
            "location": [ 33.67966, -84.30062 ],
            "duration": "PT30M",
            "minStartTravelTime": "2027-02-01T00:00:00Z"
          }
        ]
      },
      {
        "id": "Job 4",
        "stops": [
          {
            "id": "Stop G",
            "name": "Stop G",
            "location": [ 33.73698, -84.34712 ],
            "duration": "PT30M",
            "minStartTravelTime": "2027-02-01T00:00:00Z"
          },
          {
            "id": "Stop H",
            "name": "Stop H",
            "location": [ 33.74661, -84.47359 ],
            "duration": "PT30M",
            "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: driver ill example",
    "submitDateTime": "2026-04-10T09:42:31.757761+02:00",
    "startDateTime": "2026-04-10T09:42:31.886929+02:00",
    "activeDateTime": "2026-04-10T09:42:31.888494+02:00",
    "completeDateTime": "2026-04-10T09:43:01.906806+02:00",
    "shutdownDateTime": "2026-04-10T09:43:01.906811+02:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-8647soft",
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "drivers": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl Mon",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Stop G",
                "arrivalTime": "2027-02-01T09:10:21Z",
                "startServiceTime": "2027-02-01T09:10:21Z",
                "departureTime": "2027-02-01T09:40:21Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT10M21S",
                "travelDistanceMetersFromPreviousStandstill": 8629,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "pinned": true,
                "kind": "STOP"
              },
              {
                "id": "Stop H",
                "arrivalTime": "2027-02-01T09:54:26Z",
                "startServiceTime": "2027-02-01T09:54:26Z",
                "departureTime": "2027-02-01T10:24:26Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT14M5S",
                "travelDistanceMetersFromPreviousStandstill": 11743,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "pinned": true,
                "kind": "STOP"
              },
              {
                "id": "Stop C",
                "arrivalTime": "2027-02-01T10:29:27Z",
                "startServiceTime": "2027-02-01T10:29:27Z",
                "departureTime": "2027-02-01T10:59:27Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT5M1S",
                "travelDistanceMetersFromPreviousStandstill": 4186,
                "minStartTravelTime": "2027-02-01T09:47:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop D",
                "arrivalTime": "2027-02-01T11:15:47Z",
                "startServiceTime": "2027-02-01T11:15:47Z",
                "departureTime": "2027-02-01T11:45:47Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT16M20S",
                "travelDistanceMetersFromPreviousStandstill": 13610,
                "minStartTravelTime": "2027-02-01T09:47:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop A",
                "arrivalTime": "2027-02-01T11:57:21Z",
                "startServiceTime": "2027-02-01T11:57:21Z",
                "departureTime": "2027-02-01T12:27:21Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT11M34S",
                "travelDistanceMetersFromPreviousStandstill": 9640,
                "minStartTravelTime": "2027-02-01T09:47:00Z",
                "load": [],
                "kind": "STOP"
              },
              {
                "id": "Stop B",
                "arrivalTime": "2027-02-01T12:39:57Z",
                "startServiceTime": "2027-02-01T12:39:57Z",
                "departureTime": "2027-02-01T13:09:57Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT12M36S",
                "travelDistanceMetersFromPreviousStandstill": 10498,
                "minStartTravelTime": "2027-02-01T09:47:00Z",
                "load": [],
                "kind": "STOP"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H26M32S",
              "travelTimeFromStartLocationToFirstStop": "PT10M21S",
              "travelTimeBetweenStops": "PT59M36S",
              "travelTimeFromLastStopToEndLocation": "PT16M35S",
              "totalTravelDistanceMeters": 72121,
              "travelDistanceFromStartLocationToFirstStopMeters": 8629,
              "travelDistanceBetweenStopsMeters": 49677,
              "travelDistanceFromLastStopToEndLocationMeters": 13815,
              "endLocationArrivalTime": "2027-02-01T13:26:32Z"
            }
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startTime": "2027-02-01T09:00:00Z",
            "pinned": true,
            "itinerary": [
              {
                "id": "Stop E",
                "arrivalTime": "2027-02-01T09:17:11Z",
                "startServiceTime": "2027-02-01T09:17:11Z",
                "departureTime": "2027-02-01T09:47:11Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT17M11S",
                "travelDistanceMetersFromPreviousStandstill": 14324,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "pinned": true,
                "kind": "STOP"
              },
              {
                "id": "Stop F",
                "arrivalTime": "2027-02-01T10:11:57Z",
                "startServiceTime": "2027-02-01T10:11:57Z",
                "departureTime": "2027-02-01T10:41:57Z",
                "effectiveServiceDuration": "PT30M",
                "travelTimeFromPreviousStandstill": "PT24M46S",
                "travelDistanceMetersFromPreviousStandstill": 20642,
                "minStartTravelTime": "2027-02-01T00:00:00Z",
                "load": [],
                "pinned": true,
                "kind": "STOP"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT57M35S",
              "travelTimeFromStartLocationToFirstStop": "PT17M11S",
              "travelTimeBetweenStops": "PT24M46S",
              "travelTimeFromLastStopToEndLocation": "PT15M38S",
              "totalTravelDistanceMeters": 47998,
              "travelDistanceFromStartLocationToFirstStopMeters": 14324,
              "travelDistanceBetweenStopsMeters": 20642,
              "travelDistanceFromLastStopToEndLocationMeters": 13032,
              "endLocationArrivalTime": "2027-02-01T10:57:35Z"
            }
          }
        ]
      }
    ],
    "unassignedJobs": []
  },
  "inputMetrics": {
    "jobs": 4,
    "stops": 8,
    "drivers": 2,
    "driverShifts": 2,
    "pinnedStops": 4
  },
  "kpis": {
    "totalTravelTime": "PT2H24M7S",
    "totalTravelDistanceMeters": 120119,
    "totalActivatedDrivers": 2,
    "totalUnassignedJobs": 0,
    "totalAssignedJobs": 4,
    "assignedMandatoryJobs": 4,
    "totalUnassignedStops": 0,
    "totalAssignedStops": 8,
    "assignedMandatoryStops": 8,
    "travelTimeFromStartLocationToFirstStop": "PT27M32S",
    "travelTimeBetweenStops": "PT1H24M22S",
    "travelTimeFromLastStopToEndLocation": "PT32M13S",
    "travelDistanceFromStartLocationToFirstStopMeters": 22953,
    "travelDistanceBetweenStopsMeters": 70319,
    "travelDistanceFromLastStopToEndLocationMeters": 26847
  }
}

modelOutput contains Carl’s and Ann’s shift itineraries.

Ann completed Stop E and Stop F. Her other jobs (Job 1 and Job 4) were reassigned to Carl.

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.

  • © 2026 Timefold BV
  • Timefold.ai
  • Documentation
  • Changelog
  • Send feedback
  • Privacy
  • Legal
    • Light mode
    • Dark mode
    • System default