Endpoints#
Tarot Routing - Route Optimisation API
Base URL#
https://opt.route.optimiser.app
Use this URL as the base for all requests on this page.
Synchronous Route Optimisation API#
- POST /v0.40/vrp#
A synchronous endpoint for Route Optimisation requests
- Request Headers:
Authorization: Token <your_token>
The word “Token” followed by a space, followed by your Tarot Routing Token. Don’t have one? Contact us info@tarotanalytics.com
Content-Type –
Content-Type: application/json
- Request JSON Object:
- Response JSON Object:
- Status Codes:
200 OK –
400 Bad Request – Check response body for details
401 Unauthorized – Misformed or Missing Authorization header
403 Forbidden – Invalid or Expired Token
Example Request
{ "drivers": [ { "uid": "drvid1", "shift_start": 8, "shift_end": 17, "location": {"lat": -33.867798, "lon": 151.166256} } ], "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": {} }
TOKEN={your_tarot_routing_token} curl https://opt.route.optimiser.app/v0.40/vrp \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json" \ --data "@ex1.json"
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/v0.40/vrp', headers={'Content-Type': 'application/json', 'Authorization': 'Token ' + token}, json=body, )
Example Response
{ "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#
A set of endpoints for asynchronous Route Optimisation
Start Optimisation#
- POST /v0.40/polling/vrp#
Start solving your optimisation problem.
Note that the request body is identical to the Synchronous Route Optimisation API
- Request Headers:
Authorization: Token <your_token>
The word “Token” followed by a space, followed by your Tarot Routing Token. Don’t have one? Contact us info@tarotanalytics.com
Content-Type –
Content-Type: application/json
- Request JSON Object:
- Response JSON Object:
uid – You will use this unique identifier in subsequent requests to ask for status updates and receive the solution for this optimisation.
status_url – Make GET requests to this URL to understand how the optimisation is progressing, whether a solution is available, and whether the optimisation is still running.
solution_url – After a status update informs you there is a Solution, make a GET request to this URL to get the Solution. Note that this URL redirects to a pre-signed download URL for the solution, so you must follow redirects.
- Status Codes:
202 Accepted – Your optimisation problem is accepted and started optimising.
400 Bad Request – Check response body for details
401 Unauthorized – Misformed or Missing Authorization header
403 Forbidden – Invalid or Expired Token
Example Request
{ "drivers": [ { "uid": "drvid1", "shift_start": 8, "shift_end": 17, "location": {"lat": -33.867798, "lon": 151.166256} } ], "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": {} }
TOKEN=your_tarot_routing_token RESP=$(curl https://opt.route.optimiser.app/v0.40/polling/vrp \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json" \ --data "@ex1.json") VRP_UID=$(echo $RESP | jq -r .uid) echo $VRP_UID # 01GG7AEX026F47CS4NK2JBCE5G
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/v0.40/polling/vrp', headers={'Content-Type': 'application/json', 'Authorization': 'Token ' + token}, json=body, ) uid = r.json()['uid'] print(uid) # 01GG7AEX026F47CS4NK2JBCE5G
Example Response
{ "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" }
Get Optimisation Status#
- GET /v0.40/polling/vrp/{uid}/status#
Get the latest status of your optimisation request.
- Parameters:
uid (string) – The unique identifier for this Optimisation.
- Response JSON Object:
uid (string) – The unique identifier for this Optimisation.
timestamp (datetime) – The time that this status update was created in ISO8601 Format
message (string) – A message to let you know what the optimiser is currently doing (or why it stopped).
solving (bool) –
true
if the optimiser is still solving.false
if it has finished.cost (int) –
The optimiser has a number which represents how good it’s latest solution is.
A solution with a lower
cost
is better. i.e. it serves more jobs, respects more constraints, has less driving time, etc.The cost is dimensionless, and cannot be compared across different optimisations.
next_status_eta (datetime) –
An estimate of the time that the Optimiser will provide its next status, in ISO8601 Format
Instead of polling regularly (e.g. every 5 seconds), you should wait until the
next_status_eta
toGET
the next status. It is only an estimate, so you should still fallback to a regular poll (e.g. every 5 seconds) in case there’s no status update by thenext_status_eta
.
- Status Codes:
200 OK –
400 Bad Request – Check response body for details
401 Unauthorized – Misformed or Missing Authorization header
403 Forbidden – Invalid or Expired Token
Example Request:
TOKEN=your_tarot_routing_token VRP_UID=01GG7AEX026F47CS4NK2JBCE5G RESP=$(curl "https://opt.route.optimiser.app/v0.40/polling/vrp/${VRP_UID}/status" \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json") SOLVING=$(echo $RESP | jq .solving) echo $SOLVING # true
import requests token = 'Your Tarot Routing Token' vrp_uid = '01GG7AEX026F47CS4NK2JBCE5G' r = requests.get( url=f'https://opt.route.optimiser.app/v0.40/polling/vrp/{vrp_uid}/status', headers={'Content-Type': 'application/json', 'Authorization': 'Token ' + token}, ) solving = r.json()['solving'] print(solving) # True
Example Responses
{ "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" }
{ "uid": "01GG7AEX026F47CS4NK2JBCE5G", "timestamp": "2022-10-25T12:19:30.061413+02:00", "message": "Attempting to find a better solution...", "solving": true, "cost": 57516, "next_status_eta": "2022-10-25T12:19:34.061294+02:00" }
{ "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 }
Get Solution#
- GET /v0.40/polling/vrp/{uid}#
This endpoint redirects to a temporary pre-signed URL which gets the (latest) Solution for your Optimisation request.
Make sure your request client follows redirects.
Note:
curl
does not follow redirects by default, you’ll need to usecurl -L
.- Parameters:
uid (string) – The unique identifier for this Optimisation.
- Response JSON Object:
- Status Codes:
307 Temporary Redirect – Temporary Redirect to the .json file download URL. The file download itself will respond with 200.
400 Bad Request – Check response body for details
401 Unauthorized – Misformed or Missing Authorization header
403 Forbidden – Invalid or Expired Token
Example Request:
TOKEN=your_tarot_routing_token VRP_UID=01GG7AEX026F47CS4NK2JBCE5G curl "https://opt.route.optimiser.app/v0.40/polling/vrp/${VRP_UID}" \ -H "Authorization: Token $TOKEN" \ -H "Content-Type: application/json"
import requests token = 'Your Tarot Routing Token' vrp_uid = '01GG7AEX026F47CS4NK2JBCE5G' r = requests.get( url=f'https://opt.route.optimiser.app/v0.40/polling/vrp/{vrp_uid}', headers={'Content-Type': 'application/json', 'Authorization': 'Token ' + token}, )
Example Response
{ "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": [] }
End to End Polling Optimisation Example#
To make this example work, you will need
A Tarot Routing account
Your Tarot Routing email and password stored in environment variables
TAROT_EMAIL
andTAROT_PASSWORD
A valid RoutingProblem file
export TAROT_EMAIL='info@tarotanalytics.com'
export TAROT_PASSWORD='my$3cr37P@ssw0rd'
wget https://docs.opt.route.optimiser.app/_static/ex1.json
wget https://docs.opt.route.optimiser.app/_static/optimise_polling.py
pip install requests
python optimise_polling.py ex1.json
pip install requests
python optimise_polling.py ex1.json
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'Token {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)