Search for content

Quick Start - Route Optimization OptiFlow API

With the Route Optimization OptiFlow API, you can efficiently schedule the pickup and delivery of your orders onto routes and assign these routes to the most suitable vehicles of your fleet. Optimization is a long lasting progress that will gradually improve the solution towards your logistic challenge.

The whole process of route optimization can be summarised by the following steps:

  • Step 1 — Create and start an optimization.
  • Step 2 — Check the status and progress of the optimization.
  • Step 3(Optional) Stop the optimization once you're satisfied with the solution.
  • Step 4 — Get the optimized result.

For easy integration, you can use the clients for Java, C# and TypeScript on GitHub.

Please note the individual rate and request limits for each API. You can find all limits in our FAQ.

Get your free API Access Key

Create and start an optimization

Create an optimization request containing the relevant locations, orders, vehicles and depots. Choose an appropriate maximum duration for your optimization. Your optimization will automatically halt after this duration but can also stopped prematurely manually. Use the following endpoint via POST to create and start an optimization.

https://api.myptv.com/routeoptimization/optiflow/v1/optimizations

The following simple optimization request with two vehicles and two orders is inserted into the request body in JSON representation:

{
  "settings": {
    "duration": 60
  },
  "locations": [
    {
      "id": "WESTMINSTER_ABBEY",
      "latitude": 51.49948921972983,
      "longitude": -0.12729997630224155
    },
    {
      "id": "BUCKINGHAM_PALACE",
      "latitude": 51.50150756272127,
      "longitude": -0.14191146039830546
    },
    {
      "id": "TOWER_OF_LONDON",
      "latitude": 51.50866109220283,
      "longitude": -0.07603696962238603
    },
    {
      "id": "POSTAL_MUSEUM",
      "latitude": 51.524867174444,
      "longitude": -0.11387360545469306
    }
  ],
  "orders": {
    "deliveries": [
      {
        "id": "LETTERS_FOR_THE_KING",
        "delivery": {
          "locationId": "BUCKINGHAM_PALACE"
        }
      },
      {
        "id": "LETTERS_FOR_THE_BISHOP",
        "delivery": {
          "locationId": "WESTMINSTER_ABBEY"
        }
      }
    ]
  },
  "vehicles": [
    {
      "id": "VEHICLE_1",
      "start": {
        "locationId": "POSTAL_MUSEUM",
        "earliestStartTime": "2030-01-01T08:00:00+00:00"
      },
      "end": {
        "locationId": "POSTAL_MUSEUM",
        "latestEndTime": "2030-01-01T16:00:00+00:00"
      },
      "routing": {
        "profile": "EUR_VAN"
      },
      "costs": {
        "perHour": 40.0,
        "perKilometer": 0.42
      }
    },
    {
      "id": "VEHICLE_2",
      "start": {
        "locationId": "POSTAL_MUSEUM",
        "earliestStartTime": "2030-01-01T08:00:00+00:00"
      },
      "end": {
        "locationId": "POSTAL_MUSEUM",
        "latestEndTime": "2030-01-01T16:00:00+00:00"
      },
      "routing": {
        "profile": "EUR_VAN"
      },
      "costs": {
        "perHour": 40.0,
        "perKilometer": 0.42
      }
    }
  ],
  "depots": [
    {
      "id": "DEPOT",
      "locationId": "TOWER_OF_LONDON"
    }
  ]
}

You can test this simple optimization by choosing one of the following options.

cURL:

curl --location --request POST "https://api.myptv.com/routeoptimization/optiflow/v1/optimizations" --header "Content-Type: application/json" --header "ApiKey: YOUR_API_KEY" --data-raw "{\"settings\":{\"duration\":60},\"locations\":[{\"id\":\"WESTMINSTER_ABBEY\",\"latitude\":51.49948921972983,\"longitude\":-0.12729997630224155},{\"id\":\"BUCKINGHAM_PALACE\",\"latitude\":51.50150756272127,\"longitude\":-0.14191146039830546},{\"id\":\"TOWER_OF_LONDON\",\"latitude\":51.50866109220283,\"longitude\":-0.07603696962238603},{\"id\":\"POSTAL_MUSEUM\",\"latitude\":51.524867174444,\"longitude\":-0.11387360545469306}],\"orders\":{\"deliveries\":[{\"id\":\"LETTERS_FOR_THE_KING\",\"delivery\":{\"locationId\":\"BUCKINGHAM_PALACE\"}},{\"id\":\"LETTERS_FOR_THE_BISHOP\",\"delivery\":{\"locationId\":\"WESTMINSTER_ABBEY\"}}]},\"vehicles\":[{\"id\":\"VEHICLE_1\",\"start\":{\"locationId\":\"POSTAL_MUSEUM\",\"earliestStartTime\":\"2030-01-01T08:00:00+00:00\"},\"end\":{\"locationId\":\"POSTAL_MUSEUM\",\"latestEndTime\":\"2030-01-01T16:00:00+00:00\"},\"routing\":{\"profile\":\"EUR_VAN\"},\"costs\":{\"perHour\":40.0,\"perKilometer\":0.42}},{\"id\":\"VEHICLE_2\",\"start\":{\"locationId\":\"POSTAL_MUSEUM\",\"earliestStartTime\":\"2030-01-01T08:00:00+00:00\"},\"end\":{\"locationId\":\"POSTAL_MUSEUM\",\"latestEndTime\":\"2030-01-01T16:00:00+00:00\"},\"routing\":{\"profile\":\"EUR_VAN\"},\"costs\":{\"perHour\":40.0,\"perKilometer\":0.42}}],\"depots\":[{\"id\":\"DEPOT\",\"locationId\":\"TOWER_OF_LONDON\"}]}"

