Scheduled Routes

Scheduled Routes API Overview

Plan and optimize routes for vehicle fleets while respecting service time windows, capacity limits, traffic conditions, and driver breaks. Submit a problem, retrieve an optimized solution.

The API is engineered to enhance route planning and scheduling for vehicle fleets, addressing key constraints such as service time windows, capacity limits, and traffic conditions. By leveraging the API, businesses can significantly improve delivery efficiency, reduce operational costs, and save valuable time through optimized routing and scheduling solutions.

At its core, the API solves the Vehicle Routing Problem (VRP) with pickup and delivery. This problem involves calculating the most efficient routes for a fleet to visit multiple locations to perform pickup and delivery tasks while meeting constraints like time windows, vehicle capacity, and availability.

Additionally, the API supports dynamic schedule adjustments or re-optimization. If you need to modify an existing schedule, whether due to new orders, cancellations, or other changes, you can provide an updated picture of your schedule by specifying the job statuses and vehicle locations. The API will then re-optimize the schedule to reflect these changes, ensuring continuous efficiency in your operations.

For information on how to quickly get ready and start using the API, see Get Started. Several quick tutorials are also provided in the Tutorials section.

Release history
  • v1.1 added support for route Templates.
  • v1.2 added support for flexible vehicle capacity configuration.
Start here

Quickstart

Scheduled Routes is an asynchronous API: send a routing and scheduling problem, receive a reference ID, then poll that ID until the optimized solution is ready.

1. Authenticate

Send requests with an API access token in the Authorization header.

2. Submit a problem

Use POST /raas/optimization with a problem payload.

3. Retrieve the solution

Use GET /raas/optimization/{id} until the solution is returned.

Security

Authentication

Requests use a bearer access token in the Authorization header. Replace YOUR_ACCESS_TOKEN with your generated API access token.

http header
Authorization: Bearer YOUR_ACCESS_TOKEN
Publishing-safe examples

The original source documentation contained sample bearer tokens and testing credentials. This WordPress-ready file keeps the examples and steps, but uses placeholders such as YOUR_ACCESS_TOKEN, YOUR_EMAIL, and YOUR_PASSWORD so credentials are not published accidentally.

API Lifecycle #

The API offers two key methods for managing routing and scheduling optimization:

  • Optimization POST — Submit a routing and scheduling optimization problem. After submitting a POST request, you will receive a unique reference ID.
  • Optimization GET — Retrieve the status of a submitted problem using the unique reference ID obtained from the POST method. If the optimization solution is ready, you can get the solution of the optimization problem.
Concepts

How optimization works #

To solve a routing and scheduling optimization problem for a fleet of vehicles, follow these steps:

  1. Define the Problem. Begin by outlining your problem using the format specified in the Problem section.
  2. Submit the Problem. Use the POST method, as described in Get Started, to send your problem to the API.
  3. Retrieve the Solution. Access the solution to your optimization problem by using the GET method. The format of the solution is outlined in the Solution section.

To learn more about different terminologies used in the API, see the Glossary. To see a list of frequently asked questions, see the FAQ.

POST /raas/optimization #

Use this method to submit your routing and scheduling optimization problem to the API. Once an optimization POST request is successfully submitted, the API will return a unique reference ID in the acknowledgement response. Use this unique ID to retrieve the actual solution using the Optimization GET Method (see next section).

Example request (cURL)

An example for submitting an optimization problem using the POST method with a sample token and payload. In this example, the input problem is in a file called payload.json. Replace the sample token YOUR_ACCESS_TOKEN with your own token. The schema for the input problem is defined in the Problem section.

POSTbash · curl
curl -X POST "https://iq.scheduledroutes.ddswireless.net/raas/optimization" 
     -H "Content-Type: application/json" 
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" 
     -d @payload.json

Response schema

After submitting the POST method, you will get a response message with the following format:

json · response
{
 "id": "string",
 "message": "string",
 "status": "string",
 "error" : "string"
}

If the submission is successful, the status will be 202, with the message reading "accepted" and the id representing the unique reference number for the asynchronous operation. This ID is used to track the status of the operation and retrieve results later.

If there is an error, the status will indicate an error code, the id will be zero or empty, the message will be "failure", and the error will describe the error. For more details, refer to the POST status codes below.

Example request (Windows PowerShell)

The script below demonstrates how to make a POST request using a sample payload in Windows PowerShell. It assumes the input payload is stored in a file named payload.json, and the API access token is saved in token.txt. Upon execution, the generated ID is written to id.txt. To run PowerShell, simply type PowerShell in the start menu or command line.

POSTpowershell
$token = Get-Content token.txt -Raw
$headers = @{
    Authorization = "Bearer $token"
    "Content-Type" = "application/json"
}
$body = Get-Content payload.json -Raw
$response = Invoke-RestMethod -Uri "https://iq.scheduledroutes.ddswireless.net/raas/optimization" -Method Post -Headers $headers -Body $body
$response.id | Out-File -Encoding utf8 id.txt
Write-Output $response

POST status codes

CodeDescriptionAdditional notes
202The request was accepted for processing.A reference ID is returned which you can use with a GET request to retrieve the solution once ready.
400Input validation failed (Bad Request).Missing/invalid parameter or incorrect value type. Check input data and try again.
403Unauthorized request.This occurs when authentication fails.
404Requested path not found.This happens when an incorrect path is used.
429Too many requests.Rate limit exceeded (Queries per minute or quota hit).
500Internal Service Error.Issue on our end. Contact support@ddswireless.com.

GET /raas/optimization/{id} #

Use this method to retrieve the optimized solution for the optimization tasks created using the Optimization POST Method. For this purpose, you need to specify the reference ID received from the POST method.

Example request (cURL)

An example for getting the output response of the API using the GET method with an ID. Replace ID in the URL with the ID you got from the POST method, and remember to use your own API access token.

GETbash · curl
curl -X GET "https://iq.scheduledroutes.ddswireless.net/raas/optimization/ID" 
     -H "Content-Type: application/json" 
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

For example, if ID is equal to 5, use this:

GETbash · curl
curl -X GET "https://iq.scheduledroutes.ddswireless.net/raas/optimization/5" 
     -H "Content-Type: application/json" 
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response schema

json · response
 {
  status: "string",
  message: "string",
  error: "string",
 "solution": {
      "statistics": {},
      "routes": []
      "unassigned": [],
      }  
}

If the solution is ready, statistics, routes, and unassigned will be populated based on the obtained solution. Otherwise, similar to the POST method, status, message, and error will show the status or error.

The schema for the output solution is defined in the Solution section.

Example request (Windows PowerShell)

The script below demonstrates how to make a GET request using an ID generated by the POST method. It assumes the ID is stored in a file named id.txt, and the API access token is saved in token.txt. Upon execution, the generated response is written to response.txt.

GETpowershell
$token = Get-Content token.txt -Raw
$id = Get-Content id.txt -Raw
$headers = @{
    Authorization = "Bearer $token"
    "Content-Type" = "application/json"
}

$url = "https://iq.scheduledroutes.ddswireless.net/raas/optimization/$id"

$response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
$response | ConvertTo-Json -Depth 10 | Out-File -Encoding utf8 response.txt

GET status codes

CodeDescriptionAdditional notes
200The request has succeeded.The solution is returned via statistics, routes, and unassigned.
202The request was accepted but is not yet completed.Status is pending. Check again later for solution readiness.
400Could not process the request (Bad Request).A feasible solution could not be generated due to invalid input or parameters.
401Unauthorized request.User authentication is required. No valid credentials received.
500Internal service error.Something went wrong on our side. Contact support@ddswireless.com. Fields like statistics, routes, and unassigned will be empty.
Examples

Code formats

Use the same endpoint flow in your preferred format. These examples keep the request shape from the API reference and use publishing-safe placeholders.

Submit an optimization problem

cURL
curl -X POST "https://iq.scheduledroutes.ddswireless.net/raas/optimization" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d @payload.json
Python
import json
import requests

url = "https://iq.scheduledroutes.ddswireless.net/raas/optimization"
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
}

with open("payload.json", "r", encoding="utf-8") as payload_file:
    payload = json.load(payload_file)

response = requests.post(url, headers=headers, json=payload, timeout=60)
response.raise_for_status()
print(response.json())
PowerShell
$token = Get-Content token.txt -Raw
$headers = @{
    Authorization = "Bearer $token"
    "Content-Type" = "application/json"
}
$body = Get-Content payload.json -Raw
$response = Invoke-RestMethod -Uri "https://iq.scheduledroutes.ddswireless.net/raas/optimization" -Method Post -Headers $headers -Body $body
$response.id | Out-File -Encoding utf8 id.txt
Write-Output $response

Retrieve an optimization result

cURL
curl -X GET "https://iq.scheduledroutes.ddswireless.net/raas/optimization/ID" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Python
import requests

optimization_id = "ID"
url = f"https://iq.scheduledroutes.ddswireless.net/raas/optimization/{optimization_id}"
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
}

response = requests.get(url, headers=headers, timeout=60)
response.raise_for_status()
print(response.json())
Reference

Objects

The request object is centered on problem. The response object is centered on solution. The original field references, examples, diagrams, notes, and rules are preserved below.

The Problem object #

The Problem entity represents a routing and scheduling problem. As shown in the figure below, it consists of four main components: fleet, jobs, objective, and configuration. Among these, fleet and jobs are mandatory, whereas objective and configuration are optional.

Diagram of the Problem object structure
Specifying locations

To specify a location or address in the API, use WGS84 Geo-coordinates with at least 5 decimal places for accuracy. For example, the address "1600 Amphitheatre Parkway, Mountain View, CA" has the coordinate latitude 37.423021 and longitude -122.083739. You can specify it as "location": {"lat": 37.423021, "lng": -122.083739} or as [37.423021, -122.083739].

Timestamps & time zones

The API uses ISO 8601 format for timestamps, including time zone information, to define local time for the area you require optimized routing and scheduling for. For example, 2024-07-31T14:45:30-08:00 represents July 31, 2024 at 2:45:30 PM PST, which is 8 hours behind Coordinated Universal Time (UTC).

In the input payload, you must use the same local time zone consistently. If multiple time zones are detected, the API will return an error. The times for scheduled stops in the output response will be provided in the same format as specified in the input payload. For example, if you specify 2024-07-31T14:45:30-08:00 in your input, the optimized route times in the output will also use -08:00; if you use +05:30 in the input, the output will use +05:30.

Optional attributes

All optional attributes can be omitted in the payload. Empty arrays (e.g. []) can also be used for optional attributes that accept an array.

Do not send confidential data

Ensure that no confidential or personal information is included in the data sent to the API. For example, avoid using real-life identifiers such as vehicle license plate numbers as the vehicle ID or job/task IDs.

Component summary

fleetRequired

Specifies a list of vehicles along with associated information such as shift schedules, start and end locations, breaks, capacities, and skills. For each vehicle you can define one or multiple shift schedules (start/end times and locations), one or more breaks (time window, location, and duration), one or more capacity types with available units (multidimensional units such as volume, mass, or size), and one or more skills that enable it to perform certain jobs. For example, you might assign "welding machine" and "oxygen tank" as skills for one vehicle, and "lift" as a skill for another; if a job requires a lift, only the vehicle equipped with this skill will serve it. You can also set limits such as the maximum number of stops and the maximum travel distance (in miles).

jobsRequired

Specifies a list of jobs to be served by the vehicles in the fleet. Each job can include a series of tasks, which may be only pickups, only deliveries, or both pickups and deliveries. For "visit" jobs where you need to visit a location to perform work (e.g. repairs, installing a modem), treat them as a delivery task with or without a capacity demand. For each task you can define attributes such as location, time windows, duration, capacity requirements, and necessary skills. If the optimizer cannot find a suitable ETA for a task within its specified time window, the task remains unassigned. For flexible or non-time-sensitive tasks, specify a broader time window (maximum span of 24 hours).

objectiveOptional

Determines the optimization objective or strategy. Currently three objectives are supported:

  • Minimize Total Travel Time — the default strategy; minimizes the total travel time of the fleet while completing the specified jobs.
  • Minimize Number of Routes — reduces the number of vehicles needed to complete the jobs. May lead to increased total travel time or greater workload on individual vehicles as a trade-off.
  • Balance Workload among Routes — evenly distributes the workload among all vehicles in the fleet. This balance may result in increased total travel time.
configurationOptional

Adjusts API settings or modifies default options. For example, you can specify whether to include a summary of optimization statistics (such as total travel time and distance) or a list of unassigned tasks in the API response.

Input request schema #

The schema of the input request to solve a route optimization problem is as follows. To submit a problem, this request must be included in the POST method as described in Get Started.

json · request structure
 "problem": {
      "fleet": required 
        [
          "shifts": [optional]
          "capacities": [required]
          "limits": {optional}
          "skills" : [optional]
          "id": required
          "routeTemplateId" : optional
          "maxInstances": optional   
        ],
      "jobs": required
        [
          "pickups": [...] 
          "deliveries": [...]
          "id" : required
        ]
      "objective": optional
      "configuration": {optional}
      "version": optional
    }

In a route optimization problem, a fleet of vehicles aims to serve a set of jobs efficiently. The schema above lets you define your fleet and your jobs. In the current version of the API, each job can be:

  1. Pickup tasks only — involve picking up items along the route and delivering them to the route's end location.
  2. Delivery tasks only — require delivering items that are loaded onto the vehicle at the beginning of the route.
  3. Pickup and delivery (P/D) tasks together — combine both actions, picking up something at one location and bringing it to another.
Job requirements

At least one job and one vehicle must be provided for the problem. For "visit" jobs that require going to a location (e.g. repairs, modem installations), consider them as delivery tasks, with or without a capacity requirement.

Additionally:

  1. If only the pickups object is provided for a job, it is considered a pickup-only job.
  2. If only the deliveries object is provided for a job, it is considered a delivery-only job.
  3. When both pickups and deliveries are provided, it is categorized as a pickup and delivery job.
Pickup & delivery rules

The API does not support jobs with multiple pickups and multiple deliveries. In other words, for a "pickup and delivery" job:

  • The pickups array must contain only one pickup task.
  • The deliveries array must contain only one delivery task.

The API also does not support jobs with no pickups and no deliveries. Classification rules:

  • If only pickups is defined, the job is classified as a pickup-anchored job.
  • If only deliveries is defined, the job is classified as a delivery-anchored job.
  • If both pickup and delivery are defined, the anchor is the one that contains a service window.
  • If both pickup and delivery have service windows, the job is considered pickup-anchored.

For each task, various attributes and constraints can be defined, such as capacity demands, service time windows, and required skills. Visit tasks, where you need to visit specific locations to perform tasks (e.g. repairs), can be seen as a specialized form of delivery task (with or without capacity requirements). Tasks are assigned to vehicles whose capacities or skill sets match the task's requirements. For example, if a task requires a lift or ladder, only vehicles equipped with a lift or ladder will be used to perform that task.

problem — field reference

problem Required   Specifies the routing and scheduling optimization problem you would like to solve. It consists of the attributes below.

fleet

fleet Required   Defines the fleet information. It is an array of fleet objects. Each fleet object consists of the following attributes:

idintegerRequired

A unique identifier for the vehicle.

shiftsarrayOptional

An array of shift objects. Each shift object contains data for the shift start and end locations and times, as well as an array of break objects each containing break start and end locations and times. Multiple shift objects can be defined but they must be disjoint. Elements in each shift object:

start

The shift start time and start location.

  • timeoptional. Specifies the shift start time. If not specified, defaults to 00:00:00 (midnight) of the current date.
  • locationoptional. The Geo-coordinate (latitude and longitude) of the start location. Specify as an array [A,B] (A = latitude, B = longitude) or as {"lat": A,"lng": B}.
end

The shift end time and end location.

  • timeoptional. Specifies the shift end time. If not specified, defaults to 23:59:00 of the current date.
  • locationoptional. The Geo-coordinate of the end location. Specify as [A,B] or {"lat": A,"lng": B}.
breaks array Optional
  • serviceWindowrequired if breaks is used. The time period in which the break can happen.
  • durationrequired if breaks is used. An integer defining the duration of the break in seconds.
  • locationoptional. The location of the break, as [A,B] or {"lat": A,"lng": B}. If the location is omitted the break is "floating", meaning it can be taken anywhere at the convenience of the driver.

Example — shifts

json
"shifts": [{
  "start": {
    "time": "2020-07-04T09:00:00-08:00",
    "location": {"lat": 52.46642, "lng": 13.28124}
  },
  "end": {
    "time": "2020-07-04T18:00:00-08:00",
    "location": [54.21981, 14.01237]
  },
  "breaks": [
    {
      "serviceWindow": ["2020-07-04T12:00:05-08:00","2020-07-04T14:05:05-08:00"],
      "duration": 1200,
      "location": {"lat": 53.70645, "lng": 12.34156}
    },
    {
      "serviceWindow": ["2020-07-04T16:00:00-08:00","2020-07-04T16:45:00-08:00"],
      "duration": 600,
      "location": {"lat": 51.46642, "lng": 12.28124}
    }
    ]
  }]
capacitiesarrayRequired

An array of capacity objects. Each capacity object is a key-value object defined with the following keys:

  • namerequired. A string specifying the name of the capacity type (e.g. "wheelchair", "box", "seat", "bin").
  • unitsrequired. An integer specifying the available units of the capacity type.

For example, if a vehicle has a capacity for 2 seats and 20 packages, you can define its capacity as follows:

json
    "capacities": [
        {
        "name": "seat",
        "units": 2,
        },
        {
        "name": "package",
        "units": 20,
        }        
      ]
skillsarray of stringsOptional

A list of vehicle skills or equipment, each represented by an arbitrary string specific to your application. This allows you to customize the capabilities of your vehicles to match the requirements of the jobs they serve. Example: "skills": ["lift","fridge","oxygen tank"]

limitsobjectOptional

Specifies constraints applied to the vehicle.

  • maxDistanceoptional. An integer specifying the maximum distance limitation for the vehicle in miles.
  • maxStopsoptional. An integer defining the maximum number of stops (pickup or delivery tasks) the vehicle can serve in one shift.
  • lifoDepthoptional. An integer defining the LIFO (Last In First Out) depth of the vehicle.
json
  "limits": {
    "lifoDepth" : 1,
    "maxDistance": 3000,
    "maxStops" : 20,
  }
lastKnownLocationobjectRe-optimization only

Specifies the last known location of the vehicle at the specified time. This information is crucial for re-optimizing an ongoing route to account for new changes such as broken vehicles, late jobs, new jobs, or canceled jobs. When re-optimizing an existing schedule, you need to provide the location of all involved vehicles.

json
"lastKnownLocation": {
      "location": {"lat":53.45612, "lng":12.65421},
      "time" : "2020-07-04T12:00:05-08:00"
      }
routeTemplateIdintegerOptional

A unique identifier used to define a route template. The API supports the concept of "Route Templates", which allow you to define the specifications for a particular vehicle type and request the API to generate a specific number of such vehicles for optimization. A route template contains the same information as a route or vehicle, but you can specify a "size" parameter called maxInstances for it. For instance, suppose you have 100 vehicles. You might define 2 or 3 route templates:

  1. Shift 6am–6pm, capacity 4, size = 60
  2. Shift 1pm–1am, capacity 4, size = 50
  3. Shift 6am–8pm, capacity 10, size = 35

This means the API can automatically instantiate up to 60 vehicles using template 1 as needed, 5 with template 2, and 35 with template 3.

maxInstancesintegerOptional

If routeTemplateId is provided, maxInstances specifies how many route templates should be generated based on the specified route template.

Rules for id, routeTemplateId, and maxInstances
  • Exactly one of id or routeTemplateId must be used, never both.
  • id and maxInstances cannot be used together.
  • If both routeTemplateId and maxInstances are provided, the API uses the route template model to generate routes.

jobs

jobs At least one required   An array of job objects. Each job object has the following attributes:

idintegerRequired

A unique identifier for the job.

pickupsarray of Task ObjectsOptional

An array of Task Objects, each defining a pickup task.

deliveriesarray of Task ObjectsOptional

An array of Task Objects, each defining a delivery (or drop-off) task.

Job pickup & delivery configuration
  • The API does not support jobs with multiple pickups and multiple deliveries.
  • The API does not support jobs with no pickups and no deliveries.
  • If only pickups is specified, the job is classified as a pickup-anchored job.
  • If only deliveries is specified, the job is classified as a delivery-anchored job.
  • If a job has both a pickup and a delivery, the anchor is determined by the task that defines a service window.
  • If both tasks have service windows, the job is treated as a pickup-anchored job.

The Task Object

Each Task Object consists of the following attributes:

idintegerRequired

A unique identifier for the task.

locationobject or arrayRequired

A key-value object that specifies the Geo-coordinates (latitude and longitude) of the location where the task must be performed. Specify as an array [A,B] (A = latitude, B = longitude) or as {"lat": A,"lng": B}.

json
"location": {"lat": 52.46642, "lng": 13.28124}
"location": [52.46642, 13.28124]
serviceWindowsarrayOptional / Required

Specifies the service time window for performing the task (required or optional depending on the use case; see pickups and deliveries above). The service window is an array of the form [A, B] where A and B are the start and end times. The API will attempt to produce an ETA within the specified window; if this is not possible, the task is listed as unassigned. Times A and B define the earliest and latest times by which a task must be completed by a vehicle. For flexible or non-time-sensitive tasks, use an arbitrarily large window (max 24 hours) to give the API more flexibility in scheduling other tasks. The current version of the API supports only one service window per task. For pickups-only and deliveries-only tasks, the service window is required.

json
"serviceWindows": ["2024-08-30T09:00:00-08:00",
                   "2024-08-30T21:00:00-08:00"]
durationinteger or objectRequired

Specifies the duration of the task in seconds. It can be either an integer or a key-value object with the following keys:

  • fixed — the fixed duration (seconds) for the job (e.g. for finding parking, lowering the lift).
  • service — the service duration (seconds) for doing the job.
json
"duration": 1950
   OR
"duration": {"fixed":150, "service": 1800}
demandarrayOptional

An array of capacity demands for the task. The structure of each demand object is identical to that of the capacity object in the fleet entity. Each capacity item consists of a name (string) and its units (integer). The specified names must match those defined in the capacity object of the fleet entity. For example, if a job requires capacity for two seats and 20 packages:

json
"demand": [
    {
    "name": "seat",
    "units": 2,
    },
    {
    "name": "package",
    "units": 20,
    }        
  ]
skillsarray of stringsOptional

An array of skills or equipment required to perform the task, each represented by an arbitrary string specific to your application. Only vehicles whose skill set matches the skill set of the task will be considered for performing the task. These skills are matched to the skills defined in the fleet entity. Example: "skills": ["lift", "ladder", "welding machine"]

statusstringRe-optimization only

A string specifying the status of the task: pending, in_progress, or performed. This is crucial for re-optimizing an ongoing route. For new tasks or tasks not yet performed, set it to pending. If the task is already performed, set it to performed. If the vehicle has already arrived at the location and the task is underway, set it to in_progress. The default value is pending. Example: "status": "pending"

vehicleIdintegerRe-optimization only

Specifies the assigned vehicle ID for already-scheduled tasks. This is crucial for re-optimizing an ongoing route. The default value is zero. For new tasks, set it to zero. For existing tasks already assigned to a vehicle, set this attribute to the assigned vehicle ID. Example: "vehicleId": 12

etatimestampRe-optimization only

Specifies the current ETA (estimated time of arrival) for already-scheduled jobs. This is crucial for re-optimizing an ongoing route. The default value is 0. For new or performed tasks, set it to 0; for existing pending tasks, set it to the existing ETA. Example: "eta": "2021-07-04T12:13:00-08:00"

objective

objective integer Optional   Specifies the optimization objective (strategy). Default is 1.

ValueStrategy
1Minimize Total Travel Time (default)
2Minimize Number of Routes
3Balance Workload Among Routes

Example: "objective": 1

configuration

configuration Optional   Used to specify additional settings or configurations.

polylineTypestringOptional

Specifies the type of output polyline returned for each scheduled route. One of none, plain, encoded. If none, no polylines are included. If plain, an ordered list of intersections to travel between each pair of consecutive stops is returned. If encoded, the polyline is compressed into a string format you can provide to third-party navigation APIs such as Google Maps for turn-by-turn instructions. The default value is none.

unassignedTasksbooleanOptional

A flag that determines whether unassigned tasks must be included in the output response. Default is False. If for any reason the API cannot assign a task to a route, it will list it as unassigned.

statisticsbooleanOptional

A flag that determines whether the optimization statistics must be included in the output solution. Default is True.

unitsstringOptional

Specifies the units for the output statistics and the fleet limits. Either metric or imperial. The default value is metric.

maxRideTablearrayOptional

Defines the maximum onboard time for all jobs. It is defined by a static table in which each row is an array containing three time values (in minutes): [A, B, C]. This means if the direct travel time for a job is between A and B, the maximum onboard time equals "rideTime + C". For example, a simple table with two rows: "maxRideTable":[[0, 10, 30], [11, 20, 40]]. Default is [[0, 300, 720]]. Overlap and gaps are not allowed in this table, and the granularity is minutes.

enforceLockedTasksbooleanOptional

Controls how the optimization engine handles previously assigned jobs during re-optimization. Default is false.

When set to true, all jobs already assigned to a vehicle in the re-optimization payload are treated as locked and must remain on their current vehicle. The engine will only optimize and assign new jobs that do not already have a vehicle assignment.

When set to false, the engine is allowed to modify existing assignments during re-optimization. Previously assigned jobs may be removed from their original vehicle if the assignment is no longer valid or optimal. For example, a job originally scheduled for 8:00 AM may be removed during a 10:00 AM re-optimization because the task can no longer be completed within its constraints.

vehicleCapacitiesobjectOptional

Vehicle capacity definitions can be named and then used in the fleet section. This is particularly useful for complex definitions when a vehicle can have many configurations. For example, if a vehicle can fit either (10 'ambulatory' and 0 'wheelchair' passengers) OR (8 'ambulatory' and 1 'wheelchair' passengers) you could define "vehicleCapacities":{"flexBus": [[{"name": "ambulatory", "units": 10}], [{"name": "ambulatory", "units": 8},{"name":"wheelchair", "units": 1}]]}. Then in the fleet property you can use fleet[<index>].capacities: "flexBus" for each flexBus in the fleet. Named vehicle capacities can also be saved in your personal customer profile, where they become available for use without having to define them in the configuration section. If a named vehicle capacity is present in both your personal profile and the payload, the definition in the payload takes precedence.

freezeWindowLengthinteger (minutes)Optional

The freeze window length in minutes. A freeze window is a concept that only applies to same-day optimization and is useful when re-optimizing a problem. For example, if you have already optimized a problem but want to make changes in the middle of the day, you could re-send the problem (with appropriate task.status to reflect what has already been done) and set a freeze window of 60 minutes. This instructs the optimizer that the time period extending 60 minutes from "now" is off-limits: no tasks can be added to or removed from any route within the freeze window.

lifoConstrainedCapacitiesarrayOptional

An array of capacity types that are subject to the LIFO (Last In, First Out) constraint. Example: "lifoConstrainedCapacities": ['wheelchair', 'scooter']

Example — configuration

json
"configuration": 
{
      "polylineType": "plain",
      "unassignedTasks": False,
      "statistics": True,
}

version

version Optional   Specifies the version of the API. Default is 1.0.

More examples

To see various examples of a Problem and learn how to use the API in different use cases (e.g. re-optimization), see Tutorials.

Identifiers & time constraints

1. Unique identifiers. All jobs must have unique IDs. All tasks must have unique IDs. All vehicles must have unique IDs. A job may share its ID with a task or vehicle — this is allowed.

2. Time constraints. Each problem may include multiple time-related elements, such as task service windows and vehicle shifts. The API determines the minimum time across all values. For example, if the minimum is 2024-09-18T04:32:00-08:00, the maximum is computed by finding midnight on the day the minimum occurs and adding 33 hours to that timestamp. So in this example, the max allowed time is 2024-09-19T09:00:00-08:00. If any time in the problem (e.g. vehicle shift or task window) exceeds this, the API will return a 400 error.

The Solution

The Solution object #

Once you submit a problem via the POST method, you receive a unique reference ID. Use this reference ID with the GET method to retrieve the status of the submitted problem. If the optimization solution is ready, you can access it in the solution entity of the response. As shown in the figure below, the solution entity is composed of three main parts:

statistics

Includes various metrics that provide an overview of the entire solution across all routes, allowing you to evaluate its effectiveness (for example, the total travel distance for all optimized routes). By analyzing these statistics you can measure the quality and efficiency of the produced solution.

routes

Contains the optimized routes along with their stops and estimated times of arrival (ETA). It can also include the polyline of each route.

unassigned

Contains the list of unassigned tasks. If the API cannot assign a task to a route during optimization, it is listed as unassigned. It can include reasons for why each task remains unassigned, providing insight into the constraints or issues that prevented assignment.

Diagram of the Solution object structure

Output solution schema #

The template of the solution provided in the output response of the API is as follows:

json · solution
 "solution": {
      "statistics": {},
      "routes": []
      "unassigned": [],
      }  

The solution entity represents the solution of the route optimization problem and consists of the attributes described below.

statistics

Contains the statistics of the entire solution. It consists of the following properties:

distance
  • totalDistance — the total distance traveled by the entire fleet, including the distance from each vehicle's start location to its end location.
  • revenueDistance — the total revenue distance traveled by the entire fleet, including the distance from the first stop to the last stop for each vehicle. It does not include the distance from the vehicle's start location to the first stop or from the last stop to the vehicle's end location.
vehicles
  • used — the number of used vehicles in the solution to perform the scheduled jobs/tasks.
  • unused — the number of unused vehicles.
jobs
  • scheduledTasks — the number of scheduled tasks.
  • unassignedTasks — the number of unassigned tasks.
times
  • totalHours — the total travel hours for the entire fleet, including time spent traveling from each vehicle's start location to its end location.
  • revenueHours — the total revenue hours traveled by the entire fleet, including the time taken from the first stop to the last stop for each vehicle. It does not include time traveling from the vehicle's start location to the first stop or from the last stop to the vehicle's end location.

Example — statistics

json
"statistics": {
    "distance": {
        "totalDistance": 42,
        "revenueDistance": 25
    },
    "vehicles": {
        "used": 2,
        "unused": 0
    },
    "jobs": {
        "scheduledTasks": 3,
        "unassignedTasks": 0
    },
    "times": {
        "totalHours": 11.6,
        "revenueHours": 10.8
    }
}

routes

Provides an array of the scheduled route for each vehicle. Each scheduled route contains:

vehicleIdinteger

The ID of the assigned vehicle.

shiftsarray

An array of shift objects. The API supports multiple shifts for each vehicle. Each shift object consists of:

  • index — the index of the shift (integer).
  • stops — an array of all stops to be performed by the vehicle on this shift.

Each stop has the following properties:

  • ordinal — the stop's position within the vehicle schedule, represented by its index (integer).
  • jobId — the job ID related to this stop (integer).
  • taskId — the task ID related to this stop (integer).
  • type — the type of task performed at this stop ("pickup" or "delivery").
  • location — the Geo-coordinates of the location of the stop.
  • eta — the estimated time of arrival for the stop (in the same time zone as the input payload).
  • timeToNext — the driving time to the next stop. For example, if you drop off a passenger at 9:00am and your next job is at 10:00, this tells you the driving time from the current stop to the next stop is 20 mins.
  • distanceToNext — the driving distance to the next stop. Depending on the chosen units in the configuration, this can represent miles or meters.
  • waitTime — how long the driver should wait at the next stop if they start driving now.
  • polyline — the polyline connecting the stop to its preceding stop. If "plain" is specified in the configuration, the polyline is an ordered list of intersections to travel between the preceding stop and the current stop. If "encoded" is specified, the plain polyline is encoded and returned as an encoded string.
  • break — if the scheduled stop is for a break, it represents the ID of the break. Other stops do not have this element. The API does not enforce that breaks (or jobs) be listed in chronological order.

Example — routes

json
       "routes": [
            {
                "vehicleId": 1,
                "shifts": [
                    {
                        "index": 1,
                        "stops": [
                            {
                                "break": 1,
                                "start": "2023-10-01T10:00:00-08:00",
                                "end": "2023-10-01T10:15:00-08:00",
                                "timeToNext": 15,
                                "distanceToNext": 7.3,
                                "waitTime": 0,
                                "polyline": null,
                                "ordinal": 1
                            },
                            {
                                "jobId": 4,
                                "taskId": 5,
                                "type": "pickup",
                                "location": [
                                    50.70816,
                                    -120.37796
                                ],
                                "eta": "2023-10-01T10:30:00-08:00",
                                "timeToNext": 13,
                                "distanceToNext": 5.6,
                                "waitTime": 112,
                                "polyline": null,
                                "ordinal": 2
                            },
                            {
                                "jobId": 4,
                                "taskId": 6,
                                "type": "delivery",
                                "location": [
                                    50.66559,
                                    -120.36924
                                ],
                                "eta": "2023-10-01T12:45:00-08:00",
                                "timeToNext": 4,
                                "distanceToNext": 1.7,
                                "waitTime": 71,
                                "polyline": null,
                                "ordinal": 3
                            },
                            {
                                "break": 2,
                                "start": "2023-10-01T14:00:00-08:00",
                                "end": "2023-10-01T14:15:00-08:00",
                                "timeToNext": 7,
                                "distanceToNext": 3.2,
                                "waitTime": 217,
                                "polyline": null,
                                "ordinal": 4
                            }
                        ]
                    }
                ]
            },
            {
                "vehicleId": 2,
                "shifts": [
                    {
                        "index": 1,
                        "stops": [
                            {
                                "break": 1,
                                "start": "2023-10-01T11:00:00-08:00",
                                "end": "2023-10-01T11:15:00-08:00",
                                "timeToNext": 3,
                                "distanceToNext": 1.2,
                                "waitTime": 267,
                                "polyline": null,
                                "ordinal": 1
                            },
                            {
                                "jobId": 10,
                                "taskId": 11,
                                "type": "pickup",
                                "location": [
                                    50.65187,
                                    -120.40052
                                ],
                                "eta": "2023-10-01T15:45:00-08:00",
                                "timeToNext": 12,
                                "distanceToNext": 6.4,
                                "waitTime": 0,
                                "polyline": null,
                                "ordinal": 2
                            },
                            {
                                "jobId": 10,
                                "taskId": 12,
                                "type": "delivery",
                                "location": [
                                    50.69262,
                                    -120.35412
                                ],
                                "eta": "2023-10-01T16:22:00-08:00",
                                "timeToNext": 6,
                                "distanceToNext": 2.7,
                                "waitTime": 91,
                                "polyline": null,
                                "ordinal": 3
                            }
                        ]
                    }
                ]
            }
        ]

