Optimize and distribute plan
Here we will be using the Plan Optimize and the Plan Distribute endpoints to optimize and distribute an already existing plan with stops to the drivers. We will also use the Get Operations endpoint to retrieve the status of the plan optimization. Read their descriptions to see all the available options.
- JS Web
- Node
- Python
- curl
// Set the API key
const apiKey = '<your-api-key>'
// Headers for the request
const headers = new Headers()
headers.append('Authorization', `Basic ${btoa(`${apiKey}:`)}`)
// ...create and add stops to the plan. See the other example pages to
// understand how to do this
// Now suppose we already have the plan id as returned by the API to pass to
// this function after it was created in the format `plans/someId`:
async function optimizeAndDistributePlan(planId) {
// Let us optimize this plan:
const optimizationResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${planId}:optimize`,
{
method: 'POST',
headers,
},
)
// The response will return an operation object similar to the following:
// {
// "id": "operations/FQ95Ex714KYeojkeIm77",
// "done": false,
// "type": "plan_optimization",
// ...
// }
//
// Why an operation? Because the optimization can take a long while to
// finish, so we process it in an asynchronous manner.
let operation = await optimizationResponse.json()
console.log(operation)
// Now we need to wait until the optimization is done. As this can take a very
// long while depending on the number of stops, we will check it in a loop
// every few seconds.
//
// If the route is small enough, the optimization response itself can already
// return a done operation, the condition on this loop prevents us from
// even start polling if that is the case
//
// IMPORTANT: remember to add a delay between each check so
// as to not be rate-limited.
while (!operation.done) {
// Sleep/wait for a certain duration before the next check
await new Promise((resolve) => setTimeout(resolve, 5000)) // 5 seconds delay
const operationProgress = await fetch(
`https://api.getcircuit.com/public/v0.2b/${operation.id}`,
{
headers,
},
)
operation = await operationProgress.json()
}
// Now the operation is done, which means it finished processing, and it might
// have had a successful result or an error one, let's check for it (the
// result field is not included in the response until the operation finishes):
const result = operation.result
// check for errors: if there is a code and message it means that the
// operation errored with said code and error messages, check the docs for the
// meaning of these
if (result.code && result.message) {
throw new Error(`Operation failed with ${result.code}: ${result.message}`)
}
// otherwise the operation was succesful
console.log(
`Operation successfully optimized ${result.numOptimizedStops} stops`,
)
// but it still might have ignored some stops due to time constraints or other
// problems such as the stop is not reachable:
if (result.skippedStops.length > 0) {
console.log(
`Operation skipped a total of ${result.skippedStops.length} stops: check them manually`,
)
}
// Now finally we can distribute this plan and the created routes after the
// optimization to the drivers:
const distributeResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${planId}:distribute`,
{
method: 'POST',
headers,
},
)
// the above will return the plan with the `distributed` attribute set to `true`
}
// We are using the axios library here to make requests from Node
const axios = require('axios')
// Set the API key
const apiKey = '<your-api-key>'
// Axios instance with base configuration
const api = axios.create({
baseURL: 'https://api.getcircuit.com/public/v0.2b',
auth: {
username: apiKey,
},
})
// ...create and add stops to the plan. See the other example pages to
// understand how to do this
// Now suppose we already have the plan id as returned by the API to pass to
// this function after it was created in the format `plans/someId`:
async function optimizeAndDistributePlan(planId) {
// Let us optimize this plan:
const optimizationResponse = await api.post(
`/${planId}:optimize`,
undefined,
{
headers: {
// axios sends a Content-Type header even if the body is empty, this
// ensures not Content-Type is set for this request without body
'Content-Type': false,
},
},
)
// The response will return an operation object similar to the following:
// {
// "id": "operations/FQ95Ex714KYeojkeIm77",
// "done": false,
// "type": "plan_optimization",
// ...
// }
//
// Why an operation? Because the optimization can take a long while to finish,
// so we process it in an asynchronous manner.
let operation = optimizationResponse.data
console.log(operation)
// Now we need to wait until the optimization is done. As this can take a very
// long while depending on the number of stops, we will check it in a loop
// every few seconds.
//
// If the route is small enough, the optimization response itself can already
// return a done operation, the condition on this loop prevents us from even
// start polling if that is the case
//
// IMPORTANT: remember to add a delay between each check so as to not be
// rate-limited.
while (!operation.done) {
// Sleep/wait for a certain duration before the next check
await new Promise((resolve) => setTimeout(resolve, 5000)) // 5 seconds delay
const operationProgress = await api.get(`/${operation.id}`, undefined, {
headers: {
'Content-Type': false,
},
})
operation = operationProgress.data
}
// Now the operation is done, which means it finished processing, and it might
// have had a successful result or an error one, let's check for it:
const result = operation.result
// check for errors: if there is a code and message it means that the
// operation errored with said code and error messages, check the docs for the
// meaning of these
if (result.code && result.message) {
throw new Error(`Operation failed with ${result.code}: ${result.message}`)
}
// otherwise the operation was successful
console.log(
`Operation successfully optimized ${result.numOptimizedStops} stops`,
)
// but it still might have ignored some stops due to time constraints or other
// problems such as the stop is not reachable:
if (result.skippedStops.length > 0) {
console.log(
`Operation skipped a total of ${result.skippedStops.length} stops: check them manually`,
)
}
// Now finally we can distribute this plan and the created routes after the
// optimization to the drivers:
const distributeResponse = await api.post(
`/${planId}:distribute`,
undefined,
{
headers: {
'Content-Type': false,
},
},
)
// the above will return the plan with the `distributed` attribute set to `true`
}
# We are using the requests library here to make requests from Python
import requests
from requests.auth import HTTPBasicAuth
import time
# Set the API key
api_key = '<your-api-key>'
# ...create and add stops to the plan. See the other example pages to understand
# how to do this.
# Now suppose we already have the plan id as returned by the API to pass to this
# function after it was created in the format `plans/someId`:
def optimize_and_distribute_plan(plan_id):
# Let us optimize this plan:
optimization_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{plan_id}:optimize',
auth=HTTPBasicAuth(api_key, '')
)
# The response will return an operation object similar to the following:
# {
# "id": "operations/FQ95Ex714KYeojkeIm77",
# "done": false,
# "type": "plan_optimization",
# ...
# }
#
# Why an operation? Because the optimization can take a long while to
# finish, so we process it in an asynchronous manner.
operation = optimization_response.json()
print(operation)
# Now we need to wait until the optimization is done. As this can take a
# very long while depending on the number of stops, we will check it in a loop
# every few seconds.
#
# If the route is small enough, the optimization response itself can already
# return a done operation, the condition on this loop prevents us from even
# start polling if that is the case.
#
# IMPORTANT: remember to add a delay between each check so as to not be
# rate-limited.
while not operation['done']:
# Sleep/wait for a certain duration before the next check
time.sleep(5) # 5 seconds delay
operation_check_response = requests.get(
f'https://api.getcircuit.com/public/v0.2b/{operation["id"]}',
auth=HTTPBasicAuth(api_key, '')
)
operation = operation_check_response.json()
# Now the operation is done, which means it finished processing, and it
# might have had a successful result or an error one, let's check for it:
result = operation.get('result')
# Check for errors: if there is a code and message it means that the
# operation errored with said code and error messages, check the docs for
# the meaning of these.
if 'code' in result and 'message' in result:
raise Exception(f"Operation failed with {result['code']}: {result['message']}")
# Otherwise, the operation was successful.
print(f"Operation successfully optimized {result['numOptimizedStops']} stops")
# But it still might have ignored some stops due to time constraints or
# other problems such as the stop is not reachable:
if len(result.get('skippedStops', [])) > 0:
print(f"Operation skipped a total of {len(result['skippedStops'])} stops: check them manually")
# Now finally we can distribute this plan and the created routes after the
# optimization to the drivers:
distribution_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{plan_id}:distribute',
auth=HTTPBasicAuth(api_key, '')
)
# The above will return the plan with the `distributed` attribute set to `true`.
# With the plan already created and stops imported, start the optimization (we
# are considering a plan with the id plans/KBoYtDxO3FMh7zJkWdU3 here):
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3:optimize \
-X POST \
-u <your-api-key>:
# The response will return an operation object similar to the following:
# {
# "id": "operations/FQ95Ex714KYeojkeIm77",
# "done": false,
# "type": "plan_optimization",
# ...
# }
#
# Why an operation? Because the optimization can take a long while to finish, so
# we process it in an asynchronous manner.
# Now, with the returned ID, we can periodically call the GET operation endpoint
# to check it until the `done` field is `true`
curl https://api.getcircuit.com/public/v0.2b/operations/FQ95Ex714KYeojkeIm77 \
-u <your-api-key>:
# Now wait until the operation is done, which means it finished processing, and
# it might have had a successful result or an error one.
#
# The error one will have the `result.code` and `result.message` fields set,
# while the successful one will have the result fields, which include the
# skipped stops and the amount of optimized stops.
# Now if you want, you can distribute the optimized routes to your drivers:
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3:distribute \
-X POST \
-u <your-api-key>: