Lunch breaks and personal appointments

It’s important in any field service routing solution to include times when technicians can take breaks.

Technicians who work an eight-hour shift need a lunch break. They may also need to attend appointments that can’t be arranged outside their regular work hours.

There are also occasions when all technicians must attend team meetings at the same time and location.

Breaks, such as lunch breaks, can be floating breaks that fit in around the assigned visits and are taken at any location.

A technician who has an appointment, needs the appointment to be included in his schedule, and the schedule must include travel time from their last visit to the appointment and from the appointment to the next visit.

Team meetings that all technicians must attend need to provide adequate travel time for all technicians to arrive at the meeting, while still scheduling visits before and after the meeting.

Regardless of the scenario, an optimized field service routing plan will schedule customer visits, lunch breaks, appointments, team meetings, and travel between them to be a feasible solution.

This guide explains how to manage breaks with the following examples:

Prerequisites

To run the examples in this guide, you need to authenticate with a valid API key:

  1. Log in to Timefold Platform: app.timefold.ai

  2. From the Dashboard, click your username, and from the drop-down menu select API Keys.

  3. Copy the default API key.

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

The times displayed in the visualizations are approximates only.

1. Floating lunch breaks

Technician’s shifts run for a specific number of hours per day, ie, from 09:00 to 17:00, and must include a break for lunch.

Breaks have a set duration and are scheduled to occur after an earliest start time, for example, a lunch break might be scheduled to occur any time after 12:00.

In the example below, Carl completes Visit C before 12:00 (which is the earliest time he could take his lunch break), so he travels to his next visit. He arrives at the location for Visit A at 12:20. He then takes his lunch break which is scheduled for one hour. After lunch, he is on site and ready to start work at Visit A at 13:20.

vehicle floating break lunch

Breaks are added to shifts by including the requiredBreaks array:

"shifts": [
  {
    "id": "Carl-2027-02-01",
    "startLocation": [33.68786, -84.18487],
    "minStartTime": "2027-02-01T09:00:00Z",
    "maxEndTime": "2027-02-01T17:00:00Z",
    "requiredBreaks": [
      {
          "id": "carl-lunch-2027-02-01",
          "minStartTime": "2027-02-01T12:00:00Z",
          "duration": "PT1H"
      }
    ]
  }
]

At a minimum, requiredBreaks include, id, minStartTime, and duration:

  • id is a unique string that identifies the break, for instance: carl-lunch-2027-02-01 or 353.

  • minStartTime is a date and time (in ISO 8601 date time with offset to UTC format) for the earliest time the break can start.

  • duration represents the length of the break in ISO 8601 duration format.