unassigned

The optional unassigned task list is populated with tasks which cannot be assigned due to specific constraints. Each item consists of a job ID, a task ID, and possible unassignment reasons (a code plus a description):

id
  • job — the job ID (integer) of the unassigned task.
  • task — the ID (integer) of the unassigned task.
reason

An array of possible reasons for the unassigned tasks.

  • code — the code (integer) of the possible reason.
  • description — the description (string) of the possible reason.
json
{
  "unassigned": [
    {
      "id": {
        "job": 2,
        "task": 1
      },
      "reason": [
        {
          "code": 2,
          "description": "Not enough capacity for this job"
        }
      ]
    },
    {
      "id": {
        "job": "31",
        "task": "2"
      },
      "reason": [
        {
          "code": 5,
          "description": "The service time of the job is out of the shift hours"
        }
      ]
    }
  ]
}

Errors and Status Codes #

As described in Get Started, the API supports both POST and GET methods. Depending on the method, it returns a status code in the output response. Below are the descriptions of the status codes for these two methods.

POST status codes

CodeDescriptionAdditional notes
202The request was accepted for processing.A reference ID is returned which can be used with a GET request to retrieve the solution once it is ready.
400Input validation failed (Bad Request).One or more parameters are missing, invalid, or incorrectly typed. Please correct the input data and resubmit the request.
403Invalid authentication credentials or insufficient permissions.The request was understood, but the client is not authorized due to missing or incorrect permissions.
404Requested path not found.This error occurs when the requested URL path does not match any valid endpoint.
429Too many requests.The QPM (Queries Per Minute) or request quota has been exceeded. The client must slow down request frequency.
500Internal Service error.There was a server-side issue with the API. Contact support@ddswireless.com for assistance.

GET status codes

CodeDescriptionAdditional notes
200The request has succeeded.The problem was solved successfully. Results are returned via statistics, routes, and unassigned.
202The request was accepted but it is not completed yet (pending status).Solution is not ready yet. You will need to check back later.
400Could not process the request (Bad Request).A feasible solution could not be generated for the provided locations or parameters.
401Unauthorized request.The request requires user authentication. The server did not receive proper credentials.
500Internal Service error.There was a server-side issue with our API. Please contact support@ddswireless.com. The fields statistics, routes, and unassigned will be empty.
Tutorials

Guides / Tutorials #

Here you will find various examples demonstrating how to use the API. The API primarily supports two main use cases:

  1. Planning and Scheduling — generates an optimized schedule for a fleet's tours, considering constraints related to jobs and vehicles.
  2. Re-optimization — modifies an existing or ongoing schedule to reflect changes such as new jobs, cancellations, or broken vehicles.

Explore the examples below to see how these use cases are implemented:

  • Example 1 — Planning a simple pickup and delivery (drop-off) scenario.
  • Example 2 — A simple re-optimization scenario for adding new jobs to an existing schedule.
  • Example 3 — Re-optimization with cancelled jobs.
  • Example 4 — Re-optimization with broken vehicles.
Note

The locations mentioned in the following examples are fictional and randomly generated, and do not correspond to real places.

Example 1 · Planning

Planning a simple pickup and delivery scenario

A fleet of 2 vehicles serving 3 pickup and delivery jobs, optimized to minimize total travel time.

In this example, our fleet consists of 2 vehicles and we have 3 pickup and delivery jobs that must be served by the two vehicles. Here are the details for each vehicle:

Vehicle 1

  • Shift details: The shift starts on 2024-10-01 at 8:00 AM PST from location (50.67293, -120.34195) and ends at 6:00 PM at the same location. The time zone is PST, so the start time is recorded as 2024-10-01T08:00:00-08:00 and the end time as 2024-10-01T18:00:00-08:00.
  • Breaks: Two breaks, each lasting 15 minutes. First break between 10:00 AM and 10:30 AM at location (50.6531, -120.38393); second break between 2:00 PM and 2:30 PM at location (50.6531, -120.38393).
  • Capacity: 15 seats and 5 cargo.
  • Skills: Equipped with a lift and air conditioning.

Vehicle 2

  • Shift details: The shift starts on 2024-10-01 at 8:00 AM PST from location (50.7117, -120.39286) and ends at 6:00 PM at location (50.67698, -120.32012).
  • Breaks: One 15-minute break between 11:00 AM and 11:30 AM at location (50.6531, -120.38393).
  • Capacity: 10 seats and 8 cargo.
  • Skills: Equipped with a lift only.

We also have three "pickup and delivery" jobs in Kamloops, BC, Canada. Here are the details of each job:

Job 1

  • Pickup: Location (50.65391, -120.37365). Service window 9:00 AM to 9:30 AM (the job is pickup-anchored, and the pickup must be performed within this window). Duration 10 minutes. Requirements: 1 seat, 2 cargo, vehicle equipped with a lift.
  • Delivery: Location (50.69409, -120.35425). Duration 5 minutes.

Job 2

  • Pickup: Location (50.70816, -120.37796). Duration 5 minutes. Requirements: 1 seat, vehicle equipped with both a lift and air conditioning.
  • Delivery: Location (50.66559, -120.36924). Service window 12:45 PM to 1:30 PM (the job is delivery-anchored, and the delivery must be performed within this window). Duration 5 minutes.

Job 3

  • Pickup: Location (50.70393, -120.37263). Service window 2:00 PM to 2:30 PM (the job is pickup-anchored). Duration 10 minutes. Requirements: 1 seat, 3 cargo, no specific equipment required.
  • Delivery: Location (50.69028, -120.39028). Duration 5 minutes.

Our goal is to assign these jobs to the defined vehicles so that the total travel time is minimized. In other words, our optimization objective is equal to 1. The input problem is as follows:

Input problem (payload)

json · payload
{
    "problem": {
        "fleet": [
            {
                "id": 1,
                "shifts": [
                    {
                        "start": {
                            "time": "2023-10-01T08:00:00-08:00",
                            "location": {
                                "lat": 50.67293,
                                "lng": -120.34195
                            }
                        },
                        "end": {
                            "time": "2023-10-01T18:00:00-08:00",
                            "location": {
                                "lat": 50.67293,
                                "lng": -120.34195
                            }
                        },
                        "breaks": [
                            {
                                "serviceWindow": [
                                    "2023-10-01T10:00:00-08:00",
                                    "2023-10-01T10:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            },
                            {
                                "serviceWindow": [
                                    "2023-10-01T14:00:00-08:00",
                                    "2023-10-01T14:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            }
                        ]
                    }
                ],
                "capacities": [
                    {
                        "name": "seat",
                        "units": 15
                    },
                    {
                        "name": "cargo",
                        "units": 5
                    }
                ],
                "skills": [
                    "lift",
                    "air_conditioner"
                ]
            },
            {
                "id": 2,
                "shifts": [
                    {
                        "start": {
                            "time": "2023-10-01T08:00:00-08:00",
                            "location": {
                                "lat": 50.7117,
                                "lng": -120.39286
                            }
                        },
                        "end": {
                            "time": "2023-10-01T18:00:00-08:00",
                            "location": {
                                "lat": 50.67698,
                                "lng": -120.32012
                            }
                        },
                        "breaks": [
                            {
                                "serviceWindow": [
                                    "2023-10-01T11:00:00-08:00",
                                    "2023-10-01T11:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            }
                        ]
                    }
                ],
                "capacities": [
                    {
                        "name": "seat",
                        "units": 10
                    },
                    {
                        "name": "cargo",
                        "units": 8
                    }
                ],
                "skills": [
                    "lift"
                ]
            }
        ],
        "jobs": [
            {
                "id": 1,
                "pickups": [
                    {
                        "id": 2,
                        "location": [
                            50.65391,
                            -120.37365
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T09:00:00-08:00",
                                "2023-10-01T09:30:00-08:00"
                            ]
                        ],
                        "duration": 600,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 2
                            }
                        ],
                        "skills": [
                            "lift"
                        ]
                    }
                ],
                "deliveries": [
                    {
                        "id": 3,
                        "location": [
                            50.69409,
                            -120.35425
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 2
                            }
                        ],
                        "skills": [
                            "lift"
                        ]
                    }
                ]
            },
            {
                "id": 4,
                "pickups": [
                    {
                        "id": 5,
                        "location": [
                            50.70816,
                            -120.37796
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            }
                        ],
                        "skills": [
                            "lift",
                            "air_conditioner"
                        ]
                    }
                ],
                "deliveries": [
                    {
                        "id": 6,
                        "location": [
                            50.66559,
                            -120.36924
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T12:45:00-08:00",
                                "2023-10-01T13:30:00-08:00"
                            ]
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            }
                        ],
                        "skills": [
                            "lift",
                            "air_conditioner"
                        ]
                    }
                ]
            },
            {
                "id": 7,
                "pickups": [
                    {
                        "id": 8,
                        "location": [
                            50.70393,
                            -120.37263
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T14:00:00-08:00",
                                "2023-10-01T14:30:00-08:00"
                            ]
                        ],
                        "duration": 600,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 3
                            }
                        ]
                    }
                ],
                "deliveries": [
                    {
                        "id": 9,
                        "location": [
                            50.69028,
                            -120.39028
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 3
                            }
                        ]
                    }
                ]
            }
        ],
        "objective": 1,
        "configuration": {
            "polylineType": "none",
            "unassignedTasks": true,
            "units": "imperial",
            "statistics": true
        }
    }
}

After submitting this problem using the POST method (as described in Get Started), we get the following solution using the GET method:

Output solution

json · solution
{
    "id": 8193,
    "status": 200,
    "solution": {
        "statistics": {
            "distance": {
                "totalDistance": 54,
                "revenueDistance": 36
            },
            "vehicles": {
                "used": 2,
                "unused": 0
            },
            "jobs": {
                "scheduledTasks": 3,
                "unassignedTasks": 0
            },
            "times": {
                "totalHours": 9.4,
                "revenueHours": 8.7
            }
        },
        "routes": [
            {
                "vehicleId": 1,
                "shifts": [
                    {
                        "index": 1,
                        "stops": [
                            {
                                "jobId": 1,
                                "taskId": 2,
                                "type": "pickup",
                                "location": [
                                    50.65391,
                                    -120.37365
                                ],
                                "eta": "2023-10-01T09:00:00-08:00",
                                "timeToNext": 10,
                                "distanceToNext": 4.9,
                                "waitTime": 0,
                                "polyline": null,
                                "ordinal": 1
                            },
                            {
                                "jobId": 1,
                                "taskId": 3,
                                "type": "delivery",
                                "location": [
                                    50.69409,
                                    -120.35425
                                ],
                                "eta": "2023-10-01T09:25:00-08:00",
                                "timeToNext": 10,
                                "distanceToNext": 5.4,
                                "waitTime": 25,
                                "polyline": null,
                                "ordinal": 2
                            },
                            {
                                "break": 1,
                                "start": "2023-10-01T10:00:00-08:00",
                                "end": "2023-10-01T10:15:00-08:00",
                                "timeToNext": 15,
                                "distanceToNext": 7.3,
                                "waitTime": 0,
                                "polyline": null,
                                "ordinal": 3
                            },
                            {
                                "jobId": 4,
                                "taskId": 5,
                                "type": "pickup",
                                "location": [
                                    50.70816,
                                    -120.37796
                                ],
                                "eta": "2023-10-01T10:30:00-08:00",
                                "timeToNext": 13,
                                "distanceToNext": 5.6,
                                "waitTime": 112,
                                "polyline": null,
                                "ordinal": 4
                            },
                            {
                                "jobId": 4,
                                "taskId": 6,
                                "type": "delivery",
                                "location": [
                                    50.66559,
                                    -120.36924
                                ],
                                "eta": "2023-10-01T12:45:00-08:00",
                                "timeToNext": 4,
                                "distanceToNext": 1.7,
                                "waitTime": 71,
                                "polyline": null,
                                "ordinal": 5
                            },
                            {
                                "break": 2,
                                "start": "2023-10-01T14:00:00-08:00",
                                "end": "2023-10-01T14:15:00-08:00",
                                "timeToNext": 7,
                                "distanceToNext": 3.2,
                                "waitTime": 217,
                                "polyline": null,
                                "ordinal": 6
                            }
                        ]
                    }
                ]
            },
            {
                "vehicleId": 2,
                "shifts": [
                    {
                        "index": 1,
                        "stops": [
                            {
                                "break": 1,
                                "start": "2023-10-01T11:00:00-08:00",
                                "end": "2023-10-01T11:15:00-08:00",
                                "timeToNext": 13,
                                "distanceToNext": 6.6,
                                "waitTime": 152,
                                "polyline": null,
                                "ordinal": 1
                            },
                            {
                                "jobId": 7,
                                "taskId": 8,
                                "type": "pickup",
                                "location": [
                                    50.70393,
                                    -120.37263
                                ],
                                "eta": "2023-10-01T14:00:00-08:00",
                                "timeToNext": 14,
                                "distanceToNext": 4.6,
                                "waitTime": 0,
                                "polyline": null,
                                "ordinal": 2
                            },
                            {
                                "jobId": 7,
                                "taskId": 9,
                                "type": "delivery",
                                "location": [
                                    50.69028,
                                    -120.39028
                                ],
                                "eta": "2023-10-01T14:29:00-08:00",
                                "timeToNext": 13,
                                "distanceToNext": 3.9,
                                "waitTime": 197,
                                "polyline": null,
                                "ordinal": 3
                            }
                        ]
                    }
                ]
            }
        ],
        "unassigned": []
    },
    "message": "success"
}
Example 2 · Re-optimization

Adding new jobs to an existing schedule

Re-optimize a partially executed schedule at 11:36:34 to incorporate a newly received job.

Now consider the previous example. Assume that you have started performing the produced schedule since the morning, and now it is 11:36:34, and you get a new job order as follows:

Job 4 (a new job)

  • Pickup: Location (50.65187, -120.40052). Service window 15:45 to 16:15 (a pickup-anchored job). Duration 15 minutes. Requirements: 1 seat, 1 cargo.
  • Delivery: Location (50.69262, -120.35412). Duration 10 minutes.

You have already performed Job 1, but Job 2 and Job 3 are still in progress with the following details:

  • Job 1: performed.
  • Job 2: in progress. Pickup — current vehicle ID 1, ETA 10:30. Delivery — current vehicle ID 1, ETA 12:45.
  • Job 3: in progress. Pickup — current vehicle ID 2, ETA 14:00. Delivery — current vehicle ID 2, ETA 14:29.

Since Job 2 and Job 3 are in progress, they have an associated vehicle ID and ETA. To re-optimize your schedule to include the new job (Job 4), provide an updated view of your current schedule through the API. This includes details about your jobs as follows:

  • Job 1: already performed, so set the status of the pickup and delivery tasks to "status":"performed". You do not need to provide the current vehicle ID and ETA for these tasks as they are already performed and cannot be changed.
  • Job 2: still in progress and assigned to vehicle 1 with pickup ETA = 10:30 and delivery ETA = 12:45. Include "status": "in_progress", "vehicleId": 1, and the corresponding eta for its pickup and delivery tasks.
  • Job 3: still in progress and assigned to vehicle 2 with pickup ETA = 14:00 and delivery ETA = 14:29. Include "status": "in_progress", "vehicleId": 2, and the corresponding eta for its pickup and delivery tasks.
  • Job 4: a new job, not scheduled yet, so set its status to "status":"pending". You do not need to specify a vehicle ID or ETA. After re-optimization you will get a vehicle ID and an ETA for each task of this job.

You also need to provide the last known location of your vehicles so the API has an updated picture of your current schedule. Suppose the last known locations at 11:36:34 (the time we want to re-optimize) are: Vehicle 1: (50.66692, -120.35293) and Vehicle 2: (50.65324, -120.37398). Include a lastKnownLocation object with the location and time for each vehicle.

