Skip to content

Endpoints

Base URL

https://opt.route.optimiser.app/v2

Use this URL as the base for all requests on this page.

Synchronous Route Optimisation API

POST https://opt.route.optimiser.app/v2/vrp

A synchronous endpoint for Route Optimisation requests. The request blocks until the optimization completes and returns the full solution immediately. Multi-shift requests use this same endpoint; see Multi-Shift.

Example Request

Request Body
{
  "drivers": [
    {
      "uid": "drvid1",
      "shift_start": 8,
      "shift_end": 17,
      "start": {"lat": -33.867798, "lon": 151.166256},
      "end": "start"
    }
  ],
  "jobs": [
    {
      "uid": "uid1",
      "duration": 2,
      "location": {"lat": -33.849489, "lon": 151.127482}
    },
    {
      "uid": "uid2",
      "duration": 2,
      "location": {"lat": -33.880661, "lon": 151.183096}
    },
    {
      "uid": "uid3",
      "duration": 2,
      "location": {"lat": -33.913168, "lon": 151.262267}
    }
  ],
  "settings": {}
}
Request
TOKEN={your_tarot_routing_token}
curl https://opt.route.optimiser.app/v2/vrp \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      --data "@ex1.json"
Request
import json, requests

token = 'Your Tarot Routing Token'

with open('ex1.json') as f:
   body = json.load(f)

r = requests.post(
   url='https://opt.route.optimiser.app/v2/vrp',
   headers={'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token},
   json=body,
)

Example Response

Response Body
{
    "runs": [
        {
            "driver": {
                "uid": "drvid1",
                "shift_start": "08:00:00",
                "shift_end": "17:00:00",
                "run": 1,
                "seq": 0,
                "location": {
                    "lon": 151.166256,
                    "lat": -33.867798
                },
                "end_location": {
                    "lon": 151.166256,
                    "lat": -33.867798
                }
            },
            "jobs": [
                {
                    "uid": "uid1",
                    "duration": 120,
                    "eta": "08:09:45",
                    "etd": "08:11:45",
                    "run": 1,
                    "seq": 1,
                    "location": {
                        "lon": 151.127482,
                        "lat": -33.849489
                    }
                },
                {
                    "uid": "uid2",
                    "duration": 120,
                    "eta": "08:24:12",
                    "etd": "08:26:12",
                    "run": 1,
                    "seq": 2,
                    "location": {
                        "lon": 151.183096,
                        "lat": -33.880661
                    }
                },
                {
                    "uid": "uid3",
                    "duration": 120,
                    "eta": "08:42:32",
                    "etd": "08:44:32",
                    "run": 1,
                    "seq": 3,
                    "location": {
                        "lon": 151.262267,
                        "lat": -33.913168
                    }
                }
            ]
        }
    ],
    "unserved_jobs": []
}

Asynchronous Route Optimisation API

Use this API for long-running optimization problems. It follows a Post and Poll pattern:

  1. POST to start the optimization and receive a unique ID
  2. GET the status endpoint to check progress
  3. GET the solution endpoint to retrieve the final solution

Start Optimisation

POST https://opt.route.optimiser.app/v2/polling/vrp

Starts an asynchronous optimization. Returns immediately with a 202 Accepted response containing URLs for polling status and retrieving the solution.

Request Body

Use the same RoutingProblem format as the synchronous endpoint. A multi-shift request uses this same body: put multi_shift on every Driver instead of shift_start / shift_end. See Multi-Shift.

Request Body
{
  "drivers": [
    {
      "uid": "drvid1",
      "shift_start": 8,
      "shift_end": 17,
      "start": {"lat": -33.867798, "lon": 151.166256},
      "end": "start"
    }
  ],
  "jobs": [
    {
      "uid": "uid1",
      "duration": 2,
      "location": {"lat": -33.849489, "lon": 151.127482}
    },
    {
      "uid": "uid2",
      "duration": 2,
      "location": {"lat": -33.880661, "lon": 151.183096}
    },
    {
      "uid": "uid3",
      "duration": 2,
      "location": {"lat": -33.913168, "lon": 151.262267}
    }
  ],
  "settings": {}
}
Request
TOKEN={your_tarot_routing_token}
curl https://opt.route.optimiser.app/v2/vrp \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      --data "@ex1.json"
Request
import json, os, requests, sys, time
from datetime import datetime
from zoneinfo import ZoneInfo

start_optimisation_url = 'https://opt.dev.route.optimiser.app/v0.40/polling/vrp'
auth_url = 'https://api.route.optimiser.app/api/auth/token'
headers = {'Content-Type': 'application/json'}


# Get a Token and put it in the Authorization header
body = {
    'email': os.getenv('TAROT_EMAIL'),
    'password': os.getenv('TAROT_PASSWORD'),
}
r = requests.post(auth_url, headers=headers, json=body)
token = r.json()['access_token']
headers['Authorization'] = f'Bearer {token}'


# Open Optimisation Problem File.
filename = sys.argv[1]
with open(filename) as f:
    body = json.load(f)


# Make the Start Optimisation request
r = requests.post(start_optimisation_url, json=body, headers=headers)

# The response gives you the URLs you need to call for the remaining requests
resp = r.json()
status_url = resp['status_url']
solution_url = resp['solution_url']


# Start the Polling Loop
solving = True
while solving:

    # Get the status, and leave the loop if the Optimiser has finished.
    r = requests.get(status_url, headers=headers)
    status = r.json()
    solving = status['solving']
    if not solving:
        # The solver has finished, exit the loop
        break

    # If you're here, the Optimiser hasn't finished yet.
    # Calculate the next time to check the status.
    next_status_eta = datetime.fromisoformat(status['next_status_eta'])
    delta = next_status_eta - datetime.now(tz=ZoneInfo('Europe/Paris'))
    time_to_next_status = delta.total_seconds()

    # Sleep until the next_status ETA,
    # but if we've already passed it 
    # we'll just try again in 5 seconds.
    time.sleep(time_to_next_status) if time_to_next_status > 0 else time.sleep(5)


# If you're here, the optimiser has finished solving.
# Let's get the Solution
r = requests.get(solution_url, headers=headers)
solution = r.json()

# Do something with it
with open(f'solution_{filename}', 'w') as f:
    json.dump(f, solution)

Example Response (202 Accepted)

Response Body
{
    "uid": "01GG7AEX026F47CS4NK2JBCE5G",
    "status_url": "https://opt.route.optimiser.app/v0.40/polling/vrp/01GG7AEX026F47CS4NK2JBCE5G/status",
    "solution_url": "https://opt.route.optimiser.app/v0.40/polling/vrp/01GG7AEX026F47CS4NK2JBCE5G"
}

The response contains: - uid: Unique identifier for this optimization request. Use this to poll status and retrieve results. - status_url: URL to GET the current optimization status - solution_url: URL to GET the final solution when complete

Get Status

GET https://opt.route.optimiser.app/v2/polling/vrp/{uid}/status

Polls the current status of an ongoing optimization.

Request
TOKEN=your_tarot_routing_token
VRP_UID=01GG7AEX026F47CS4NK2JBCE5G

curl "https://opt.route.optimiser.app/v0.40/vrp/${VRP_UID}/status" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" 
Request
import requests

token = 'Your Tarot Routing Token'
vrp_uid = '01GG7AEX026F47CS4NK2JBCE5G'

r = requests.get(
   url=f'https://opt.route.optimiser.app/v0.40/vrp/{vrp_uid}/status',
   headers={'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token},
)

Example Response (Solving in Progress)

Response Body
{
    "uid": "01GG7AEX026F47CS4NK2JBCE5G",
    "timestamp": "2022-10-25T12:19:26.129294+02:00",
    "message": "Started solving...",
    "solving": true,
    "cost": 0,
    "next_status_eta": "2022-10-25T12:19:30.129134+02:00"
}

Example Response (Solving Complete)

Response Body
{
    "uid": "01GG7AEX026F47CS4NK2JBCE5G",
    "timestamp": "2022-10-25T12:19:33.421031+02:00",
    "message": "The Improvement Threshold has been reached.",
    "solving": false,
    "cost": 57516,
    "next_status_eta": null
}

The response contains: - uid: The unique identifier from the start request - timestamp: When this status was recorded - message: Human-readable description of the current state - solving: Boolean flag indicating if optimization is still running - cost: Current best solution cost. 0 while solving hasn't started computing costs - next_status_eta: Recommended time to check status again (ISO 8601 format). null when solving is complete

Get Solution

GET https://opt.route.optimiser.app/v2/polling/vrp/{uid}

Retrieves the final optimization solution. Should be called after the status endpoint indicates solving: false.

Returns the same RoutingSolution format as the synchronous endpoint.

Example Response

Response Body
{
    "runs": [
        {
            "driver": {
                "uid": "drvid1",
                "shift_start": "08:00:00",
                "shift_end": "17:00:00",
                "run": 1,
                "seq": 0,
                "location": {
                    "lon": 151.166256,
                    "lat": -33.867798
                },
                "end_location": {
                    "lon": 151.166256,
                    "lat": -33.867798
                }
            },
            "jobs": [
                {
                    "uid": "uid1",
                    "duration": 120,
                    "eta": "08:09:45",
                    "etd": "08:11:45",
                    "run": 1,
                    "seq": 1,
                    "location": {
                        "lon": 151.127482,
                        "lat": -33.849489
                    }
                },
                {
                    "uid": "uid2",
                    "duration": 120,
                    "eta": "08:24:12",
                    "etd": "08:26:12",
                    "run": 1,
                    "seq": 2,
                    "location": {
                        "lon": 151.183096,
                        "lat": -33.880661
                    }
                },
                {
                    "uid": "uid3",
                    "duration": 120,
                    "eta": "08:42:32",
                    "etd": "08:44:32",
                    "run": 1,
                    "seq": 3,
                    "location": {
                        "lon": 151.262267,
                        "lat": -33.913168
                    }
                }
            ]
        }
    ],
    "unserved_jobs": []
}