Create and delete Stops from a live Plan
Here we will be using the Create Live Stop, the Delete Live Stop, the Re-Optimize Plan, and the Save Plan endpoints to create and delete a Stop from a Plan that was already optimized, and therefore not editable via the Create Stop and Delete Stop endpoints.
The Save Plan will be called instead of Re-Distribute to make sure the plan won't be distributed. We can call the Distribute endpoint in the end if we want to only distribute it.
- JS Web
- Node
- Python
- curl
// Set the API key
const apiKey = '<your-api-key>'
// Headers for the request
const headers = new Headers()
headers.append('Content-Type', 'application/json')
headers.append('Authorization', `Basic ${btoa(`${apiKey}:`)}`)
async function createAndDeleteStop(planId) {
// example stop data to create. Remember to provide valid addresses
const stopData = {
address: {
addressLineOne: 'Some valid address',
},
}
// We create the stop using the liveCreate method
const createStopResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${planId}/stops:liveCreate`,
{
method: 'POST',
headers: headers,
body: JSON.stringify(stopData),
},
)
// We get the stop id from the response
const createStopResponseJson = await createStopResponse.json()
console.log(createStopResponseJson)
const stopId = createStopResponseJson.stop.id
// We delete the created stop using the liveDelete endpoint
// Note that we can do multiple requests before applying the changes through
// reoptimize and redistribute/save. All changes will be applied at once.
const deleteStopResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${stopId}:liveDelete`,
{
method: 'POST',
headers: headers,
body: JSON.stringify({}),
},
)
// The response will return an object similar to the following:
// {
// "pending": true,
// }
const deleteStopResponseJson = await deleteStopResponse.json()
console.log(deleteStopResponseJson)
// Now, we have to check if the update was applied to the plan or if it's
// pending a new optimization and distribution. On `pending = true`, we must
// use the re-optimize and re-distribute endpoints to apply the changes to the plan,
// even in this case where we deleted our previously created stop.
if (deleteStopResponseJson.pending) {
// Let us re-optimize this plan:
const reoptimizationResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${planId}:reoptimize`,
{
method: 'POST',
headers,
body: JSON.stringify({}),
},
)
// The response will return an operation object similar to the following:
// {
// "id": "operations/FQ95Ex714KYeojkeIm77",
// "done": false,
// "type": "plan_optimization",
// ...
// }
//
// Why an operation? Because the re-optimization can take a long while to
// finish, so we process it in an asynchronous manner.
let operation = await reoptimizationResponse.json()
console.log(operation)
// Now we need to wait until the re-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 re-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 save this plan's changes
const saveResponse = await fetch(
`https://api.getcircuit.com/public/v0.2b/${planId}:save`,
{
method: 'POST',
headers,
body: JSON.stringify({}),
},
)
// the above will return 204 with empty body
}
}
// We are using the axios library here to make requests from Node
import axios from '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,
},
})
async function createAndDeleteStop(planId) {
// example stop data to create. Remember to provide valid addresses
const stopData = {
address: {
addressLineOne: 'Some valid address',
},
}
// We create the stop using the liveCreate method
const createStopResponse = await api.post(
`/${planId}/stops:liveCreate`,
stopData,
)
// We get the stop id from the response
const createStopResponseJson = createStopResponse.data
console.log(createStopResponseJson)
const stopId = createStopResponseJson.stop.id
// We delete the created stop using the liveDelete endpoint
// Note that we can do multiple requests before applying the changes through
// reoptimize and redistribute/save. All changes will be applied at once.
const deleteStopResponse = await api.post(`/${stopId}:liveDelete`, {})
// The response will return an object similar to the following:
// {
// "pending": true,
// }
const deleteStopResponseJson = await deleteStopResponse.data
console.log(deleteStopResponseJson)
// Now, we have to check if the update was applied to the plan or if it's
// pending a new optimization and distribution. On `pending = true`, we must
// use the re-optimize and re-distribute endpoints to apply the changes to the plan,
// even in this case where we deleted our previously created stop.
if (deleteStopResponseJson.pending) {
// Let us re-optimize this plan:
const reoptimizationResponse = await api.post(`/${planId}:reoptimize`, {})
// The response will return an operation object similar to the following:
// {
// "id": "operations/FQ95Ex714KYeojkeIm77",
// "done": false,
// "type": "plan_optimization",
// ...
// }
//
// Why an operation? Because the re-optimization can take a long while to
// finish, so we process it in an asynchronous manner.
let operation = reoptimizationResponse.data
console.log(operation)
// Now we need to wait until the re-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 re-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}`)
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 (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 save this plan's changes
const saveResponse = await api.post(`/${planId}:save`, {})
// the above will return 204 with empty body
}
}
# 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>'
auth = HTTPBasicAuth(api_key, '')
def create_and_delete_stop(plan_id):
# example stop data to create. Remember to provide valid addresses
stop_data = {
'address': {
'addressLineOne': 'Some valid address'
}
}
# We create the stop using the liveCreate method
create_stop_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{plan_id}/stops:liveCreate',
json=stop_data,
auth=auth
)
# We get the stop id from the response
create_stop_response_json = create_stop_response.json()
print(create_stop_response_json)
stop_id = create_stop_response_json['stop']['id']
# We delete the created stop using the liveDelete endpoint
# Note that we can do multiple requests before applying the changes through
# reoptimize and redistribute/save. All changes will be applied at once.
delete_stop_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{stop_id}:liveDelete',
json={},
auth=auth
)
# The response will return an object similar to the following:
# {
# "pending": true,
# }
delete_stop_response_json = delete_stop_response.json()
print(delete_stop_response_json)
# Now, we have to check if the update was applied to the plan or if it's
# pending a new optimization and distribution. On `pending = true`, we must
# use the re-optimize and re-distribute endpoints to apply the changes to the plan,
# even in this case where we deleted our previously created stop.
if (delete_stop_response_json['pending']):
# Let us re-optimize this plan:
reoptimization_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{plan_id}:reoptimize',
auth=auth,
json={}
)
# The response will return an operation object similar to the following:
# {
# "id": "operations/FQ95Ex714KYeojkeIm77",
# "done": false,
# "type": "plan_optimization",
# ...
# }
#
# Why an operation? Because the re-optimization can take a long while to
# finish, so we process it in an asynchronous manner.
operation = reoptimization_response.json()
print(operation)
# Now we need to wait until the re-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 re-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=auth
)
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 save this plan's changes
save_response = requests.post(
f'https://api.getcircuit.com/public/v0.2b/{plan_id}:save',
auth=auth
)
# The above will return 204 with empty body
# We create the stop using the liveCreate method
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3/stops:liveCreate \
-X POST \
-H 'Content-Type: application/json' \
-d '{"address": {"addressLineOne": "Some valid address"}}' \
-u <your-api-key>:
# We delete the stop we created before
# Note that we can do multiple requests before applying the changes through
# reoptimize and redistribute/save. All changes will be applied at once.
# (we are considering a stop with the id plans/KBoYtDxO3FMh7zJkWdU3/stops/vgsTiQi85ueWRs1JnXx7)
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3/stops/vgsTiQi85ueWRs1JnXx7:liveDelete \
-X POST \
-u <your-api-key>:
# Now we must use re-optimize and re-distribute to apply the changes to the plan,
# even in this case where we deleted our previously created stop.
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3:reoptimize \
-X POST \
-H 'Content-Type: application/json' \
-d '{}' \
-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 finally we can save this plan's changes
curl https://api.getcircuit.com/public/v0.2b/plans/KBoYtDxO3FMh7zJkWdU3:save \
-X POST \
-u <your-api-key>: