Visit assignment restrictions
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.
Prerequisite
To run the examples in this guide, you need to authenticate with a valid API key:
-
Log in to Timefold Platform: app.timefold.ai
-
From the Dashboard, click your username, and from the drop-down menu select API Keys.
-
Copy the default API key.
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",
"completeDateTime": "2024-07-15T04:39:42.884169539Z",
"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.
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.