Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
  • Platform
Try models
  • Field Service Routing
  • Real-time planning (preview)
  • Real-time planning: technician ill (Preview)

Field Service Routing

    • Introduction
    • Getting started with field service routing
    • User guide
      • User guide
      • Terms
      • Planning AI concepts
      • Constraints
      • Understanding the API
      • Planning window
      • Model configuration
      • Configuration overrides
      • Time zones and daylight-saving time (DST)
      • Routing with Timefold’s maps service
      • Validation
      • Model response
      • Key performance indicators (KPIs)
      • Metrics and optimization goals
    • Vehicle resource constraints
      • Vehicle resource constraints
      • Shift hours and overtime
      • Lunch breaks and personal appointments
      • Fairness
      • Route optimization
      • Technician coverage area
      • Technician costs
      • Technician ratings
    • Visit service constraints
      • Visit service constraints
      • Time windows and opening hours
      • Skills
      • Visit dependencies
      • Visit requirements
      • Multi-vehicle visits
      • Movable visits and multi-day schedules
      • Priority visits and optional visits
      • Visit service level agreement (SLA)
    • Recommendations
      • Recommendations
      • Visit time window recommendations
      • Visit group time window recommendations
    • Real-time planning
      • Real-time planning
      • Real-time planning: extended visit
      • Real-time planning: reassignment
      • Real-time planning: emergency visit
      • Real-time planning: no show
      • Real-time planning: technician ill
      • Real-time planning: pinning visits
    • Real-time planning (preview)
      • Real-time planning (preview)
      • Real-time planning: extended visit (preview)
      • Real-time planning: reassignment (preview)
      • Real-time planning: emergency visit (preview)
      • Real-time planning: no show (Preview)
      • Real-time planning: technician ill (Preview)
      • Real-time planning: pinning visits (preview)
    • Scenarios
      • Long-running visits
    • Changelog
    • Upgrade to the latest version
    • Feature requests

Real-time planning: technician ill (Preview)

This guide describes features currently available as a preview feature. If you’d like early access to this feature, please Contact us. For information about the current supported feature, see Real-time planning.

There are many situations where Real-time planning (preview) is necessary.

Sometimes technicians 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:

Carl has three visits: Visit E, Visit B, and Visit D. Ann has two visits: Visit C and Visit A.

If Carl calls in sick before the shift starts or goes home part way through the day due to illness, his shifts must be reassigned to another technician or rescheduled for another day.

real time planning technician ill

Prerequisites

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 Tenant Settings, 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 current model.

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

1. Batch schedule: technician ill