To do re-optimization, you can now submit your new optimization problem as follows:

Re-optimization payload

json · payload
{
    "problem": {
        "fleet": [
            {
                "id": 1,
                "shifts": [
                    {
                        "start": {
                            "time": "2023-10-01T08:00:00-08:00",
                            "location": {
                                "lat": 50.67293,
                                "lng": -120.34195
                            }
                        },
                        "end": {
                            "time": "2023-10-01T18:00:00-08:00",
                            "location": {
                                "lat": 50.67293,
                                "lng": -120.34195
                            }
                        },
                        "breaks": [
                            {
                                "serviceWindow": [
                                    "2023-10-01T10:00:00-08:00",
                                    "2023-10-01T10:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            },
                            {
                                "serviceWindow": [
                                    "2023-10-01T14:00:00-08:00",
                                    "2023-10-01T14:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            }
                        ]
                    }
                ],
                "capacities": [
                    {
                        "name": "seat",
                        "units": 15
                    },
                    {
                        "name": "cargo",
                        "units": 5
                    }
                ],
                "skills": [
                    "lift",
                    "air_conditioner"
                ],
                "lastKnownLocation":{
                         "location":[50.66692,-120.35293],
                         "time":"2024-10-01T11:36:34-08:00"
               }                 
            },
            {
                "id": 2,
                "shifts": [
                    {
                        "start": {
                            "time": "2023-10-01T08:00:00-08:00",
                            "location": {
                                "lat": 50.7117,
                                "lng": -120.39286
                            }
                        },
                        "end": {
                            "time": "2023-10-01T18:00:00-08:00",
                            "location": {
                                "lat": 50.67698,
                                "lng": -120.32012
                            }
                        },
                        "breaks": [
                            {
                                "serviceWindow": [
                                    "2023-10-01T11:00:00-08:00",
                                    "2023-10-01T11:30:00-08:00"
                                ],
                                "duration": 900,
                                "location": {
                                    "lat": 50.6531,
                                    "lng": -120.38393
                                }
                            }
                        ]
                    }
                ],
                "capacities": [
                    {
                        "name": "seat",
                        "units": 10
                    },
                    {
                        "name": "cargo",
                        "units": 8
                    }
                ],
                "skills": [
                    "lift"
                ],
                "lastKnownLocation":{
                         "location":[50.65324,-120.37398],
                         "time":"2024-10-01T11:36:34-08:00"
               }                 
            }
        ],
        "jobs": [
            {
                "id": 1,
                "pickups": [
                    {
                        "id": 2,
                        "location": [
                            50.65391,
                            -120.37365
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T09:00:00-08:00",
                                "2023-10-01T09:30:00-08:00"
                            ]
                        ],
                        "duration": 600,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 2
                            }
                        ],
                        "skills": [
                            "lift"
                        ],
                        "status": "performed"
                    }
                ],
                "deliveries": [
                    {
                        "id": 3,
                        "location": [
                            50.69409,
                            -120.35425
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 2
                            }
                        ],
                        "skills": [
                            "lift"
                        ],
                        "status": "performed"
                    }
                ]
            },
            {
                "id": 4,
                "pickups": [
                    {
                        "id": 5,
                        "location": [
                            50.70816,
                            -120.37796
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            }
                        ],
                        "skills": [
                            "lift",
                            "air_conditioner"
                        ],
                        "status": "in_progress",
                        "vehicleId": 1,
                        "eta": "2023-10-01T10:30:00-08:00"
                    }
                ],
                "deliveries": [
                    {
                        "id": 6,
                        "location": [
                            50.66559,
                            -120.36924
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T12:45:00-08:00",
                                "2023-10-01T13:30:00-08:00"
                            ]
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            }
                        ],
                        "skills": [
                            "lift",
                            "air_conditioner"
                        ],
                        "status": "in_progress",
                        "vehicleId": 1,
                        "eta": "2023-10-01T12:45:00-08:00"
                    }
                ]
            },
            {
                "id": 7,
                "pickups": [
                    {
                        "id": 8,
                        "location": [
                            50.70393,
                            -120.37263
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T14:00:00-08:00",
                                "2023-10-01T14:30:00-08:00"
                            ]
                        ],
                        "duration": 600,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 3
                            }
                        ],
                        "status": "in_progress",
                        "vehicleId": 2,
                        "eta": "2023-10-01T14:00:00-08:00"                        
                    }
                ],
                "deliveries": [
                    {
                        "id": 9,
                        "location": [
                            50.69028,
                            -120.39028
                        ],
                        "duration": 300,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 3
                            }
                        ],
                        "status": "in_progress",
                        "vehicleId": 2,
                        "eta": "2023-10-01T14:29:00-08:00"                       
                    }
                ]
            },
            {
                "id": 10,
                "pickups": [
                    {
                        "id": 11,
                        "location": [
                            50.65187,
                            -120.40052
                        ],
                        "serviceWindows": [
                            [
                                "2023-10-01T15:45:00-08:00",
                                "2023-10-01T16:15:00-08:00"
                            ]
                        ],
                        "duration": 900,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 1
                            }
                        ],
                        "status": "pending"
                    }
                ],
                "deliveries": [
                    {
                        "id": 12,
                        "location": [
                            50.69262,
                            -120.35412
                        ],
                        "duration": 600,
                        "demand": [
                            {
                                "name": "seat",
                                "units": 1
                            },
                            {
                                "name": "cargo",
                                "units": 1
                            }
                        ],
                        "status": "pending"
                    }
                ]
            }

        ],
        "objective": 1,
        "configuration": {
            "polylineType": "none",
            "unassignedTasks": true,
            "units": "imperial",
            "statistics": true
        }
    }
}
Example 3 · Re-optimization

Re-optimization with cancelled jobs

Remove cancelled jobs from an in-place schedule and re-optimize the remainder.

If you've submitted an optimization problem for a set of jobs and already have a schedule in place, but some jobs have been cancelled, you can re-optimize your schedule by removing the cancelled jobs from the problem. To do this, you'll need to:

  • Provide an updated picture of your remaining jobs and the last known locations of your vehicles, similar to Example 2.
  • Create and submit a revised problem reflecting these changes.

Once submitted, you will receive a new schedule that accounts for the updated jobs and fleet status.

Example 4 · Re-optimization

Re-optimization with broken vehicles

Reassign the work of a vehicle that has broken down mid-shift.

Suppose it's 8:00 AM and you use the API to generate an optimized schedule for your jobs with 10 vehicles. You begin executing the schedule, but at 9:14 AM you learn that one of your vehicles has broken down and can no longer perform its assigned jobs. To re-optimize the schedule, follow these steps:

  1. Update fleet information. Remove the broken vehicle from your fleet object.
  2. Provide vehicle locations. Submit the last known locations of the remaining vehicles, similar to Example 2.
  3. Update task status. Provide the status of all tasks: specify which tasks are already performed, which are in progress, and which are new or pending. For tasks in progress, include the associated vehicle ID and ETA.
  4. Handle tasks for the broken vehicle. Change the status of all tasks previously assigned to the broken vehicle to "pending". This allows the API to reassign them to other available vehicles and recalculate their ETAs.
  5. Submit for re-optimization. Submit the updated problem to the API for a new schedule optimization.

How to test Scheduled Routes #

Step 1 — Generate an access token

First send a POST request to the following URL to get an access token, using the credentials below.

POST request body for Vancouver (Tenant 2):

json · request body
{
    "plugin": "internal;basic",
    "internal": {
        "email": "YOUR_EMAIL",
        "password": "YOUR_PASSWORD",
        "tenantId": 2
    },
    "basic": {
        "username": "YOUR_EMAIL",
        "password": "YOUR_PASSWORD",
        "tenantId": 2
    }
}

POST request body for Finland (Tenant 3):

json · request body
{
    "plugin": "internal;basic",
    "internal": {
        "email": "YOUR_EMAIL",
        "password": "YOUR_PASSWORD",
        "tenantId": 3
    },
    "basic": {
        "username": "YOUR_EMAIL",
        "password": "YOUR_PASSWORD",
        "tenantId": 3
    }
}

Then, copy the generated token. Here is a screenshot of this step:

Screenshot of generating an access token

Step 2 — Send an input payload (optimization problem) to the API

To send an input payload to the API and get a reference ID, put the generated token in the "Authorization" part of the following POST request, and put the input payload in the "Body" part of the request.

A sample input payload:

json · payload
{
  "problem": {
    "fleet": [
      {
        "id": 1,
        "shifts": [
          {
            "start": {
              "time": "2023-10-01T08:00:00-08:00",
              "location": { "lat": 50.67293, "lng": -120.34195 }
            },
            "end": {
              "time": "2023-10-01T18:00:00-08:00",
              "location": { "lat": 50.67293, "lng": -120.34195 }
            },
            "breaks": [
              {
                "serviceWindow": ["2023-10-01T10:00:00-08:00", "2023-10-01T10:30:00-08:00"],
                "duration": 900,
                "location": { "lat": 50.6531, "lng": -120.38393 }
              },
              {
                "serviceWindow": ["2023-10-01T14:00:00-08:00", "2023-10-01T14:30:00-08:00"],
                "duration": 900,
                "location": { "lat": 50.6531, "lng": -120.38393 }
              }
            ]
          }
        ],
        "capacities": [
          {
            "name": "seat",
            "units": 15
          },
          {
            "name": "baggage",
            "units": 5
          }
        ],
        "skills": ["lift", "air_conditioner"]
      },
      {
        "id": 2,
        "shifts": [
          {
            "start": {
              "time": "2023-10-01T08:00:00-08:00",
              "location": { "lat": 50.7117, "lng": -120.39286 }
            },
            "end": {
              "time": "2023-10-01T18:00:00-08:00",
              "location": { "lat": 50.67698, "lng": -120.32012 }
            },
            "breaks": [
              {
                "serviceWindow": ["2023-10-01T11:00:00-08:00", "2023-10-01T11:30:00-08:00"],
                "duration": 900,
                "location": { "lat": 50.6531, "lng": -120.38393 }
              }
            ]
          }
        ],
        "capacities": [
          {
            "name": "seat",
            "units": 10
          },
          {
            "name": "baggage",
            "units": 8
          }
        ],
        "skills": ["lift"]
      }
    ],
    "jobs": [
      {
        "id": 1,
        "pickups": [
          {
            "id": 2,
            "location": [50.65391, -120.37365],
            "serviceWindows": [["2023-10-01T09:00:00-08:00", "2023-10-01T09:30:00-08:00"]],
            "duration": 600,
            "demand": [
              {
                "name": "seat",
                "units": 1
              },
              {
                "name": "baggage",
                "units": 2
              }
            ],
            "skills": ["lift"]
          }
        ],
        "deliveries": [
          {
            "id": 3,
            "location": [50.69409, -120.35425],
            "duration": 300,
            "demand": [
              {
                "name": "seat",
                "units": 1
              },
              {
                "name": "baggage",
                "units": 2
              }
            ],
            "skills": ["lift"]
          }
        ]
      },
      {
        "id": 4,
        "pickups": [
          {
            "id": 5,
            "location": [50.70816, -120.37796],
            "duration": 300,
            "demand": [
              {
                "name": "seat",
                "units": 1
              }
            ],
            "skills": ["lift", "air_conditioner"]
          }
        ],
        "deliveries": [
          {
            "id": 6,
            "location": [50.66559, -120.36924],
            "serviceWindows": [["2023-10-01T12:45:00-08:00", "2023-10-01T13:30:00-08:00"]],
            "duration": 300,
            "demand": [
              {
                "name": "seat",
                "units": 1
              }
            ],
            "skills": ["lift", "air_conditioner"]
          }
        ]
      },
      {
        "id": 7,
        "pickups": [
          {
            "id": 8,
            "location": [50.70393, -120.37263],
            "serviceWindows": [["2023-10-01T14:00:00-08:00", "2023-10-01T14:30:00-08:00"]],
            "duration": 600,
            "demand": [
              {
                "name": "seat",
                "units": 1
              },
              {
                "name": "baggage",
                "units": 3
              }
            ]
          }
        ],
        "deliveries": [
          {
            "id": 9,
            "location": [50.69028, -120.39028],
            "duration": 300,
            "demand": [
              {
                "name": "seat",
                "units": 1
              },
              {
                "name": "baggage",
                "units": 3
              }
            ]
          }
        ]
      }
    ],
    "objective": 1,
    "configuration": {
        "polylineType": "none",
        "unassignedTasks": true,
        "units" : "imperial",
        "statistics" : true
    }
  }
}

If the POST method is successful, you get a reference ID by which you can retrieve the output response via the GET method. Below is a screenshot of this step:

Screenshot of submitting an input payload

Step 3 — Get the output response of the API call

To get the output response using the received reference ID, put the access token in the "Authorization" part of the following GET request, and include the reference ID in the URL.

Here is a screenshot of this step:

Screenshot of retrieving the output response
Reference

Glossary #

TermDefinition
problemA routing and scheduling optimization problem to be solved by the API.
solutionThe solution of the routing and scheduling optimization problem provided by the API.
fleetA fleet specifies a list of vehicle types and their information.
jobA list of delivery or pickup and delivery tasks that must be performed by a specific vehicle.
taskA task is part of a job and is to be performed at a specific location and time.
breakAn attribute to define one or multiple break times for drivers at specific locations.
demandTask capacity requirement represented in multidimensional units (e.g., volume, mass).
durationThe amount of time used for performing a task or a break.
shiftsDefines vehicle schedules, including start/end times, locations, and potential breaks.
deliveryA job task for delivering something loaded earlier in the tour.
pickup and deliveryA job where both pickup and delivery places are specified.
skillsVehicle skills needed to serve certain tasks (e.g., equipment, size requirements).
service windowA time range within which a task must be completed.
start/end locationWhere a vehicle departs from or returns to (e.g., depot or garage).
start/end timeDefines timing for shifts, breaks, departures, or tasks.
locationThe latitude and longitude of an address in WGS84 format.
re-optimizationUpdating an active schedule due to changes like new/cancelled orders.
ID (or id)A unique identifier for a job, task, or vehicle.
VRPVehicle Routing Problem.
CVRPCapacitated Vehicle Routing Problem.
PDPPickup and Delivery Problem.
limitsConstraints applied to a vehicle type.
objectiveThe optimization strategy used to solve the problem.
statisticsStatistics of the optimized routes returned in the solution.
stopA list of activities performed at a specific time/place along a route.
unassigned jobs/tasksJobs/tasks that could not be assigned to a route.
ETAEstimated Time of Arrival. Provided for all stops in the output.
polylineA connected line path representing a route on the map.
encoded polylineA compressed string version of a polyline, used to minimize data size (e.g., _kv~uF|y~wGdkZ~gAx|]t@).
Reference

FAQ #

QuestionAnswer
Does the API support solving Pickup and Delivery Problem (PDP)?Yes, see the Tutorials section for the detailed explanation.
Does the API support open PDP?Yes, you can define arbitrary start and end locations for each vehicle in your fleet.
Does the API utilize real-time traffic data?Yes, it uses both historical and real-time traffic data.
Can I define vehicle shift timings, start/end locations, and breaks?Yes, see the fleet object of the Problem page.
Can we define multiple arbitrary capacity types for vehicles?Yes, the capacity attribute in the fleet object supports multiple dimensions like weight, volume, and quantity.
Can we specify the max number of tasks per vehicle?Yes, this can be defined using the fleet object of the Problem page.
Does the API support multiple breaks per vehicle?Yes, supported via the fleet object in the Problem page.
Does the API support pickups, deliveries, or both?Yes, see the jobs object in the Problem documentation.
Can I specify task duration?Yes, use the duration attribute in the jobs object of the Problem.
Can I define arbitrary task capacity demands?Yes, supported via the jobs object in the Problem definition.
Can we define a service time window per task?Yes, specify earliest and latest start times using time windows in jobs object.
Can I define skills or traits required for each task?Yes, traits are supported in the jobs object and help match tasks to qualified vehicles or drivers.
Does the API support re-optimization for ongoing routes?Yes, see Tutorials for how to re-optimize in-progress solutions.
Does the API provide route and schedule statistics?Yes, see Solution for detailed stats like travel time, distance, and unassigned jobs.
Does the API explain why tasks were unassigned?Yes, see Solution for reasons behind unassigned jobs.
Does the API return estimated arrival times?Yes, see Solution for ETAs per task.
Can the API cluster jobs by location?Yes, clustering is supported to improve route efficiency.
Can I choose different optimization objectives?Yes. Options include: Minimize Total Travel Time, Minimize Number of Routes, and Balance Workload among Routes. See Problem for more details.

Scheduled Routes — Routing & Scheduling API. Need help? Contact support@ddswireless.com.

v1.1 added support for route templates. v1.2 added support for flexible vehicle capacity configuration.