In the following example, Carl works an eight-hour shift with a one-hour break for lunch:

  • 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": "Lunch break 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",
            "requiredBreaks": [
              {
                  "id": "Carl-lunch-2027-02-01",
                  "minStartTime": "2027-02-01T12:00:00Z",
                  "duration": "PT1H"
              }
            ]
          }
        ]
      }
    ],
    "visits": [
      {
        "id": "Visit A",
        "location": [33.77301, -84.43838],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit B",
        "location": [33.74699, -84.02504],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit C",
        "location": [33.88664, -84.28118],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit D",
        "location": [33.71030, -84.05439],
        "serviceDuration": "PT1H"
      }
    ]
  }
}
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>
{
  "run": {
    "id": "bbaf713f-e62a-4b77-9d56-269767f6d9e0",
    "name": "Lunch break example",
    "submitDateTime": "2024-09-18T01:43:43.227601124Z",
    "startDateTime": "2024-09-18T01:43:48.576942816Z",
    "completeDateTime": "2024-09-18T01:48:49.174389094Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-7148soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:27:39Z",
                "startServiceTime": "2027-02-01T09:27:39Z",
                "departureTime": "2027-02-01T10:27:39Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT27M39S",
                "travelDistanceMetersFromPreviousStandstill": 30741,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:51:08Z",
                "startServiceTime": "2027-02-01T10:51:08Z",
                "departureTime": "2027-02-01T11:51:08Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT23M29S",
                "travelDistanceMetersFromPreviousStandstill": 24210,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Carl-lunch-2027-02-01",
                "kind": "BREAK",
                "startTime": "2027-02-01T12:34:44Z",
                "endTime": "2027-02-01T13:34:44Z"
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T12:34:44Z",
                "startServiceTime": "2027-02-01T13:34:44Z",
                "departureTime": "2027-02-01T14:34:44Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT43M36S",
                "travelDistanceMetersFromPreviousStandstill": 49957,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T14:42:50Z",
                "startServiceTime": "2027-02-01T14:42:50Z",
                "departureTime": "2027-02-01T15:42:50Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT8M6S",
                "travelDistanceMetersFromPreviousStandstill": 7287,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H59M8S",
              "travelTimeFromStartLocationToFirstVisit": "PT27M39S",
              "travelTimeBetweenVisits": "PT1H15M11S",
              "travelTimeFromLastVisitToEndLocation": "PT16M18S",
              "totalTravelDistanceMeters": 127554,
              "travelDistanceFromStartLocationToFirstVisitMeters": 30741,
              "travelDistanceBetweenVisitsMeters": 81454,
              "travelDistanceFromLastVisitToEndLocationMeters": 15359,
              "endLocationArrivalTime": "2027-02-01T15:59:08Z"
            }
          }
        ]
      }
    ]
  },
  "kpis": {
    "totalTravelTime": "PT1H59M8S",
    "travelTimeFromStartLocationToFirstVisit": "PT27M39S",
    "travelTimeBetweenVisits": "PT1H15M11S",
    "travelTimeFromLastVisitToEndLocation": "PT16M18S",
    "totalTravelDistanceMeters": 127554,
    "travelDistanceFromStartLocationToFirstVisitMeters": 30741,
    "travelDistanceBetweenVisitsMeters": 81454,
    "travelDistanceFromLastVisitToEndLocationMeters": 15359,
    "totalUnassignedVisits": 0
  }
}

modelOutput contains Carl’s itinerary for the day with his scheduled lunch break.

2. Personal appointments

Sometimes, breaks are fixed and need to occur at a specific time and location, for instance, if a technician has a personal appointment, such as a visit to the dentist.

When this is the case, Timefold will schedule the break at the specified time and include travel time to the location.

In the following example, Carl has a dentist appointment at 12:00. Visit A ends at 12:30, Carl then travels to the location of his appointment, but he arrives early and must wait until the scheduled appointment at 14:00.

After his appointment, he travels to Visit B.

vehicle fixed break dentist appointment

Fixed breaks are achieved by adding a maxStartTime that is the same as the minStartTime.

Setting both minStartTime and maxStartTime to "2027-02-01T14:00:00Z" will result in the break starting at 14:00.

The location is specified in the requiredBreaks array. The plan will include travel to the location of the break and to the next visit after the break.

 "requiredBreaks": [
  {
      "id": "Carl-dentist-2027-02-01",
      "minStartTime": "2027-02-01T14:00:00Z",
      "maxStartTime": "2027-02-01T14:00:00Z",
      "duration": "PT1H",
      "location": [33.68786, -84.18487]
  }
]