PowerShell:

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("ApiKey", "YOUR_API_KEY")
$headers.Add("Content-Type", "application/json")

$body='{"settings":{"duration":60},"locations":[{"id":"WESTMINSTER_ABBEY","latitude":51.49948921972983,"longitude":-0.12729997630224155},{"id":"BUCKINGHAM_PALACE","latitude":51.50150756272127,"longitude":-0.14191146039830546},{"id":"TOWER_OF_LONDON","latitude":51.50866109220283,"longitude":-0.07603696962238603},{"id":"POSTAL_MUSEUM","latitude":51.524867174444,"longitude":-0.11387360545469306}],"orders":{"deliveries":[{"id":"LETTERS_FOR_THE_KING","delivery":{"locationId":"BUCKINGHAM_PALACE"}},{"id":"LETTERS_FOR_THE_BISHOP","delivery":{"locationId":"WESTMINSTER_ABBEY"}}]},"vehicles":[{"id":"VEHICLE_1","start":{"locationId":"POSTAL_MUSEUM","earliestStartTime":"2030-01-01T08:00:00+00:00"},"end":{"locationId":"POSTAL_MUSEUM","latestEndTime":"2030-01-01T16:00:00+00:00"},"routing":{"profile":"EUR_VAN"},"costs":{"perHour":40.0,"perKilometer":0.42}},{"id":"VEHICLE_2","start":{"locationId":"POSTAL_MUSEUM","earliestStartTime":"2030-01-01T08:00:00+00:00"},"end":{"locationId":"POSTAL_MUSEUM","latestEndTime":"2030-01-01T16:00:00+00:00"},"routing":{"profile":"EUR_VAN"},"costs":{"perHour":40.0,"perKilometer":0.42}}],"depots":[{"id":"DEPOT","locationId":"TOWER_OF_LONDON"}]}'

try
{
    $response = Invoke-RestMethod 'https://api.myptv.com/routeoptimization/optiflow/v1/optimizations' -Method 'POST' -Headers $headers -Body $body
    $response | ConvertTo-Json -Depth 10
}
catch
{
    $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
    $streamReader.ReadToEnd() | ConvertFrom-Json
    $streamReader.Close()
}

When the request is accepted, the server returns the HTTP status code 202 and generates a unique identifier for the optimization which will be provided in the response body.

{
  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"
}

This ID is used in the following steps in the URL path, indicated as {id}.

Check the status and progress of the optimization

To check the status and progress of the optimization, the following endpoint is used via GET.

https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}

You can test the process by choosing one of the following options.

cURL:

curl --location --request GET "https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}" --header "ApiKey: YOUR_API_KEY"

PowerShell:

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("ApiKey", "YOUR_API_KEY")

$response = Invoke-RestMethod 'https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}' -Method 'GET' -Headers $headers
$response | ConvertTo-Json -Depth 10

The response contains the current status of the optimization. Following an initial PREPARING phase, the optimization status will progress to RUNNING, with the response incorporating the most optimal configuration of routes discovered up to that point. Additionally, the response will feature metrics for the current solution.

{
  "id": "5578dcf6-84a0-477a-8d49-926cbf6c863d",
  "status": "RUNNING",
  "routes": [
    {
      "vehicleId": "VEHICLE_1",
      "start": {
        "locationId": "POSTAL_MUSEUM",
        "start": "2030-01-01T08:00:00Z",
        "duration": 0,
        "departure": "2030-01-01T08:00:00Z"
      },
      "stops": [
        {
          "locationId": "TOWER_OF_LONDON",
          "approach": {
            "startLocationId": "POSTAL_MUSEUM",
            "departure": "2030-01-01T08:00:00Z",
            "endLocationId": "TOWER_OF_LONDON",
            "arrival": "2030-01-01T08:13:20Z",
            "breaks": [],
            "distance": 3867,
            "drivingDuration": 800
          },
          "arrival": "2030-01-01T08:13:20Z",
          "preparationDuration": 0,
          "appointments": [
            {
              "breaks": [],
              "waitingDuration": 0,
              "start": "2030-01-01T08:13:20Z",
              "preparationDuration": 0,
              "tasks": [
                {
                  "orderId": "LETTERS_FOR_THE_KING",
                  "type": "PICKUP",
                  "breaks": [],
                  "start": "2030-01-01T08:13:20Z",
                  "duration": 0,
                  "end": "2030-01-01T08:13:20Z",
                  "depotId": "DEPOT"
                },
                {
                  "orderId": "LETTERS_FOR_THE_BISHOP",
                  "type": "PICKUP",
                  "breaks": [],
                  "start": "2030-01-01T08:13:20Z",
                  "duration": 0,
                  "end": "2030-01-01T08:13:20Z",
                  "depotId": "DEPOT"
                }
              ],
              "end": "2030-01-01T08:13:20Z"
            }
          ],
          "departure": "2030-01-01T08:13:20Z"
        },
        {
          "locationId": "WESTMINSTER_ABBEY",
          "approach": {
            "startLocationId": "TOWER_OF_LONDON",
            "departure": "2030-01-01T08:13:20Z",
            "endLocationId": "WESTMINSTER_ABBEY",
            "arrival": "2030-01-01T08:27:30Z",
            "breaks": [],
            "distance": 4547,
            "drivingDuration": 850
          },
          "arrival": "2030-01-01T08:27:30Z",
          "preparationDuration": 0,
          "appointments": [
            {
              "breaks": [],
              "waitingDuration": 0,
              "start": "2030-01-01T08:27:30Z",
              "preparationDuration": 0,
              "tasks": [
                {
                  "orderId": "LETTERS_FOR_THE_BISHOP",
                  "type": "DELIVERY",
                  "breaks": [],
                  "start": "2030-01-01T08:27:30Z",
                  "duration": 0,
                  "end": "2030-01-01T08:27:30Z"
                }
              ],
              "end": "2030-01-01T08:27:30Z"
            }
          ],
          "departure": "2030-01-01T08:27:30Z"
        },
        {
          "locationId": "BUCKINGHAM_PALACE",
          "approach": {
            "startLocationId": "WESTMINSTER_ABBEY",
            "departure": "2030-01-01T08:27:30Z",
            "endLocationId": "BUCKINGHAM_PALACE",
            "arrival": "2030-01-01T08:33:23Z",
            "breaks": [],
            "distance": 1630,
            "drivingDuration": 353
          },
          "arrival": "2030-01-01T08:33:23Z",
          "preparationDuration": 0,
          "appointments": [
            {
              "breaks": [],
              "waitingDuration": 0,
              "start": "2030-01-01T08:33:23Z",
              "preparationDuration": 0,
              "tasks": [
                {
                  "orderId": "LETTERS_FOR_THE_KING",
                  "type": "DELIVERY",
                  "breaks": [],
                  "start": "2030-01-01T08:33:23Z",
                  "duration": 0,
                  "end": "2030-01-01T08:33:23Z"
                }
              ],
              "end": "2030-01-01T08:33:23Z"
            }
          ],
          "departure": "2030-01-01T08:33:23Z"
        }
      ],
      "end": {
        "locationId": "POSTAL_MUSEUM",
        "approach": {
          "startLocationId": "BUCKINGHAM_PALACE",
          "departure": "2030-01-01T08:33:23Z",
          "endLocationId": "POSTAL_MUSEUM",
          "arrival": "2030-01-01T08:47:17Z",
          "breaks": [],
          "distance": 4119,
          "drivingDuration": 834
        },
        "arrival": "2030-01-01T08:47:17Z",
        "duration": 0,
        "end": "2030-01-01T08:47:17Z"
      },
      "metrics": {
        "numberOfStops": 3,
        "cost": 37.47068222222222,
        "distance": 14163,
        "duration": 2837
      }
    }
  ],
  "metrics": {
    "numberOfUnscheduledOrders": 0,
    "numberOfRoutes": 1,
    "totalCost": 37.47068222222222,
    "totalDistance": 14163,
    "totalDuration": 2837
  },
  "warnings": []
}

Stopping the optimization

The optimization process will automatically conclude after running for the specified duration outlined in the optimization request settings. Nevertheless, if you are content with the current result, which can be obtained by monitoring the ongoing optimization progress, you also have the option to manually halt the optimization. Use the following endpoint via POST to manually stop the optimization.

https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}/stop

You can test to stop the optimization by choosing one of the following options.

cURL:

curl --location --request POST "https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}/stop" --header "ApiKey: YOUR_API_KEY" --header "Content-Type: application/json" --data-raw ""

PowerShell:

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("ApiKey", "YOUR_API_KEY")
$response = Invoke-RestMethod 'https://api.myptv.com/routeoptimization/optiflow/v1/optimizations/{id}/stop' -Method 'POST' -Headers $headers
$response | ConvertTo-Json -Depth 10

If the request has been successful, the server will return with HTTP status code 202 and the optimization will stop as soon as possible.

Get the optimized result

After the optimization has finished, either automatically or manually by stopping the optimization, the final result can be retrieved. The exact same request of step 2 can be repeated in order the obtain the optimization result. If the optimization is successful, the outcome will be labeled as SUCCEEDED, and the specified routes will represent the most efficient paths identified by the optimization. If an issue arises, the status will be marked as FAILED, accompanied by a response detailing the encountered error.