Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
  • Platform
Try models
  • Pick-up and Delivery Routing
  • Job service constraints
  • Stop service level agreement (SLA)

Pick-up and Delivery Routing

    • Introduction
    • Getting started: Hello world
    • User guide
      • Terms
      • Use case guide
      • Planning AI concepts
      • Integration
      • Constraints
      • Demo datasets
      • Input validation
      • Routing with Timefold’s maps service
      • Metrics and optimization goals
    • Driver resource constraints
      • Lunch breaks and personal appointments
      • Route optimization
      • Shift hours and overtime
    • Job service constraints
      • Time windows and opening hours
      • Skills
      • Movable stops and multi-day schedules
      • 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
        • Driver capacity
        • Tags
    • Real-time planning
    • Changelog
    • Upgrading to the latest versions
    • Feature requests

Stop service level agreement (SLA)

As described in the time windows guide, stops can have hard requirements for when they can be serviced. This can refer to business hours of the service location or describe the general availability of the customer on site. In addition to these hard constraints about site availability, there are often requirements regarding the latest time the stop can be completed. This requirement is called a service level agreement (SLA). This is often determined by the urgency of the incident that has been reported, and how quickly the service must be performed.

This guide describes the SLA with the following example:

  • 1. Stop SLAs

1. Stop SLAs

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 Pick-up and Delivery Routing model.

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

To define an SLA, add the property latestSlaEndTime to the stop.

{
  "jobs": [
    {
      "id": "Job A",
      "stops": [
        {
          "id": "A1",
          "location": [33.78592, -84.46136],
          "duration": "PT20M",
          "latestSlaEndTime": "2027-02-01T15:00:00Z"
        }
      ]
    }
  ]
}

latestSlaEndTime uses the ISO 8601 date and time format with offset to UTC format.

The Latest SLA end time soft constraint is invoked for any stop with a latestSlaEndTime, where the latestSlaEndTime is broken. To optimize for SLAs, the constraint adds a soft penalty to the dataset score if the stop ends after the time specified by latestSlaEndTime. The penality is derived from the time between latestSlaEndTime and when the stop ends. If a stop with a latestSlaEndTime remains unassigned and the latestSlaEndTime is within the planning window, the soft penalty will also be applied. In this case, the penalty is derived from the time between latestSlaEndTime and the end of the planning window.

Stops can still be scheduled even if doing so breaks this constraint, but Timefold is incentivized to use the route plan with the best score.

1.1. Stop SLAs example

Below is an example dataset with two drivers and one job with two stops, where one stop has a latestSlaEndTime defined:

  • 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": "Latest SLA end time example"
    }
  },
  "modelInput": {
    "drivers": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startLocation": [33.68786, -84.18487],
            "endLocation": [33.68786, -84.18487],
            "minStartTime": "2027-02-01T08:00:00Z",
            "maxEndTime": "2027-02-01T16:00:00Z"
          }
        ]
      },
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl Mon",
            "startLocation": [33.7859, -84.4613],
            "endLocation": [33.7859, -84.4613],
            "minStartTime": "2027-02-01T12:00:00Z",
            "maxEndTime": "2027-02-01T20:00:00Z"
          }
        ]
      }
    ],
    "jobs": [
      {
        "id": "Job A",
        "stops": [
          {
            "id": "A1",
            "location": [33.78592, -84.46136],
            "duration": "PT20M"
          },
          {
            "id": "A2",
            "location": [33.72757, -83.96354],
            "duration": "PT20M",
            "latestSlaEndTime": "2027-02-01T12:00:00Z",
            "stopDependencies": [
              {
                "id": "jobA_dep1",
                "precedingStop": "A1"
              }
            ]
          }
        ]
      }
    ]
  }
}
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": "Latest SLA end time example",
    "submitDateTime": "2025-12-17T10:30:21.323246+01:00",
    "startDateTime": "2025-12-17T10:30:21.345487+01:00",
    "activeDateTime": "2025-12-17T10:30:21.346208+01:00",
    "completeDateTime": "2025-12-17T10:30:51.356161+01:00",
    "shutdownDateTime": "2025-12-17T10:30:51.356163+01:00",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-6855soft",
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "drivers": [
      {
        "id": "Ann",
        "shifts": [
          {
            "id": "Ann Mon",
            "startTime": "2027-02-01T08:00:00Z",
            "itinerary": [
              {
                "id": "A1",
                "kind": "STOP",
                "arrivalTime": "2027-02-01T08:33:21Z",
                "startServiceTime": "2027-02-01T08:33:21Z",
                "departureTime": "2027-02-01T08:53:21Z",
                "effectiveServiceDuration": "PT20M",
                "travelTimeFromPreviousStandstill": "PT33M21S",
                "travelDistanceMetersFromPreviousStandstill": 27795,
                "load": []
              },
              {
                "id": "A2",
                "kind": "STOP",
                "arrivalTime": "2027-02-01T09:49:07Z",
                "startServiceTime": "2027-02-01T09:49:07Z",
                "departureTime": "2027-02-01T10:09:07Z",
                "effectiveServiceDuration": "PT20M",
                "travelTimeFromPreviousStandstill": "PT55M46S",
                "travelDistanceMetersFromPreviousStandstill": 46477,
                "load": []
              }
            ],
            "metrics": {
              "totalTravelTime": "PT1H54M15S",
              "travelTimeFromStartLocationToFirstStop": "PT33M21S",
              "travelTimeBetweenStops": "PT55M46S",
              "travelTimeFromLastStopToEndLocation": "PT25M8S",
              "totalTravelDistanceMeters": 95216,
              "travelDistanceFromStartLocationToFirstStopMeters": 27795,
              "travelDistanceBetweenStopsMeters": 46477,
              "travelDistanceFromLastStopToEndLocationMeters": 20944,
              "endLocationArrivalTime": "2027-02-01T10:34:15Z"
            }
          }
        ]
      },
      {
        "id": "Carl",
        "shifts": [
          {
            "id": "Carl Mon",
            "startTime": "2027-02-01T12:00:00Z",
            "itinerary": [],
            "metrics": {
              "totalTravelTime": "PT0S",
              "travelTimeFromStartLocationToFirstStop": "PT0S",
              "travelTimeBetweenStops": "PT0S",
              "travelTimeFromLastStopToEndLocation": "PT0S",
              "totalTravelDistanceMeters": 0,
              "travelDistanceFromStartLocationToFirstStopMeters": 0,
              "travelDistanceBetweenStopsMeters": 0,
              "travelDistanceFromLastStopToEndLocationMeters": 0
            }
          }
        ]
      }
    ],
    "unassignedJobs": []
  },
  "inputMetrics": {
    "jobs": 1,
    "stops": 2,
    "drivers": 2,
    "driverShifts": 2
  },
  "kpis": {
    "totalTravelTime": "PT1H54M15S",
    "totalTravelDistanceMeters": 95216,
    "totalActivatedDrivers": 1,
    "totalUnassignedJobs": 0,
    "totalAssignedJobs": 1,
    "assignedMandatoryJobs": 1,
    "totalUnassignedStops": 0,
    "totalAssignedStops": 2,
    "assignedMandatoryStops": 2,
    "travelTimeFromStartLocationToFirstStop": "PT33M21S",
    "travelTimeBetweenStops": "PT55M46S",
    "travelTimeFromLastStopToEndLocation": "PT25M8S",
    "travelDistanceFromStartLocationToFirstStopMeters": 27795,
    "travelDistanceBetweenStopsMeters": 46477,
    "travelDistanceFromLastStopToEndLocationMeters": 20944
  }
}

In this example, there are two drivers: Ann and Carl. Anne’s shift begins at 08:00 and Carl’s shift begins at 12:00. There is one job with two stops: stop A1 and stop A2. Stop A2 has a latestSlaEndTime of 2027-02-01T12:00:00Z. Although Carl’s location is very close to stop A1, the job gets assigned to Ann. If it had been assigned to Carl, the SLA for stop A2 would have been broken.

Next

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

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