The original schedule was generated from the following input dataset during batch planning:

  • 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/field-service-routing/v1/route-plans [email protected]
{
  "config": {
    "run": {
      "name": "Original shift plan: technician ill example"
    }
  },
  "modelInput": {
    "vehicles": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T17:00:00Z"
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startLocation": [33.70474, -84.06508],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T17:00:00Z"
          }
        ]
      }
    ],
    "visits": [
      {
        "id": "Visit E",
        "location": [33.84475, -84.63649],
        "serviceDuration": "PT1H30M"
      },
      {
        "id": "Visit B",
        "location": [33.90719, -84.28149],
        "serviceDuration": "PT1H30M"
      },
      {
        "id": "Visit D",
        "location":  [33.89351, -84.00649],
        "serviceDuration": "PT1H30M"
      },
      {
        "id": "Visit A",
        "location":  [33.67590, -84.11845],
        "serviceDuration": "PT1H30M"
      },
      {
        "id": "Visit C",
        "location":  [33.71517, -84.08527],
        "serviceDuration": "PT1H30M"
      }
    ]
  }
}
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/field-service-routing/v1/route-plans/<ID>
{
  "metadata": {
    "id": "ID",
    "parentId": null,
    "originId": "ID",
    "name": "Original shift plan: technician ill example",
    "submitDateTime": "2025-09-15T07:19:31.627798228Z",
    "startDateTime": "2025-09-15T07:20:10.806254314Z",
    "activeDateTime": "2025-09-15T07:20:10.868817439Z",
    "completeDateTime": "2025-09-15T07:20:41.322620578Z",
    "shutdownDateTime": "2025-09-15T07:20:41.809701203Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-11836soft",
    "tags": [
      "system.type:from-request",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit E",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:49:00Z",
                "startServiceTime": "2027-02-01T09:49:00Z",
                "departureTime": "2027-02-01T11:19:00Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT49M",
                "travelDistanceMetersFromPreviousStandstill": 54141,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T11:59:33Z",
                "startServiceTime": "2027-02-01T11:59:33Z",
                "departureTime": "2027-02-01T13:29:33Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT40M33S",
                "travelDistanceMetersFromPreviousStandstill": 42300,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T14:01:14Z",
                "startServiceTime": "2027-02-01T14:01:14Z",
                "departureTime": "2027-02-01T15:31:14Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT31M41S",
                "travelDistanceMetersFromPreviousStandstill": 34290,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT2H39M7S",
              "travelTimeFromStartLocationToFirstVisit": "PT49M",
              "travelTimeBetweenVisits": "PT1H12M14S",
              "travelTimeFromLastVisitToEndLocation": "PT37M53S",
              "totalTravelDistanceMeters": 165335,
              "travelDistanceFromStartLocationToFirstVisitMeters": 54141,
              "travelDistanceBetweenVisitsMeters": 76590,
              "travelDistanceFromLastVisitToEndLocationMeters": 34604,
              "endLocationArrivalTime": "2027-02-01T16:09:07Z"
            }
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:09:55Z",
                "startServiceTime": "2027-02-01T09:09:55Z",
                "departureTime": "2027-02-01T10:39:55Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT9M55S",
                "travelDistanceMetersFromPreviousStandstill": 6094,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:52:12Z",
                "startServiceTime": "2027-02-01T10:52:12Z",
                "departureTime": "2027-02-01T12:22:12Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT12M17S",
                "travelDistanceMetersFromPreviousStandstill": 8841,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT32M50S",
              "travelTimeFromStartLocationToFirstVisit": "PT9M55S",
              "travelTimeBetweenVisits": "PT12M17S",
              "travelTimeFromLastVisitToEndLocation": "PT10M38S",
              "totalTravelDistanceMeters": 23769,
              "travelDistanceFromStartLocationToFirstVisitMeters": 6094,
              "travelDistanceBetweenVisitsMeters": 8841,
              "travelDistanceFromLastVisitToEndLocationMeters": 8834,
              "endLocationArrivalTime": "2027-02-01T12:32:50Z"
            }
          }
        ]
      }
    ],
    "unassignedVisits": []
  },
  "inputMetrics": {
    "visits": 5,
    "visitGroups": 0,
    "vehicles": 2,
    "mandatoryVisits": 5,
    "optionalVisits": 0,
    "vehicleShifts": 2,
    "visitsWithSla": 0
  },
  "kpis": {
    "totalTravelTime": "PT3H11M57S",
    "travelTimeFromStartLocationToFirstVisit": "PT58M55S",
    "travelTimeBetweenVisits": "PT1H24M31S",
    "travelTimeFromLastVisitToEndLocation": "PT48M31S",
    "totalTravelDistanceMeters": 189104,
    "travelDistanceFromStartLocationToFirstVisitMeters": 60235,
    "travelDistanceBetweenVisitsMeters": 85431,
    "travelDistanceFromLastVisitToEndLocationMeters": 43438,
    "totalUnassignedVisits": 0,
    "totalAssignedVisits": 5,
    "assignedMandatoryVisits": 5,
    "assignedOptionalVisits": 0,
    "totalActivatedVehicles": 2,
    "workingTimeFairnessPercentage": 66.3
  },
  "run": {
    "id": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "parentId": null,
    "originId": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "name": "Original shift plan: technician ill example",
    "submitDateTime": "2025-09-15T07:19:31.627798228Z",
    "startDateTime": "2025-09-15T07:20:10.806254314Z",
    "activeDateTime": "2025-09-15T07:20:10.868817439Z",
    "completeDateTime": "2025-09-15T07:20:41.322620578Z",
    "shutdownDateTime": "2025-09-15T07:20:41.809701203Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-11836soft",
    "tags": [
      "system.type:from-request",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  }
}

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

2. Real-time planning update: technician ill

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

The following shows the input to be removed and the patch operation that will change the original input:

  • Input

  • Patch