In the following example, Carl has a dentist appointment at 14:00.

  • 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": "Fixed break with a location 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",
            "requiredBreaks": [
              {
                  "id": "Carl-dentist-2027-02-01",
                  "minStartTime": "2027-02-01T14:00:00Z",
                  "maxStartTime": "2027-02-01T14:00:00Z",
                  "duration": "PT1H",
                  "location": [33.79438, -84.13629]
              }
            ]
          }
        ]
      }
    ],
    "visits": [
      {
        "id": "Visit A",
        "location": [33.77301, -84.43838],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit B",
        "location": [33.74699, -84.02504],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit C",
        "location": [33.88664, -84.28118],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit D",
        "location": [33.71030, -84.05439],
        "serviceDuration": "PT1H"
      }
    ]
  }
}
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>
{
  "run": {
    "id": ID,
    "name": "Fixed break with a location example",
    "submitDateTime": "2024-09-16T09:55:41.986875415Z",
    "startDateTime": "2024-09-16T09:55:47.648560712Z",
    "completeDateTime": "2024-09-16T10:00:48.108145695Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-7070soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:16:24Z",
                "startServiceTime": "2027-02-01T09:16:24Z",
                "departureTime": "2027-02-01T10:16:24Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT16M24S",
                "travelDistanceMetersFromPreviousStandstill": 15551,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:53:08Z",
                "startServiceTime": "2027-02-01T10:53:08Z",
                "departureTime": "2027-02-01T11:53:08Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT36M44S",
                "travelDistanceMetersFromPreviousStandstill": 43191,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T12:16:37Z",
                "startServiceTime": "2027-02-01T12:16:37Z",
                "departureTime": "2027-02-01T13:16:37Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT23M29S",
                "travelDistanceMetersFromPreviousStandstill": 24210,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Carl-dentist-2027-02-01",
                "kind": "BREAK",
                "startTime": "2027-02-01T14:00:00Z",
                "endTime": "2027-02-01T15:00:00Z",
                "travelTimeFromPreviousStandstill": "PT36M34S",
                "travelDistanceMetersFromPreviousStandstill": 31230
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T15:19:33Z",
                "startServiceTime": "2027-02-01T15:19:33Z",
                "departureTime": "2027-02-01T16:19:33Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT19M33S",
                "travelDistanceMetersFromPreviousStandstill": 15307,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT2H34M24S",
              "travelTimeFromStartLocationToFirstVisit": "PT16M24S",
              "travelTimeBetweenVisits": "PT1H56M20S",
              "travelTimeFromLastVisitToEndLocation": "PT21M40S",
              "totalTravelDistanceMeters": 150711,
              "travelDistanceFromStartLocationToFirstVisitMeters": 15551,
              "travelDistanceBetweenVisitsMeters": 113938,
              "travelDistanceFromLastVisitToEndLocationMeters": 21222,
              "endLocationArrivalTime": "2027-02-01T16:41:13Z"
            }
          }
        ]
      }
    ]
  },
  "kpis": {
    "totalTravelTime": "PT2H34M24S",
    "travelTimeFromStartLocationToFirstVisit": "PT16M24S",
    "travelTimeBetweenVisits": "PT1H56M20S",
    "travelTimeFromLastVisitToEndLocation": "PT21M40S",
    "totalTravelDistanceMeters": 150711,
    "travelDistanceFromStartLocationToFirstVisitMeters": 15551,
    "travelDistanceBetweenVisitsMeters": 113938,
    "travelDistanceFromLastVisitToEndLocationMeters": 21222,
    "totalUnassignedVisits": 0
  }
}

modelOutput contains Carl’s itinerary for the day with his scheduled appointment break.

2.1. Appointments without a location

There are occasions when employees need to attend appointments, but the location of the appointment is sensitive information, for instance if they are receiving medical treatment or attending a job interview, and they do not share the location with their employer.

When the location for a fixed appointment is not provided, Timefold cannot schedule travel time.

In the following example, Carl has an appointment at 13:00, but he hasn’t provided the location.

In this case, Carl is assigned to Visit A which ends at 12:20. Without the location information, Timefold delays travel from Visit A to Visit B until after the appointment.

However, this approach may not provide enough travel time to reach the appointment, and the travel time from the appointment to Visit B is unlikely to be accurate. In such situations, it may be necessary to pad the appointment to provide additional travel time.

vehicle fixed break with private location

Sharing the location of appointments with their employer is a change for many employees who might be familiar with systems where this isn’t necessary, but if employees are comfortable sharing the location of their appointments, travel time can be included, and it becomes unnecessary to add additional time, and the schedule will include less driving time and more time available for customer visits.

3. Team meetings

When technicians are all required to attend a meeting at the same location, the meeting is added as a required break for each technician.

Timefold will schedule visits and travel throughout the day, with travel from the last visit before the meeting to the meeting, and travel from the meeting to the next visit after the meeting for each technician.

vehicle fixed break team meeting

The meeting is a fixed break that must happen at a specific time at a specific location.

minStartTime and maxStartTime are set to the same value. A duration and a location are both included.

"requiredBreaks": [
  {
      "id": "Ann-meeting-2027-02-01",
      "minStartTime": "2027-02-01T13:00:00Z",
      "maxStartTime": "2027-02-01T13:00:00Z",
      "duration": "PT2H",
      "location": [33.75812, -84.36219]
  }
]

The technicians are all attending the same team meeting, however, the requiredBreaks.id must be unique for each instance of the meeting. For instance:

  • Ann-meeting-2027-02-01

  • Beth-meeting-2027-02-01

  • Carl-meeting-2027-02-01

