Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
  • Platform
Try models
  • Field Service Routing
  • Visit service constraints
  • Visit requirements

Field Service Routing

    • Introduction
    • Planning AI concepts
    • Metrics and optimization goals
    • Getting started with field service routing
    • Understanding the API
    • Constraints
    • Vehicle resource constraints
      • Shift hours and overtime
      • Lunch breaks and personal appointments
      • Fairness
      • Technician costs
    • Visit service constraints
      • Time windows and opening hours
      • Skills
      • Visit dependencies
      • Visit requirements
      • Multi-vehicle visits
      • Priority visits and optional visits
    • 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
    • Recommendations
      • Recommendations
      • Visit time window recommendations
      • Visit group time window recommendations
    • Time zones and daylight-saving time (DST)
    • New and noteworthy
    • Upgrading to the latest versions
    • Feature requests
    • Reference guide

Visit requirements

Sometimes a specific technician is required to handle a customer visit. For instance, the visit might be one in a series of related customer visits that all need to be performed by the same technician. Alternatively, the customer might have requested a specific technician.

Prerequisites

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

  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. Vehicles required by a visit

For a customer visit that must be handled by specific technicians, for instance, Beth or Carl, specify the list of required vehicle IDs (not vehicle shifts) in the visit’s requiredVehicles attribute:

{
  "visits": [
    {
      "id": "Visit A",
      "location": [33.77301, -84.43838],
      "serviceDuration": "PT1H30M",
      "requiredVehicles": [ "Beth", "Carl" ]
    }
  ]
}

If the requiredVehicles list is empty or not specified, the visit can be assigned to any vehicle’s shift.

Any solution that assigns the visit to a vehicle ID that is not "Beth" or "Carl" will be penalized for breaking a hard constraint.

Learn about the hard and soft constraints in the Field Service Routing model.

Below is an example dataset with three vehicles and one visit that can only be assigned to Beth’s or Carl’s shifts:

  • Input

  • Output

Try this example in Timefold Platform by saving the JSON into a file called required-vehicles-example-1.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": "Required vehicles example"
    }
  },
  "modelInput": {
    "vehicles": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startLocation": [33.77301, -84.43899],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T17:00:00Z"
          }
        ]
      },
      {
        "id": "Beth",
        "shifts": [
          {
            "id": "Beth-2027-02-01",
            "startLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T09:00:00Z",
            "maxEndTime": "2027-02-01T12:30:00Z"
          }
        ]
      },
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T12:30:00Z",
            "maxEndTime": "2027-02-01T16:00:00Z"
          }
        ]
      }
    ],
    "visits": [
      {
        "id": "Visit A",
        "location": [33.77301, -84.43838],
        "serviceDuration": "PT1H30M",
        "requiredVehicles": [ "Beth", "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>
{
  "run": {
    "id": "ID",
    "name": "Required vehicles example",
    "submitDateTime": "2024-07-15T04:39:34.792750944Z",
    "startDateTime": "2024-07-15T04:39:40.233674574Z",
    "activeDateTime": "2024-07-15T04:39:40.333674574Z",
    "completeDateTime": "2024-07-15T04:39:42.884169539Z",
    "shutdownDateTime": "2024-07-15T04:39:42.984169539Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-8soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "vehicles": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [],
            "metrics": {
              "totalTravelTime": "PT0S",
              "travelTimeFromStartLocationToFirstVisit": "PT0S",
              "travelTimeBetweenVisits": "PT0S",
              "travelTimeFromLastVisitToEndLocation": "PT0S",
              "totalTravelDistanceMeters": 0,
              "travelDistanceFromStartLocationToFirstVisitMeters": 0,
              "travelDistanceBetweenVisitsMeters": 0,
              "travelDistanceFromLastVisitToEndLocationMeters": 0,
              "endLocationArrivalTime": null
            }
          }
        ]
      },
      {
        "id": "Beth",
        "shifts": [
          {
            "id": "Beth-2027-02-01",
            "startTime": "2027-02-01T09:00:00Z",
            "itinerary": [
              {
                "id": "Visit A",
                "kind": "VISIT",
                "arrivalTime": "2027-02-01T09:00:04Z",
                "startServiceTime": "2027-02-01T09:00:04Z",
                "departureTime": "2027-02-01T10:30:04Z",
                "effectiveServiceDuration": "PT1H30M",
                "travelTimeFromPreviousStandstill": "PT4S",
                "travelDistanceMetersFromPreviousStandstill": 25336,
                "minStartTravelTime": "2027-02-01T00:00:00Z"
              }
            ],
            "metrics": {
              "totalTravelTime": "PT8S",
              "travelTimeFromStartLocationToFirstVisit": "PT4S",
              "travelTimeBetweenVisits": "PT0S",
              "travelTimeFromLastVisitToEndLocation": "PT4S",
              "totalTravelDistanceMeters": 50672,
              "travelDistanceFromStartLocationToFirstVisitMeters": 25336,
              "travelDistanceBetweenVisitsMeters": 0,
              "travelDistanceFromLastVisitToEndLocationMeters": 25336,
              "endLocationArrivalTime": "2027-02-01T10:30:08Z"
            }
          }
        ]
      },
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl-2027-02-01",
            "startTime": "2027-02-01T12:30:00Z",
            "itinerary": [],
            "metrics": {
              "totalTravelTime": "PT0S",
              "travelTimeFromStartLocationToFirstVisit": "PT0S",
              "travelTimeBetweenVisits": "PT0S",
              "travelTimeFromLastVisitToEndLocation": "PT0S",
              "totalTravelDistanceMeters": 0,
              "travelDistanceFromStartLocationToFirstVisitMeters": 0,
              "travelDistanceBetweenVisitsMeters": 0,
              "travelDistanceFromLastVisitToEndLocationMeters": 0,
              "endLocationArrivalTime": null
            }
          }
        ]
      }
    ]
  },
  "kpis": {
    "totalTravelTime": "PT8S",
    "travelTimeFromStartLocationToFirstVisit": "PT4S",
    "travelTimeBetweenVisits": "PT0S",
    "travelTimeFromLastVisitToEndLocation": "PT4S",
    "totalTravelDistanceMeters": 50672,
    "travelDistanceFromStartLocationToFirstVisitMeters": 25336,
    "travelDistanceBetweenVisitsMeters": 0,
    "travelDistanceFromLastVisitToEndLocationMeters": 25336,
    "totalUnassignedVisits": 0
  }
}

modelOutput contains the itineraries with Visit A assigned to Beth.

In this example, Ann’s shift startLocation is very close to Visit A, so assigning the visit to Ann would result in minimal travel time and is a more optimal schedule. However, because Visit A requires Beth or Carl, Beth is assigned instead of Ann.

This example illustrates that requirements for specific vehicles might result in a suboptimal schedule compared to a solution where any technician could be assigned the visit.

visit assignment required vehicles

Next

  • Understand the constraints of the Field Service Routing model.

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

  • Manage shift times with Time zones and daylight-saving time (DST) changes.

  • Learn about Shift hours and overtime.

  • Send technicians with the right skills to visits.

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