{
  "id": "Carl",
    "shifts": [
    {
      "id": "Carl-2027-02-01",
      "startLocation": [33.68786, -84.18487],
      "minStartTime": "2027-02-01T09:00:00Z",
      "maxEndTime": "2027-02-01T17:00:00Z"
    }
  ]
}
{
  "op": "remove",
  "path": "/vehicles/[id=Carl]"
}

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

  • Patch

  • Output

Try this example in Timefold Platform by saving this JSON into a file called patch.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/field-service-routing/v1/route-plans/<ID>/from-patch [email protected]
{
  "config": {
    "run": {
      "name": "Real-time planning: technician ill example"
    }
  },
  "patch": [
    {
      "op": "remove",
      "path": "/vehicles/[id=Carl]"
    }
  ]
}
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/field-service-routing/v1/route-plans/<ID>
{
  "metadata": {
    "id": "ID",
    "name": "Real-time planning: technician ill example",
    "submitDateTime": "2025-09-15T07:36:38.891715232Z",
    "startDateTime": "2025-09-15T07:36:44.841277954Z",
    "activeDateTime": "2025-09-15T07:36:44.875963124Z",
    "completeDateTime": "2025-09-15T07:37:15.107747028Z",
    "shutdownDateTime": "2025-09-15T07:37:15.429735966Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-10000medium/-6944soft",
    "tags": [
      "system.type:from-patch",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:09:55Z",
                "startServiceTime": "2027-02-01T09:09:55Z",
                "departureTime": "2027-02-01T10:39:55Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT9M55S",
                "travelDistanceMetersFromPreviousStandstill": 6094,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T11:09:40Z",
                "startServiceTime": "2027-02-01T11:09:40Z",
                "departureTime": "2027-02-01T12:39:40Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT29M45S",
                "travelDistanceMetersFromPreviousStandstill": 24817,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T13:11:25Z",
                "startServiceTime": "2027-02-01T13:11:25Z",
                "departureTime": "2027-02-01T14:41:25Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT31M45S",
                "travelDistanceMetersFromPreviousStandstill": 34235,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T15:15:06Z",
                "startServiceTime": "2027-02-01T15:15:06Z",
                "departureTime": "2027-02-01T16:45:06Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT33M41S",
                "travelDistanceMetersFromPreviousStandstill": 35988,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H55M44S",
              "travelTimeFromStartLocationToFirstVisit": "PT9M55S",
              "travelTimeBetweenVisits": "PT1H35M11S",
              "travelTimeFromLastVisitToEndLocation": "PT10M38S",
              "totalTravelDistanceMeters": 109968,
              "travelDistanceFromStartLocationToFirstVisitMeters": 6094,
              "travelDistanceBetweenVisitsMeters": 95040,
              "travelDistanceFromLastVisitToEndLocationMeters": 8834,
              "endLocationArrivalTime": "2027-02-01T16:55:44Z"
            }
          }
        ]
      }
    ],
    "unassignedVisits": [
      "Visit E"
    ]
  },
  "inputMetrics": {
    "visits": 5,
    "visitGroups": 0,
    "vehicles": 1,
    "mandatoryVisits": 5,
    "optionalVisits": 0,
    "vehicleShifts": 1,
    "visitsWithSla": 0
  },
  "kpis": {
    "totalTravelTime": "PT1H55M44S",
    "travelTimeFromStartLocationToFirstVisit": "PT9M55S",
    "travelTimeBetweenVisits": "PT1H35M11S",
    "travelTimeFromLastVisitToEndLocation": "PT10M38S",
    "totalTravelDistanceMeters": 109968,
    "travelDistanceFromStartLocationToFirstVisitMeters": 6094,
    "travelDistanceBetweenVisitsMeters": 95040,
    "travelDistanceFromLastVisitToEndLocationMeters": 8834,
    "totalUnassignedVisits": 1,
    "totalAssignedVisits": 4,
    "assignedMandatoryVisits": 4,
    "assignedOptionalVisits": 0,
    "totalActivatedVehicles": 1,
    "workingTimeFairnessPercentage": 100
  },
  "run": {
    "id": "7e7dfc1c-6660-44f2-96d5-2a03644802ab",
    "parentId": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "originId": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "name": "Real-time planning: technician ill example",
    "submitDateTime": "2025-09-15T07:36:38.891715232Z",
    "startDateTime": "2025-09-15T07:36:44.841277954Z",
    "activeDateTime": "2025-09-15T07:36:44.875963124Z",
    "completeDateTime": "2025-09-15T07:37:15.107747028Z",
    "shutdownDateTime": "2025-09-15T07:37:15.429735966Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-10000medium/-6944soft",
    "tags": [
      "system.type:from-patch",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  }
}