In the following example, Ann and Carl are both working 09:00 to 17:00 shifts, Beth is taking PTO in the morning. The team has been working hard and the team meeting has been combined with a team lunch. The meeting is taking place at 13:00 to 15:00.

  • 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": "Team meeting example"
    }
  },
  "modelInput": {
    "vehicles": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T17:00:00Z",
            "requiredBreaks": [
              {
                  "id": "Ann-meeting-2027-02-01",
                  "minStartTime": "2027-02-01T13:00:00Z",
                  "maxStartTime": "2027-02-01T13:00:00Z",
                  "duration": "PT2H",
                  "location": [33.75812, -84.36219]
              }
            ]
          }
        ]
      },
      {
        "id": "Beth",
        "shifts": [
          {
            "id": "Beth-2027-02-01",
            "startLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T12:30:00Z",
            "maxEndTime": "2027-02-01T17:00:00Z",
            "requiredBreaks": [
              {
                  "id": "Beth-meeting-2027-02-01",
                  "minStartTime": "2027-02-01T13:00:00Z",
                  "maxStartTime": "2027-02-01T13:00:00Z",
                  "duration": "PT2H",
                  "location": [33.75812, -84.36219]
              }
            ]
          }
        ]
      },
      {
        "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",
            "requiredBreaks": [
              {
                  "id": "Carl-meeting-2027-02-01",
                  "minStartTime": "2027-02-01T13:00:00Z",
                  "maxStartTime": "2027-02-01T13:00:00Z",
                  "duration": "PT2H",
                  "location": [33.75812, -84.36219]
              }
            ]
          }
        ]
      }
    ],
    "visits": [
      {
        "id": "Visit A",
        "location": [33.77301, -84.43838],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit B",
        "location": [33.74699, -84.02504],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit C",
        "location": [33.88664, -84.28118],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit D",
        "location": [33.71030, -84.05439],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit E",
        "location": [33.75790, -84.12067],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit F",
        "location": [33.72416, -84.01022],
        "serviceDuration": "PT1H"
      },
      {
        "id": "Visit G",
        "location": [33.75987, -84.17453],
        "serviceDuration": "PT1H"
      }
    ]
  }
}
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>
{
  "run": {
    "id": ID,
    "name": "Team meeting example",
    "submitDateTime": "2024-09-17T05:08:30.310476661Z",
    "startDateTime": "2024-09-17T05:08:38.367377371Z",
    "completeDateTime": "2024-09-17T05:13:38.83207233Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-11096soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit D",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:16:24Z",
                "startServiceTime": "2027-02-01T09:16:24Z",
                "departureTime": "2027-02-01T10:16:24Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT16M24S",
                "travelDistanceMetersFromPreviousStandstill": 15551,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit F",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:26:23Z",
                "startServiceTime": "2027-02-01T10:26:23Z",
                "departureTime": "2027-02-01T11:26:23Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT9M59S",
                "travelDistanceMetersFromPreviousStandstill": 7749,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Ann-meeting-2027-02-01",
                "kind": "BREAK",
                "startTime": "2027-02-01T13:00:00Z",
                "endTime": "2027-02-01T15:00:00Z",
                "travelTimeFromPreviousStandstill": "PT36M20S",
                "travelDistanceMetersFromPreviousStandstill": 41231
              },
              {
                "id": "Visit G",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T15:23:18Z",
                "startServiceTime": "2027-02-01T15:23:18Z",
                "departureTime": "2027-02-01T16:23:18Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT23M18S",
                "travelDistanceMetersFromPreviousStandstill": 19886,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H37M42S",
              "travelTimeFromStartLocationToFirstVisit": "PT16M24S",
              "travelTimeBetweenVisits": "PT1H9M37S",
              "travelTimeFromLastVisitToEndLocation": "PT11M41S",
              "totalTravelDistanceMeters": 94301,
              "travelDistanceFromStartLocationToFirstVisitMeters": 15551,
              "travelDistanceBetweenVisitsMeters": 68866,
              "travelDistanceFromLastVisitToEndLocationMeters": 9884,
              "endLocationArrivalTime": "2027-02-01T16:34:59Z"
            }
          }
        ]
      },
      {
        "id": "Beth",
        "shifts": [
          {
            "id": "Beth-2027-02-01",
            "startTime": "2027-02-01T12:30:00Z",
            "itinerary": [
              {
                "id": "Beth-meeting-2027-02-01",
                "kind": "BREAK",
                "startTime": "2027-02-01T13:00:00Z",
                "endTime": "2027-02-01T15:00:00Z",
                "travelTimeFromPreviousStandstill": "PT22M19S",
                "travelDistanceMetersFromPreviousStandstill": 22006
              },
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T15:11:44Z",
                "startServiceTime": "2027-02-01T15:11:44Z",
                "departureTime": "2027-02-01T16:11:44Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT11M44S",
                "travelDistanceMetersFromPreviousStandstill": 9137,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H3M35S",
              "travelTimeFromStartLocationToFirstVisit": "PT22M19S",
              "travelTimeBetweenVisits": "PT11M44S",
              "travelTimeFromLastVisitToEndLocation": "PT29M32S",
              "totalTravelDistanceMeters": 65127,
              "travelDistanceFromStartLocationToFirstVisitMeters": 22006,
              "travelDistanceBetweenVisitsMeters": 9137,
              "travelDistanceFromLastVisitToEndLocationMeters": 33984,
              "endLocationArrivalTime": "2027-02-01T16:41:16Z"
            }
          }
        ]
      },
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit E",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:16:26Z",
                "startServiceTime": "2027-02-01T09:16:26Z",
                "departureTime": "2027-02-01T10:16:26Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT16M26S",
                "travelDistanceMetersFromPreviousStandstill": 12102,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Visit B",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T10:32:02Z",
                "startServiceTime": "2027-02-01T10:32:02Z",
                "departureTime": "2027-02-01T11:32:02Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT15M36S",
                "travelDistanceMetersFromPreviousStandstill": 13054,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              },
              {
                "id": "Carl-meeting-2027-02-01",
                "kind": "BREAK",
                "startTime": "2027-02-01T13:00:00Z",
                "endTime": "2027-02-01T15:00:00Z",
                "travelTimeFromPreviousStandstill": "PT36M45S",
                "travelDistanceMetersFromPreviousStandstill": 40321
              },
              {
                "id": "Visit C",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T15:21:29Z",
                "startServiceTime": "2027-02-01T15:21:29Z",
                "departureTime": "2027-02-01T16:21:29Z",
                "effectiveServiceDuration": "PT1H",
                "travelTimeFromPreviousStandstill": "PT21M29S",
                "travelDistanceMetersFromPreviousStandstill": 22771,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H59M3S",
              "travelTimeFromStartLocationToFirstVisit": "PT16M26S",
              "travelTimeBetweenVisits": "PT1H13M50S",
              "travelTimeFromLastVisitToEndLocation": "PT28M47S",
              "totalTravelDistanceMeters": 117922,
              "travelDistanceFromStartLocationToFirstVisitMeters": 12102,
              "travelDistanceBetweenVisitsMeters": 76146,
              "travelDistanceFromLastVisitToEndLocationMeters": 29674,
              "endLocationArrivalTime": "2027-02-01T16:50:16Z"
            }
          }
        ]
      }
    ]
  },
  "kpis": {
    "totalTravelTime": "PT4H40M20S",
    "travelTimeFromStartLocationToFirstVisit": "PT55M9S",
    "travelTimeBetweenVisits": "PT2H35M11S",
    "travelTimeFromLastVisitToEndLocation": "PT1H10M",
    "totalTravelDistanceMeters": 277350,
    "travelDistanceFromStartLocationToFirstVisitMeters": 49659,
    "travelDistanceBetweenVisitsMeters": 154149,
    "travelDistanceFromLastVisitToEndLocationMeters": 73542,
    "totalUnassignedVisits": 0
  }
}

modelOutput contains the technicians' itineraries which include the team meeting.

Team meetings typically occur at the beginning or the end of the shift.

If the team meeting occurs at the beginning of the shift, you can use minFirstVisitArrivalTime set to the start time of the meeting so that travel time to the meeting isn’t included in the schedule.

See First travel time for more information.

If the team meeting occurs at the end of the shift, you can use maxLastVisitDepartureTime set to the end time of the meeting so that travel time home isn’t included in the schedule.

See Last travel time for more information.

Next