modelOutput contains Ann’s updated shift itinerary.

Carl’s shifts were reassigned to Ann.

3. Real-time planning update: technician becomes ill

In this example, Carl becomes ill after starting work. He can complete his first visit, then needs to go home.

The plan must be updated part way through the day.

Carl will be going home after Visit E. Visit E ends at 11.18:56.

Update Carl’s shift by removing the original maxEndTime and adding a maxLastVisitDepartureTime to set the time Carl returns home from his last visit (Visit E).

The following shows the required input and the patch operation that will change the original input:

  • Input

  • Patch

{
 "id": "Carl",
  "shifts": [
    {
      "id": "Carl-2027-02-01",
      "startLocation": [33.68786, -84.18487],
      "minStartTime": "2027-02-01T09:00:00Z",
      "maxLastVisitDepartureTime": "2027-02-01T11:18:56Z"
    }
  ]
}
{
  "op": "remove",
  "path": "/vehicles/[id=Carl]/shifts/[id=Carl-2027-02-01]/maxEndTime"
},
{
  "op": "add",
  "path": "/vehicles/[id=Carl]/shifts/[id=Carl-2027-02-01]/maxLastVisitDepartureTime",
  "value": "2027-02-01T11:18:56Z"
}

Learn more about maxLastVisitDepartureTime in Shift hours and overtime.

The departure times for visits that have already occurred and that technicians have already begin traveling to can be frozen by adding freezeDeparturesBeforeTime and including the time when the freeze is implemented.

The following shows the required input and the patch operation that will change the original input:

  • Input

  • Patch

{
  "modelInput": {
    "freezeDeparturesBeforeTime": "2027-02-01T11:10:00Z"
  }
}
{
  "op": "add",
  "path": "/freezeDeparturesBeforeTime",
  "value": "2027-02-01T11:10:00Z"
}

Carl knows he will be going home after his visit which ends at 11:18:56 so the freezeDeparturesBeforeTime can be set to 11:10.

Submit the input dataset to generate the new real-time plan:

  • Patch

  • Output

Try this example in Timefold Platform by saving this JSON into a file called patch.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/field-service-routing/v1/route-plans/<ID>/from-patch [email protected]
{
  "config": {
    "run": {
      "name": "Real-time planning: technician becomes ill example"
    }
  },
  "patch": [
    {
      "op": "add",
      "path": "/freezeDeparturesBeforeTime",
      "value": "2027-02-01T11:10:00Z"
    },
    {
      "op": "remove",
      "path": "/vehicles/[id=Carl]/shifts/[id=Carl-2027-02-01]/maxEndTime"
    },
    {
      "op": "add",
      "path": "/vehicles/[id=Carl]/shifts/[id=Carl-2027-02-01]/maxLastVisitDepartureTime",
      "value": "2027-02-01T11:18:56Z"
    }
  ]
}
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/field-service-routing/v1/route-plans/<ID>
{
  "metadata": {
    "id": "ID",
    "parentId": "ORIGIN-ID",
    "originId": "ORIGIN-ID",
    "name": "Real-time planning: technician becomes ill example",
    "submitDateTime": "2025-09-15T07:52:12.823730247Z",
    "startDateTime": "2025-09-15T07:52:18.747761096Z",
    "activeDateTime": "2025-09-15T07:52:18.7817495Z",
    "completeDateTime": "2025-09-15T07:52:49.018604073Z",
    "shutdownDateTime": "2025-09-15T07:52:49.390741482Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "-4hard/0medium/-53252soft",
    "tags": [
      "system.type:from-patch",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit E",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:49:00Z",
                "startServiceTime": "2027-02-01T09:49:00Z",
                "departureTime": "2027-02-01T11:19:00Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT49M",
                "travelDistanceMetersFromPreviousStandstill": 54141,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H39M",
              "travelTimeFromStartLocationToFirstVisit": "PT49M",
              "travelTimeBetweenVisits": "PT0S",
              "travelTimeFromLastVisitToEndLocation": "PT50M",
              "totalTravelDistanceMeters": 111336,
              "travelDistanceFromStartLocationToFirstVisitMeters": 54141,
              "travelDistanceBetweenVisitsMeters": 0,
              "travelDistanceFromLastVisitToEndLocationMeters": 57195,
              "endLocationArrivalTime": "2027-02-01T12:09:00Z"
            }
          }
        ]
      },
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:09:55Z",
                "startServiceTime": "2027-02-01T09:09:55Z",
                "departureTime": "2027-02-01T10:39:55Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT9M55S",
                "travelDistanceMetersFromPreviousStandstill": 6094,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:52:12Z",
                "startServiceTime": "2027-02-01T10:52:12Z",
                "departureTime": "2027-02-01T12:22:12Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT12M17S",
                "travelDistanceMetersFromPreviousStandstill": 8841,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T12:55:41Z",
                "startServiceTime": "2027-02-01T12:55:41Z",
                "departureTime": "2027-02-01T14:25:41Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT33M29S",
                "travelDistanceMetersFromPreviousStandstill": 38701,
                "minStartTravelTime": "2027-02-01T11:10:00Z"
              },
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T14:57:22Z",
                "startServiceTime": "2027-02-01T14:57:22Z",
                "departureTime": "2027-02-01T16:27:22Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT31M41S",
                "travelDistanceMetersFromPreviousStandstill": 34290,
                "minStartTravelTime": "2027-02-01T11:10:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H57M34S",
              "travelTimeFromStartLocationToFirstVisit": "PT9M55S",
              "travelTimeBetweenVisits": "PT1H17M27S",
              "travelTimeFromLastVisitToEndLocation": "PT30M12S",
              "totalTravelDistanceMeters": 113418,
              "travelDistanceFromStartLocationToFirstVisitMeters": 6094,
              "travelDistanceBetweenVisitsMeters": 81832,
              "travelDistanceFromLastVisitToEndLocationMeters": 25492,
              "endLocationArrivalTime": "2027-02-01T16:57:34Z"
            }
          }
        ]
      }
    ],
    "unassignedVisits": []
  },
  "inputMetrics": {
    "visits": 5,
    "visitGroups": 0,
    "vehicles": 2,
    "mandatoryVisits": 5,
    "optionalVisits": 0,
    "vehicleShifts": 2,
    "visitsWithSla": 0
  },
  "kpis": {
    "totalTravelTime": "PT3H36M34S",
    "travelTimeFromStartLocationToFirstVisit": "PT58M55S",
    "travelTimeBetweenVisits": "PT1H17M27S",
    "travelTimeFromLastVisitToEndLocation": "PT1H20M12S",
    "totalTravelDistanceMeters": 224754,
    "travelDistanceFromStartLocationToFirstVisitMeters": 60235,
    "travelDistanceBetweenVisitsMeters": 81832,
    "travelDistanceFromLastVisitToEndLocationMeters": 82687,
    "totalUnassignedVisits": 0,
    "totalAssignedVisits": 5,
    "assignedMandatoryVisits": 5,
    "assignedOptionalVisits": 0,
    "totalActivatedVehicles": 2,
    "workingTimeFairnessPercentage": 84.48
  },
  "run": {
    "id": "065dd413-2f88-4520-8497-6cf89a208b46",
    "parentId": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "originId": "fbb54106-09f0-4f80-ab9d-8ce92d099066",
    "name": "Real-time planning: technician becomes ill example",
    "submitDateTime": "2025-09-15T07:52:12.823730247Z",
    "startDateTime": "2025-09-15T07:52:18.747761096Z",
    "activeDateTime": "2025-09-15T07:52:18.7817495Z",
    "completeDateTime": "2025-09-15T07:52:49.018604073Z",
    "shutdownDateTime": "2025-09-15T07:52:49.390741482Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "-4hard/0medium/-53252soft",
    "tags": [
      "system.type:from-patch",
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  }
}

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

Carl completed Visit E, and Visit B and Visit D were reassigned to Ann.

Next

  • See the full API spec or try the online API.

  • Learn more about field service routing from our YouTube playlist.

  • Learn about real-time planning.

  • Real-time planning with pinned visits.

  • Real-time planning with extended visits.

  • Real-time planning and emergency visits.

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