# Route Optimization API

## Introduction

Nextbillion.ai's Route Optimization API is a powerful tool that helps businesses optimize their delivery routes to maximize efficiency, save time, and reduce costs. It is designed to solve both Single and/or Multi Vehicle Routing Problem ([VRP](https://nextbillion.ai/blog/solving-vehicle-routing-problem)), which is a classic optimization problem in operations research that involves finding the optimal set of routes for a fleet of vehicles to visit a set of locations while satisfying various constraints such as time windows, capacity, and vehicle availability.

The Route Optimization API consists of the following methods to handle different types of service requests:

1. **Build an Optimization Request** - Submits an optimization request via HTTP POST, with configurations for all input variables.
2. **Retrieve Optimized Solution** - Retrieves the solution for a previously submitted optimization request.
3. **Re-optimize An Existing Solution** - Updates an existing route plan by re-optimizing it based on its request ID and modifications to the original task or vehicle configuration.

## Build an Optimization Request

POST

https://api.nextbillion.io/optimization/v2?key={your_api_key}

  

Use this method to configure the constraints and properties of the optimization problem that you need to solve. Use the fundamental objects - `vehicles`, `jobs`, `locations` and `shipments` to emulate the scenario that your business needs to optimize. You can choose to use either one of `jobs` and `shipments` or use both of them.

Define the objective of your optimization, soft-constraints and routing preferences in the `options` object. You can also use advanced features like re-optimization and order sequencing using the `solutions` and `relations` object respectively.

Once an optimization request is successfully submitted, the API will return a unique task ID in the acknowledgement response. Use this unique ID to retrieve the actual solution using the method listed in *Retrieve Optimized Solution* section below.

### Request Parameter

| Name | Required | Format and Usage | Description |
|------|----------|------------------|-------------|
| `key` | Yes | Type: `string`<br>Format: 32 bit alphanumeric character<br>Example: key=API_KEY | A key is a unique identifier that is required to authenticate a request to the API. |

### Request Body

| Field | Type | Description |
|-------|------|-------------|
| `locations` | object | The `locations` object is used to define all the locations that will be used during the optimization process. Read more about this attribute in the [Location Object](#location-object) section. |
| `locations.id` | integer | A unique ID for the set of locations. It should be a positive integer. |
| `locations.location` | array of string | Indicate all the location coordinates that will be used during optimization. The coordinates should be specified in the format “latitude, longitude”. It is recommended to avoid adding duplicate location coordinates to this array. In case there are multiple tasks at the same location, users can repeat the index of the location while configuring all such tasks.<br>Please use this array to determine the index of a location when setting the `location_index` parameter in `jobs`, `shipments`, `vehicles` or other parts of the request. The length of this array determines the valid values for `location_index` parameter. |
| `locations.approaches` | array of string | Describe if the location is curbside. An array of strings indicates the side of the road from which to approach the location in the calculated route. If provided, the number of approaches must be equal to the number of locations. However, you can skip a coordinate and show its position in the list using “” (empty string). Please note these values are case-sensitive. |
| `vehicles` | array of object | The `vehicles` attribute describes the characteristics and constraints of the vehicles that will be used for fulfilling the tasks. Read more about this attribute in the [Vehicle Object](#vehicle-object) section. |
| `vehicles[].id` | string | Specify a unique ID for the vehicle. The IDs are case-sensitive. |
| `vehicles[].description` | string | Specify a custom description for this vehicle. It will be returned in the response as-is. |
| `vehicles[].start_index` | integer | Specify the index of the vehicle’s starting point in the `location` array. The valid value range is \[0, length of `location` array).<br>Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicles[].start_depot_ids` | array of string | Specify the depots from which the vehicle can start. It is assumed that the vehicles can load the goods, which are to be delivered during the trip, when starting from the given depot. If certain delivery jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles starting from those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Pick-up type jobs which have depots configured, can not by fulfilled by vehicles who have only the start depots configured.<br>*   In case multiple depots are provided, then the vehicle starts from the depot which is nearest to the first task that it has to perform.<br>*   Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicles[].end_index` | integer | Specify the index of the vehicle’s final stop point in the `location` array. The valid value range is \[0, length of locations).<br>Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicles[].end_depot_ids` | array of string | Specify the depots where the vehicle should end its trip. It is assumed that the vehicles will unload the goods, which were picked-up during the trip, upon arriving the given depot. If certain pickup jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles ending their trips at those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Delivery type jobs which have depots configured, can not by fulfilled by vehicles who have only the end depots configured.<br>*   In case multiple depots are provided, then the vehicle ends the trip at the depot which is nearest to the last task that it performs.<br>*   Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicles[].capacity` | array of integer | `capacity` attribute is used to define multidimensional capacities of the vehicle.<br>It is recommended to keep the dimensions of `capacity` consistent with the dimensions provided in quantity related attributes of `jobs` and `shipments` objects.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicles[].alternative_capacities` | array of array of integer | An array of alternate capacity configurations for the vehicle. Each array should have same number of dimensions as those configured when specifying task loads/quantities. Multiple arrays can also be specified to add more than one alternate capacity configurations for a given vehicle. These capacities can not be shared / merged.<br>**Example:** An alternate capacity of \[ \[4,1\] , \[3,3\] \] indicates that the vehicle can either take 4 units of first dimension and a single unit of second dimension or else, 3 units each of both the dimensions. |
| `vehicles[].time_window` | array of integer | `time_window` field is used to describe the time period during which a vehicle is available to perform assigned tasks. The time_window should be specified in the format of \[start_timestamp,end_timestamp\] and each timestamp must be expressed as an UNIX timestamp in seconds.<br>Please observe that it accepts only a single time window for the vehicle. It is important to note this difference with respect to the `time_windows` field used for `shipments` and `jobs`, which is a two-dimensional array used to describe the multiple time windows for each individual shipment or job. |
| `vehicles[].skills` | array of integer | It is a multi-dimensional object that can be used to define multiple skills and abilities of drivers or vehicles.<br>Please note that only those vehicles with all the skills needed for a job/shipment will be assigned to fulfill that task.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicles[].max_tasks` | integer | Describe the maximum number of tasks that can be assigned to this vehicle. It should be a positive integer. |
| `vehicles[].breaks` | array of object | The `breaks` attribute is used to provide details of breaks that a driver can take during their route. For each break, multiple time windows can be provided during which the break can actually be taken. Please note that:<br>*   All breaks are treated as mandatory by the optimization engine. If they are feasible, then all of them will be part of vehicle's trip.<br>*   Only one of `breaks` or `layover_config` is allowed for a vehicle at a time. |
| `vehicles[].breaks[].id` | integer | Specify an ID for the break. It should be a positive integer. |
| `vehicles[].breaks[].time_windows` | array of array of integer | Describe the possible time slots for the driver's break period to start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that<br>*   Individual time window should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\].<br>*   All time windows of all breaks should be inside the vehicle's time window. |
| `vehicles[].breaks[].description` | string | Add a custom description for the break. |
| `vehicles[].breaks[].service` | integer | Specify the break duration, in seconds. |
| `vehicles[].costs` | object | The `cost` attribute is used to define the cost of using the vehicle. It is a positive integer value with no specific unit of its own, but assumes the unit as per the value of `travel_cost` parameter.<br>*   When the `travel_cost` parameter is set to `distance` then `cost` will be in meters.<br>*   When the `travel_cost` parameter is set to `duration` then `cost` will be in seconds.<br>*   When the `travel_cost` is set to `customized` then `cost` will not have any unit, but during calculations it will be considered at its face value.<br>*   When the `travel_cost` is set to `air_distance` then `cost` will be in meters.<br>`cost` parameter is critical in determining the number of vehicles to be used for optimization. The optimization engine will prefer using vehicles which help in lowering the cost for a particular route, if other parameters (location, time, etc) favor the configuration.<br>Please note that:<br>*   When only the `fixed` vehicle cost is provided, it will be added to the `travel_cost` of the optimized route to arrive at the overall cost of the route.<br>*   When only the `per_hour` or `per_km` cost is provided for a vehicle, then the cost of the route to which the vehicle is assigned, is calculated using only the given `per_hour` or `per_km` cost and not the `travel_cost` of the route.<br>*   When `per_hour` or `per_km` is provided along with `fixed` cost for a vehicle, then the cost of the route to which the vehicle is assigned, is equal to the sum of `fixed` and calculated `per_hour` or the `per_km` costs.<br>*   `per_order` cost is always added to the overall cost of the route to which the vehicle is assigned. |
| `vehicles[].costs.fixed` | integer | Specify a fixed cost for using a vehicle. It should be a positive integer. Default value is 0. |
| `vehicles[].costs.per_hour` | integer | Define the cost for one hour of drive time of the vehicle. When `per_hour` cost is used, the final vehicle cost is determined based on the given value, instead of travel duration of the route.<br>Please note that<br>*   `per_hour` cost is effective only when `travel_cost` is `duration`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_hour` costs are ineffective when using `options.grouping` configurations. |
| `vehicles[].costs.per_km` | integer | Define the cost incurred by the vehicle for travelling a distance of one kilometer (km). When `per_km` cost is used, the final vehicle cost is determined based on the given value, instead of distance travelled on the trip.<br>Please note that<br>*   `per_km` cost is effective only when `travel_cost` is `distance`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_km` costs are ineffective when using `options.grouping` configurations. |
| `vehicles[].costs.per_order` | integer | Define the cost incurred by the vehicle for fulfilling one order. A job or a shipment, both are considered as a single order. When `per_order` cost is defined, the final vehicle cost is calculated as the sum of total costs of fulfilling the orders assigned to the vehicle and any other costs that the vehicle incurs (travel_cost, fixed cost, per_km or per_hour costs). |
| `vehicles[].costs.min_stop_load_fixed_penalty` | integer | Specify the fixed penalty to be applied in case the vehicle is assigned to any delivery task with a load below the specified `min_stop_load` threshold. If all the tasks assigned to the vehicle have loads more than the specified `min_stop_load` threshold, this fixed penalty is not applied. |
| `vehicles[].costs.min_stop_load_unit_penalty` | array of integer | Defines the penalty applied per unit of load shortfall when a task’s load is lower than the vehicle’s configured `min_stop_load`. As a result, higher penalty values make the optimizer increasingly reluctant to assign low-load tasks to vehicles with higher minimum load expectations, while still preserving flexibility when capacity or feasibility constraints require such assignments. |
| `vehicles[].costs.deadhead_duration_penalty` | integer | Specify a penalty to be applied for each unit of deadhead duration exceeding the specified `max_deadhead_duration` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_duration` is not provided. |
| `vehicles[].costs.deadhead_distance_penalty` | integer | Specify a penalty to be applied for each unit of deadhead distance exceeding the specified `max_deadhead_distance` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_distance` is not provided. |
| `vehicles[].speed_factor` | number | A positive number indicating the factor by which the vehicle’s speed should be adjusted , relative to normal speed, affecting the driving durations consequently. When `speed_factor` is greater than 1, effective travel time will be less than the normal travel duration. Similarly, when `speed_factor` is less than 1, effective travel time will be more than the normal travel duration. Please note that the `speed_factor` value supports values greater than 0 upto a maximum of 5.0, with a precision of two digits after the decimal point.<br>For example, a normal trip duration of 1hr would be considered as a trip with duration of 30min if the `speed_factor` is 2.<br>Using this attribute will have an effect on the vehicle’s arrival time at task locations (allocate task `time_windows` accordingly) and can affect the cost of the route as well (when `travel_cost=duration`). |
| `vehicles[].layover_config` | object | Use this object to configure continuous driving time limitations and subsequent rest duration for the driver. Please note that only one of `layover_config` or `breaks` is allowed for a vehicle, at a time. |
| `vehicles[].layover_config.max_continuous_time` | integer | Define the maximum time, in seconds, that a driver can drive without taking a break. This field is mandatory when using the `layover_config` attribute. Please note that accumulation of driving time is not interrupted by service time, setup or waiting time when fulfilling tasks, unless `include_service_time` is set to true.<br>It is worth highlighting that, if different `max_continuous_time` durations are used then optimizer might choose vehicles with lower `max_continuous_time` because layover time is not affecting its objectives. |
| `vehicles[].layover_config.layover_duration` | integer | Specify the duration, in seconds, for which the driver should rest after driving continuously for the duration provided in `max_continuous_time`. This field is mandatory when using the `layover_config` attribute.<br>Please note that the `layover_duration` will be added to the total service time and will impact arrival time of vehicle/driver at task’s location, but it won’t influence the `cost` or `duration` of the routes. |
| `vehicles[].layover_config.include_service_time` | boolean | Choose if the optimizer should count the `service_time` spent while fulfilling tasks towards continuous working time of the driver. If set to `false` (default setting), only the driving time is considered to schedule the next break. When set to `true`, drive time and `service_time` are added together to determine the next break schedule. |
| `vehicles[].allowed_zones` | array of integer | Specifies the zones where the vehicle is allowed to fulfil any tasks. Please note the following:<br>*   If this parameter is provided, then the vehicle can fulfil tasks only in the given zones but, it is restricted from taking up tasks anywhere else.<br>*   Providing an empty array implies that there are no allowed zones. Consequently, the vehicle can only fulfill tasks without specified zones that are outside of any defined zone polygon boundaries.<br>*   If the parameter itself is not provided in the input, then the vehicle is allowed to complete tasks in all zones as well as outside them. |
| `vehicles[].restricted_zones` | array of integer | Specifies the zones where the vehicle is restricted from fulfilling any tasks. Although, the vehicle can be routed through such zones. Please note:<br>*   If this parameter is provided, then the vehicle is restricted from fulfilling tasks belonging to the given zones. Vehicle is allowed to fulfil tasks from everywhere else.<br>*   If an empty array is provided or if the parameter itself is not provided then zone based restrictions do not apply on the vehicle. |
| `vehicles[].max_distance` | integer | Specify the total distance, in meters, that the vehicle can travel. This is a constraint on the driving distance of the vehicle.<br>In case `distance_matrix` is also provided in the input, then this constraint is applied on the distance driven as per the custom distance values instead of actual distance values. |
| `vehicles[].max_travel_time` | integer | Specify the total duration, in seconds, that the vehicle can be driven for. This is a constraint on the driving duration of the vehicle only and any wait, service or setup times spent towards the job is not counted against this constraint.<br>In case `duration_matrix` is also provided in the input, then this constraint is applied on the drive duration as per the custom duration values instead of actual duration values. |
| `vehicles[].max_stops` | integer | Specify the maximum number of stops that the vehicle can make. Whenever the vehicle makes a stop during a trip, it is counted against the “max_stop” constraint. Vehicles stopping for breaks or layovers will not be counted against this constraint. |
| `vehicles[].profile` | string | Specify the profile for this vehicle. The routing properties of the profile specified here must be defined within `routing.profiles` under `options`. If no profile is specified, then default routing profile is used. |
| `vehicles[].max_working_time` | integer | Specify the maximum duration, in seconds, that the vehicle can work for on the assigned route. Please note that all types of driver activities during the route—service, waiting, setup, and driving—contribute against the specified maximum duration. |
| `vehicles[].volume` | object | Specify the dimensions of the vehicle's loading compartment. These inputs will be used to decide which cargo can be loaded into the vehicle based on their dimensions and alignment orientations. Please note that if a vehicle is not provided with the `volume` input, it can not be assigned to tasks with `volume` specified. |
| `vehicles[].volume.width` | number | Compartment width, in meters. |
| `vehicles[].volume.depth` | number | Compartment length, in meters. |
| `vehicles[].volume.height` | number | Compartment height, in meters. |
| `vehicles[].max_depot_runs` | integer | Specify the maximum number of times the vehicle can return to the designated depot in order to reload items/cargo for completing additional tasks. Please note that:<br>*   `start_depot_id` is required for the vehicle when specifying `max_depot_runs`.<br>*   `relations` , `layover_config` , `depots.throughput` and deadhead constraints ( `max_deadhead_duration` and `max_deadhead_distance` ) can not be used along with `max_depot_runs.` |
| `vehicles[].max_deadhead_distance` | integer | Specify the maximum distance, in meters, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_distance` and `max_depot_runs` can not be used simultaneously. |
| `vehicles[].max_deadhead_duration` | integer | Specify the maximum duration, in seconds, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_duration` and `max_depot_runs` can not be used simultaneously. |
| `vehicles[].min_stop_load` | array of integer | Specifies the minimum load threshold that should be preferred to serve at a stop. When a task’s load is lower than this threshold, the optimizer applies a penalty (as defined by `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty` ) instead of strictly rejecting the assignment. This allows users to discourage inefficient assignments for heavy vehicles by not assigning very light loads, while still keeping them feasible when no better alternatives exist. Please note that:<br>*   the number of elements in the `min_stop_load` array, should be exactly the same as those in the vehicle’s capacity input.<br>*   the `min_stop_load` threshold is effective only for “delivery” type `jobs`.<br>*   when multiple tasks are grouped together to share a single stop, the effective load used for `min_stop_load` calculations at that stop will be the sum of the loads of all tasks that are grouped.<br>*   if `min_stop_load` is provided without specifying the penalties `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty`), the stop load thresholds do not impact route choices. |
| `vehicles[].depot` | integer | **Deprecated! Please use the** `start_depot_ids` **and** `end_depot_ids` **to configure the originating and culminating depots for the vehicle, respectively.**<br>The `depot` attribute specifies the ID of the depot that is assigned to the vehicle.<br>Please note that if `depot` is specified, then the depot’s location will act as the starting point for the vehicle.<br>There is no restriction on the number of vehicles that can be assigned to a depot but one vehicle can only have one depot. |
| `vehicles[].max_travel_cost` | integer | **Deprecated! Please use the** `max_distance` or `max_travel_time` **parameters to limit the vehicle’s driving distance or driving durations respectively.**<br>It restricts the maximum “cost” that a vehicle can incur while operating. This parameter is linked to `travel_cost` parameter, which determines whether the `max_travel_cost` value will be considered as `distance` (in meters) or `duration` (in seconds) or `customized`.<br>For example, if the `travel_cost` attribute is set to `distance`, the `max_travel_cost` value will be considered as the maximum allowable distance that a vehicle can travel in the optimized solution.<br>If the `travel_cost` parameter is set to `duration`, then the `max_travel_cost` value will be considered as the maximum allowable time that a vehicle can drive in the optimized solution.<br>If the `travel_cost` is `customized` then the value provided for `max_travel_cost` will be compared directly with the custom cost of the route to determine if the vehicle can be assigned for that route or not. Please note that `max_travel_cost`, in this case, will be considered abstract (unit-less) and at face value.<br>Setting a value for `max_travel_cost` ensures the vehicle does not exceed its operational limits, which can result in increased fuel costs, longer delivery times, or potential vehicle breakdowns. |
| `jobs` | array of object | `jobs` object is used to collect the details of a particular job or task that needs to be completed as part of the optimization process. Each job can have either a `pickup` or `delivery` step, but not both. Read more about this attribute in the [Job Object](#job-object) section.<br>Please note that either the `jobs` or the `shipments` attribute should be specified to build a valid request. |
| `jobs[].id` | string | Provide an unique ID for the job. The IDs are case-sensitive. |
| `jobs[].description` | string | Add a custom description for the job. |
| `jobs[].location_index` | integer | An integer denoting the index (in the `location` array) of the location coordinates where the job needs to be performed. The valid range of values is \[0, length of `location` array).<br>Please note the `location_index` is mandatory when using the `jobs` object. |
| `jobs[].delivery` | array of integer | In case the job involves a delivery step, use this attribute to describe delivery quantity. This attribute supports multidimensional quantities, to support delivering quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the quantity of delivery will be added to the assigned vehicle’s initial load.<br>In case depots are being added, the delivery configured here can be fulfilled by vehicles starting from specific depots. Refer to `depot_ids` and `vehicles.start_depot_ids` to know more. |
| `jobs[].pickup` | array of integer | In case the job involves a pickup step, use this attribute to describe pickup quantity. This attribute supports multidimensional quantities, to support picking up quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the vehicle will continue to carry the picked-up quantity until its last stop.<br>In case depots are being added, the pickup configured here can be fulfilled by vehicles ending at specific depots. Refer to `depot_ids` and `vehicles.end_depot_ids` to know more. |
| `jobs[].service` | integer | Use this attribute to define the time duration, in seconds, needed to complete the job. Default value is 0. |
| `jobs[].time_windows` | array of array of integer | Define time periods within which this job should be started. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `jobs[].skills` | array of integer | Define the skills needed to complete the job. This attribute supports multidimensional skills allowing users to add multiple skills.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `jobs[].priority` | integer | Specify the priority of this job. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this job will be assigned or not, but has nothing to do with the sequence of job fulfilment. |
| `jobs[].setup` | integer | Specify the job set-up duration, in seconds. `setup` is the one-time effort needed apart from working on the original task - for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `jobs[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this job belongs to. The job can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this job. Please note following points about job zones:<br>*   If zone IDs are provided for any one of the jobs, then all other jobs should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Jobs can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a job is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of those zones.<br>*   Jobs not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `jobs[].depot_ids` | array of string | Specify the depots which can be used to fulfil this job. In case of a pickup job, the assigned vehicle will deliver the goods to the depot specified here, at the end of its trip. Conversely, in case of delivery jobs, the vehicle will load the goods from the depot specified here, before starting the trip.<br>**Note:**<br>*   If multiple IDs are provided for this field then any of the given depots can be used to fulfil the job.<br>*   If this field is not provided then the given job can be fulfilled by any vehicle (subject to other constraints configured in the input).<br>*   If the job does not have any delivery or pick-up step configured then depots configuration will not have any impact on the given job. |
| `jobs[].load_types` | array of string | Use this parameter to specify the type of loads for the given job. Once this property is configured, the job can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that job’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this job to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, `load_types` might be ignored. |
| `jobs[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the job’s load type. Once this property is configured, the job can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this job. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that current job’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this job to a vehicle which has served any task with `load_types` as either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `jobs[].sequence_order` | integer | Use this parameter to prioritize completing a task relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `jobs[].revenue` | integer | Specify the revenue earned by completing this job. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this job after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the job.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a job is negative, it will remain unassigned whatsoever. |
| `jobs[].outsourcing_cost` | integer | Specify the cost of keeping this job unassigned, namely, the cost of outsourcing the job. When provided, the optimizer weighs the cost of assigning the job against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned jobs is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the job can not be outsourced, then the optimizer tries to fulfill the job irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a job. Also, the `outsourcing_cost` would override the priority settings of the job. |
| `jobs[].follow_lifo_order` | boolean | Specify whether the job route should follow LIFO (last in, first out). Use this parameter when `pickup` or `delivery` jobs are involved and the loading or unloading sequence of cargo is important. The default is `false`. |
| `jobs[].max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a job after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `jobs[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the task. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a job consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total length, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `jobs[].volume.width` | number | Cargo width, in meters. |
| `jobs[].volume.depth` | number | Cargo length, in meters. |
| `jobs[].volume.height` | number | Cargo height, in meters. |
| `jobs[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `jobs[].joint_order` | integer | Specify a joint order group ID that this job is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each job in a single joint order group will be fulfilled by a unique vehicle.<br>*   Jobs belonging to a joint order group can be served in any sequence.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `jobs[].split` | object | An object to configure the rules for splitting the job into multiple sub-jobs. Please note that:<br>*   It is applicable only to `jobs` with:<br>    *   a `delivery` or `pickup` quantity specified.<br>    *   have only 1 load dimension (only element in the `delivery` or `pickup` array). Multi-dimension loads are not supported.<br>*   There is no partial completion for a splittable job - either all sub-jobs are fulfilled or none of them.<br>*   Each split part of the task is assigned a unique integer identifier in the range 0 ≤ identifier < total parts. These identifiers are available in the optimized result as `split_indicator`. |
| `jobs[].split.can_be_split` | boolean | Specify if a pickup or a delivery type job can be split into multiple sub-tasks. Default value is "false". |
| `jobs[].split.max_split` | integer | The maximum number of parts/sub-tasks that this job can be split into. This field is mandatory when `can_be_split = true` and must have a minimum value of 2. |
| `jobs[].split.quant` | number | The minimum quantity allowed for each split sub-task, expressed as a ratio of the original job load (e.g., `0.25` ensures each split is ≥ 25% of the total). If omitted, the solver splits greedily based on available vehicle capacity. Please note that it is applicable only for tasks with single-dimensional load only. |
| `shipments` | array of object | The `shipments` object is used to collect the details of shipments that need to be completed as part of the optimization process.<br>Each shipment should have a pickup and the corresponding delivery step.<br>Please note that either the `jobs` or the `shipments` attribute should be specified to build a valid request. |
| `shipments[].pickup` | object | Specify the details of the pickup step of the shipment. |
| `shipments[].pickup.id` | string | Indicate the ID of this shipment pickup step. An error will be reported if there are duplicate IDs for multiple shipment pick-ups. The IDs are case-sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipments[].pickup.description` | string | Specify a custom description for the shipment pickup step. |
| `shipments[].pickup.location_index` | integer | Indicate the index of the location for this shipment pickup. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array). |
| `shipments[].pickup.service` | integer | Provide the time duration, in seconds, needed to complete the shipment pickup. Default value is 0. |
| `shipments[].pickup.time_windows` | array of array of integer | Describe time periods within which the shipment pickup should be start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\] |
| `shipments[].pickup.setup` | integer | Specify the set-up duration, in seconds, for the pickup. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipments[].pickup.sequence_order` | integer | Use this parameter to prioritize completing the shipment pickup relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment pickups's sequence order must be lesser than or equal to its corresponding delivery's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipments[].pickup.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment pickup after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipments[].delivery` | object | Specify the details of the delivery step of the shipment. |
| `shipments[].delivery.id` | string | Indicate the ID of this shipment delivery step. An error will be reported if there are duplicate IDs for multiple shipment deliveries. The IDs are case sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipments[].delivery.description` | string | Specify a custom description for the shipment delivery step. |
| `shipments[].delivery.location_index` | integer | Indicate the index of location for this shipment delivery. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array).<br>Please note `location_index` is mandatory when using the `shipment` attribute. |
| `shipments[].delivery.service` | integer | Provide the time duration, in seconds, needed to complete the shipment delivery. Default value is 0. |
| `shipments[].delivery.time_windows` | array of array of integer | Describe time periods within which the shipment delivery should start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `shipments[].delivery.setup` | integer | Specify the set-up duration, in seconds, for the delivery. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipments[].delivery.sequence_order` | integer | Use this parameter to prioritize completing the shipment delivery relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment delivery's sequence order must be greater than or equal to its corresponding pickup's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipments[].delivery.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment delivery after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipments[].amount` | array of integer | This parameter defines the quantity that needs to be shipped. This attribute supports multidimensional quantities, to support shipment of quantities of different units/dimensions. It is recommended to keep the dimensions of `amount` in `shipments` and that of `capacity` in `vehicles` consistent.<br>Please note that the `amount` will be added to the assigned vehicle’s initial load.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipments[].skills` | array of integer | Define the skills needed to complete the shipment. This attribute supports multidimensional skills allowing users to add multiple skills for a shipment.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipments[].priority` | integer | Describe the priority of this shipment. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this shipment will be assigned or not, but has nothing to do with the sequence of fulfilling shipments. |
| `shipments[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this shipment belongs to. The shipment can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this shipment. If the pickup and delivery steps belong to different zones, then a vehicle should be allowed to fulfil tasks in both zones to take up such shipments. Please note following points about shipment zones:<br>*   If zone IDs are provided for any one of the shipments, then all other shipments should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Shipment steps can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a shipment pickup or delivery location is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of the overlapping zones, provided the vehicle is allowed to fulfill tasks in the zone containing the complementing shipment step.<br>*   Shipments not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `shipments[].load_types` | array of string | Use this parameter to specify the type of loads for the given shipment. Once this property is configured, the shipment can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this shipment to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `load_types` might be ignored. |
| `shipments[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the shipment’s load type. Once this property is configured, the shipment can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this shipment. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this shipment to a vehicle which has served any task with `load_types` as either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `shipments[].max_time_in_vehicle` | integer | Use this parameter to limit the drive time for which a shipment stays in the vehicle. The time-in-vehicle calculations start once the pickup leg of shipment is completed after serving any setup and service time that may have been configured for it. For the delivery leg, time-in-vehicle calculations wouldn’t consider any setup and service time that needs to be served for completing the delivery. The service or setup times of other tasks performed in between will also be not accumulated against the time-in-vehicle limit.<br>Please note that this property would be overridden if any `relations` configuration is used except for “precedence” type. If “precedence” type relations is used then `max_time_in_vehicle` will override it. |
| `shipments[].revenue` | integer | Specify the revenue earned by completing this shipment. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this shipment after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the shipment.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a shipment is negative, it will remain unassigned whatsoever. |
| `shipments[].outsourcing_cost` | integer | Specify the cost of keeping this shipment unassigned, namely, the cost of outsourcing the shipment. When provided, the optimizer weighs the cost of assigning the shipment against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned shipments is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the shipment can not be outsourced, then the optimizer tries to fulfill the shipment irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a shipment. Also, the `outsourcing_cost` would override the priority settings of the shipment. |
| `shipments[].follow_lifo_order` | boolean | Specify whether the shipment route should follow LIFO (last in, first out). Use this parameter when the loading or unloading sequence of cargo is important. The default value is \`false\`. |
| `shipments[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the shipment. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a shipment consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total depth, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `shipments[].volume.width` | number | Cargo width, in meters. |
| `shipments[].volume.depth` | number | Cargo length, in meters. |
| `shipments[].volume.height` | number | Cargo height, in meters. |
| `shipments[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `shipments[].joint_order` | integer | Specify a joint order group ID that this shipment is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each shipment in a single joint order group will be fulfilled by a unique vehicle.<br>*   Shipments belonging to a joint order group can be served in any sequence while maintaining the pickup -> delivery sequence for an individual shipment.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `depots` | array of object | `depots` object is used to collect the details of a depot. Depots can be used as a starting point and/or ending point for the routes and vehicles. They also can be used to fulfil pickup and delivery type`jobs` . The loads which are to be delivered at task locations will be picked from depots and loads picked-up from task locations will be delivered back to the depots. A depot can be configured using the following fields: |
| `depots[].id` | string | Provide an unique ID for the depot. The IDs are case sensitive. |
| `depots[].location_index` | integer | Specify the index of coordinates (in the `location` array) denoting the depot’s location. The valid range of values is \[0, length of `location` array). If the location index exceeds the count of input locations in the `location` array, the API will report an error.<br>Please note the `location_index` is mandatory when using the `depots` object. |
| `depots[].description` | string | Add a custom description for the depot. |
| `depots[].time_windows` | array of array of integer | Specify the time-windows during which the depot is operational and allows vehicles to be loaded / unloaded. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that:<br>*   Multiple time-windows can be provided but those time windows should not overlap with each other.<br>*   Time windows should always be specified in the format of \[start_timestamp, end_timestamp\]. |
| `depots[].service` | integer | Specify the time duration, in seconds, needed to load or unload the vehicle each time it starts or arrives at a depot, respectively. Please note that:<br>*   The default value is 0.<br>*   If `throughput.handling_duration` is also provided along with `service`, the optimizer applies both of them. |
| `depots[].throughput` | object | An object to collect the details about depot's throughput - speed of loading orders into vehicle. Please note that `throughput` attributes are ineffective when either of `max_depot_runs` and `relations` are used. |
| `depots[].throughput.handling_duration` | integer | Specify the unit time needed for loading orders into a vehicle. The number of orders that can be served within this duration is determined by the `max_load` setting. Please note that:<br>*   Default value is 0<br>*   When `max_load` is not specified, it is assumed that depot can load an infinite number of orders into the available vehicles for the given `handling_duration`.<br>*   Any `depot.service` time specified gets applied in addition to `handling_duration` provided. |
| `depots[].throughput.max_vehicles` | integer | Specify the maximum number of vehicles that the depot can service simultaneously. This is a soft constraint and requires `vehicle_penalty` to be provided along with it. |
| `depots[].throughput.vehicle_penalty` | integer | Specify the penalty, a positive integer, for simultaneously servicing vehicles that exceed the `max_vehicles` limit at any time.<br>This attribute controls the balance between respecting `max_vehicles` limit at the depot and achieving greater efficiency by maximizing the number of deliveries/pickups fulfilled. A higher penalty favors the vehicle limits at depots over task fulfillment. |
| `depots[].throughput.max_load` | array of integer | Specify the sum total of load or orders that the depot can load into the available vehicles within the `handling_duration`. Please note that:<br>*   This is a soft constraint and requires `load_penalty` to be specified.<br>*   The load dimensions \[number of array elements\] provided should be consistent with the vehicle's capacity dimensions.<br>*   All elements in the input array should be positive integers. |
| `depots[].throughput.load_penalty` | array of integer | Specify the penalty to be applied when a depot exceeds its `max_load` limit during any `handling_duration` interval. The penalty is applied for each excess unit of load. A penalty value must be provided for each dimension \[number of elements in array\] specified in the `max_load` input. Each penalty value should be a positive integer.<br>It serves as a lever to manage the trade-off between strictly adhering to the depot's loading rate limits and the operational benefits of completing a higher volume of deliveries/pickups. A higher penalty favors the loading rate limits over task fulfillment. |
| `options` | object | It represents the set of options that can be used to configure optimization algorithms so that the solver provides a solution that meets the desired business objectives. |
| `options.objective` | object | This attribute is used to configure the objective of the optimization job. |
| `options.objective.travel_cost` | string | The `travel_cost` parameter specifies the type of cost used by the solver to determine the routes.<br>If the `travel_cost` parameter is set to `distance`, the solver will minimize the total distance traveled by vehicles while determining a solution. This objective would be useful in cases where the primary objective is to reduce fuel consumption or travel expenses.<br>If the `travel_cost` parameter is set to `duration`, the solver will minimize the total time taken by the vehicles to complete all tasks while determining a solution. This objective would be useful in cases where the primary objective is to minimize completion time or maximize the number of orders fulfilled within a given time window.<br>If the `travel_cost` parameter is set to `air_distance`, the solver will try to calculate the distance,in meters, between two points using the great-circle distance formula (i.e., the shortest distance between two points on a sphere) instead of the actual road distance. This would be useful in cases where the delivery locations are far apart and the road distance between them is significantly longer than the actual straight-line distance. For example, in Drone Delivery services.<br>If the `travel_cost` is set to `customized` the solver would use the custom cost values provided by the user (in `cost_matrix` attribute) and prefer a solution with lower overall cost. This enables the user to have greater control over the routes preferred by the solver and hence the sequence in which the jobs are completed. |
| `options.objective.custom` | object | The `custom` parameter is used to define special objectives apart from the simpler travel cost minimization objectives. |
| `options.objective.custom.type` | string | The `type` parameter accepts two inputs:<br>*   `min`: This type of customized objective will minimize the metric provided in the `value` parameter.<br>*   `min-max`: This type of customized objective will approximate an even distribution of the metric provided in the `value` parameter, among all the routes in solution.<br>Please note that `type` is mandatory only when using `custom` attribute. |
| `options.objective.custom.value` | string | The `value` parameter accepts four inputs, two of them are valid for `min` type and other two are valid for `min-max` type custom objective. Let’s look at the values for `min` type objective:<br>*   `vehicles`: Solver will minimize the number of vehicles used in the solution.<br>*   `completion_time`: Solver will minimize the total time taken to complete all tasks.<br>The next set of values are acceptable when `type` is set to `min-max`.<br>*   `tasks`: Solver will evenly distribute the tasks on each route.<br>*   `travel_cost`: Solver will assign tasks such that the traveling cost of each route is within a close range of other routes. The travel cost metric considered here is the one set using `objective.travel_cost` .<br>Please note that `value` is mandatory only when using `custom` attribute. The above values provide flexibility to tune the optimization algorithm to fulfill practical objectives beyond the relatively simpler time or distance minimization approaches. |
| `options.objective.allow_early_arrival` | boolean | Choose where the optimizer should schedule the driver’s wait time. When set to `true` the driver waits at the location of the task until its time window allows him to start the task. When set to `false` the driver waits at the location of the previous task and starts driving only at such a time that makes him arrive at the next task location in time to start the task as soon as he reaches. |
| `options.objective.solving_time_limit` | integer | Specify the number of seconds within which the optimizer should ideally solve the optimization request.<br>Please note that:<br>*   In case the specified time limit is not enough to generate a solution for a given problem set, the optimizer will continue processing until it arrives at a solution.<br>*   It is recommended to specify a duration of at least 5-7 minutes in case the input problem contains a large set of tasks or vehicles. |
| `options.constraint` | object | This attribute defines both the soft and hard constraints for an optimization job.<br>Soft constraints are constraints that do not necessarily have to be satisfied, but the optimization algorithm will try to satisfy them as much as possible. Whereas the hard constraints are the constraints that will not be violated by the solver. Users can use multiple constraints together.<br>Please note that soft constraints are ineffective when using `relations` attribute in a request. |
| `options.constraint.max_vehicle_overtime` | integer | This is a soft constraint for vehicle overtime. Overtime is defined as the time that a vehicle spends to complete a set of jobs after its time window has ended. `max_vehicle_overtime` attribute specifies the maximum amount of overtime a vehicle can have, in seconds. Use `vehicle_overtime_penalty` to regulate how optimizer's willingness to utilize/avoid overtime for a vehicle.<br>Please note that this constraint applies to all vehicles in the optimization request. |
| `options.constraint.vehicle_overtime_penalty` | integer | This parameter defines the penalty applied for every unit of time a vehicle operates beyond its scheduled time window. A higher penalty encourages the optimizer to minimize or eliminate overtime altogether. The default value is 200. The actual overtime allowed for the vehicle can be configured using `max_vehicle_overtime` setting.<br>Use this input to balance the benefits of higher task completion against the operational cost and duration of overtime. |
| `options.constraint.max_visit_lateness` | integer | This is a soft constraint for permissible delay, in seconds, to complete a job or shipment after its time window is over. If a job or shipment’s lateness exceeds this value, it will be considered a violation of this constraint.<br>Please note that this constraint applies to all tasks in the optimization request. In case lateness duration needs to be applied for individual tasks, please use the `max_visit_lateness` parameter under `jobs` and `shipments` |
| `options.constraint.visit_lateness_penalty` | integer | Specify the penalty to be applied for every unit of time by which a vehicle is late for a scheduled task. A higher penalty discourages any lateness for a scheduled task. The default value is 10. Use \`max_visit_lateness\` to set actual delay allowed to fulfill any task after its schedule window ends.<br>Use this input strike a balance between the benefits of efficient routes and adherence to service quality/customer expectations. |
| `options.constraint.sequence_order_penalty` | integer | Specify the penalty to be applied if a task is not fulfilled at its requested `jobs.sequence_order`. This penalty is ineffective if `jobs.sequence_order` is not provided. The default value is 10000. |
| `options.routing` | object | This attribute is used to define the routing configurations for the optimization job. |
| `options.routing.mode` | string | Define the traveling mode to be used for determining the optimized routes. Only the `car` profile is enabled by default. Please note that other profiles might not be available for all regions. Please contact your [NextBillion.ai](http://NextBillion.ai) account manager or reach out at [support@nextbillion.ai](mailto:support@nextbillion.ai) in case you need additional profiles |
| `options.routing.traffic_timestamp` | integer | Specify the general time when the job needs to be carried out. The time should be expressed as an UNIX timestamp in seconds format. The solver will take into account the general traffic conditions at the given time to determine the routes and their ETAs. |
| `options.routing.truck_size` | string | Specify the truck dimensions, in centimeters, in the format of “height,width,length”. Please note that this parameter is effective only when `mode=truck`. |
| `options.routing.truck_weight` | integer | Specify the truck weight including the trailers and shipped goods, in kilograms. Please note that this parameter is effective only when `mode=truck`. |
| `options.routing.avoid` | array of string | Specify the type of objects/maneuvers that the route should avoid. This is a soft-constraint. The optimizer would try to avoid the given objects/maneuvers as long as there are feasible, alternative routes present. If not, then it will use the route containing the given objects/maneuvers.<br>Please note that:<br>*   By default `ferry` routes are set to be avoided. Please use `none` to allow `ferry` routes.<br>*   The values are case-sensitive.<br>*   When using `avoid:bbox` feature, users need to specify the boundaries of the bounding box to be avoided. Multiple bounding boxes can be provided simultaneously. Please note that bounding box is a hard filter and if it blocks all possible routes between given locations, a 4xx error is returned. Mention the bounding box boundaries in the following format: bbox: min_latitude,min_longitude,max_latitude,max_longitude.<br>*   When using `avoid=sharp_turn`, the range of allowed turn angles is \[120,240\] in the clockwise direction from the current road. Any roads with turn angles outside the range will be avoided. |
| `options.routing.exclude` | array of string | Specify the type of objects/maneuvers that the route should exclude. This is a hard-constraint. The optimizer would exclude the given objects/maneuvers and return feasible, alternative routes. If no feasible, alternative routes are available, a 4xx error is returned.<br>Please note that:<br>*   By default `ferry` routes are set to be excluded. Please use `none` to allow `ferry` routes.<br>*   The values are case-sensitive.<br>*   When using `exclude=sharp_turn`, the range of allowed turn angles is \[120,240\] in the clockwise direction from the current road. Any roads with turn angles outside the range will be avoided. |
| `options.routing.disable_cache` | boolean | Specify if the optimizer should cache the matrix result set (containing ETAs and distances) for the given set of locations in the request. Once the results are cached, the optimizer can use it during the next 60 mins if exactly the same set of locations are provided again. Please note that if a cached result is retrieved, the timer is reset and that result will be available for another 60 mins.<br>If the users want to regenerate the result set, they can set this parameter to `true` and optimizer will not use the cached results.<br>This feature is helpful in expediting the optimization process and generate results quickly. It also helps users to quickly simulate route plans for different combinations of constraints for a given set of locations. |
| `options.routing.hazmat_type` | array of string | Specify the type of hazardous material being carried and the service will avoid roads which are not suitable for the type of goods specified. Provide multiple values separated by a comma `,` .<br>Please note that this parameter is effective only when `mode=truck`. |
| `options.routing.profiles` | object | Defines all the vehicle profiles. `profiles` is implemented as a dictionary of objects where each profile name is the unique key and the associated value is an object describing the routing properties of that profile. All routing properties available in `options.routing` can be added as values for a given profile.<br>Please note:<br>*   The routing properties configured using `options.routing` (and not part of any \`profiles\`) are considered as default route settings i.e. they are applied to vehicles which are not associated with any profile.<br>*   The default route settings are independent from those defined for any `profiles` . Consequently, for vehicles which are tagged to a given profile, only the routing properties configured for the given profile will apply.<br>*   If the "mode" is not specified for any profile, by default it is considered to be `car` .<br>*   "default" is a reserved keyword and can not be used as the name for any custom profile.<br>*   `profiles` can't be nested in other profiles.<br>*   The number of profiles, including default route settings, are limited to<br>    *   15, if 0 < number of location <= 100<br>    *   6, if 100 < number of location <= 600，<br>    *   2, if 600 < number of location <= 1200,<br>    *   1, if number of location > 1200<br>Routing profiles attribute is useful for configuring fleets containing multiple vehicles types. Check [Routing Profiles](https://docs.nextbillion.ai/docs/optimization/api/route-optimization-flexible/tutorials/routing-profiles) tutorial to learn more. |
| `options.routing.allow` | array of string | Use this parameter to let the optimizer use taxi-specific lanes/roads for calculating routes. When not specified, the routes generated will not use any taxi specific lanes. It is effective only when `mode=car`. |
| `options.routing.cross_border` | boolean | Specify if crossing an international border is allowed for operations near border areas. When set to false, the API will prohibit any routes crossing international borders. When set to true, the service will return routes which cross the borders between countries, if required for the given set `locations`<br>This feature is available in North America region only. Please get in touch with [support@nextbillion.ai](mailto:support@nextbillion.ai) to enquire/enable other areas. |
| `options.routing.truck_axle_load` | number | Specify the total load per axle (including the weight of trailers and shipped goods) of the truck, in tonnes. When used, the optimizer will use only those routes which are legally allowed to carry the load specified per axle.<br>Please note this parameter is effective only when `mode=truck`. |
| `options.grouping` | object | Set grouping rules for the tasks and routes.<br>*   Use `order_grouping` to group nearby tasks<br>*   Use `route_grouping` to control route sequencing. |
| `options.grouping.order_grouping` | object | Specify the criteria for grouping nearby tasks. The grouped tasks will be treated as one stop by the optimizer and no cost would be incurred when driver travels to different tasks within a group. Users can use this feature to model use cases like multiple deliveries in a building complex or a condo.<br>Please note that when the multiple tasks are grouped together, only one setup time is considered for all such tasks. The durations of this setup time is equal to maximum setup time among all grouped tasks, if provided. On the other hand, the service time is applied to each task individually, as per the input provided when configuring those tasks. |
| `options.grouping.order_grouping.grouping_diameter` | number | Specify the straight line distance, in meters, which will be used to identify the tasks that should be grouped together. The default value is `null`. |
| `options.grouping.route_grouping` | object | Specifies the criteria for preferring routes in a given zone over routes that are part of another zone. As a result, more often than not, the tasks falling in a zone will be fulfilled before tasks that are part of a different zone. |
| `options.grouping.route_grouping.zone_source` | string | Specify the source for creating boundaries of the routing zones. The default value is “system_generated”.<br>*   system_generated - Routing zone boundaries are created automatically by the optimizer based on the `zone_diameter` provided.<br>*   custom_definition - Custom routing zone boundaries should be provided by the user in input using the `zones` attribute. An error would be returned if the `zones` attribute is null or missing in the input request. |
| `options.grouping.route_grouping.zone_ids` | array of integer | An array of IDs associated with custom defined zones to be used for route grouping. Please note:<br>*   This parameter is effective only when `"zone_source": "custom_definition"`<br>*   Use the `zones` attribute to define custom route grouping zones/boundaries. |
| `options.grouping.route_grouping.zone_diameter` | number | Specify the diameter of the zone, routes within which will be prioritized before routes falling in other zones. Please note<br>*   `zone_diameter` is the straight line distance, in meters.<br>*   It is effective only when `"zone_source": "system_generated"`. |
| `options.grouping.route_grouping.penalty_factor` | number | Specify a non-negative value which indicates the penalty of crossing zones on the same route. Default penalty value is 0.<br>A higher value, for example 30.0, will place a higher penalty on zone violations and hence push the optimizer to prefer a solution without any zone violations, where all tasks in a single region are fulfilled before any tasks in other regions or outside the current region. Whereas a lower value, say 5.0, will place a lower penalty allowing the optimizer to return solutions which may have few violations, say a couple of routing zone violations in our example. A still lower penalty factor, like 1.0, may have several zone violations. |
| `options.grouping.proximity_factor` | number | When specified, routes are built taking into account the distance to the nearest tasks. A higher proximity factor helps build routes with closer distances between neighboring tasks, whereas a lower proximity factor helps build routes with farther distances between neighboring tasks. As a result, the total number of routes in the solution can vary based on the configured proximity factor - more routes for higher factor and less routes with lower factor.  <br>In practice, such routes are more resistant to changes in task time windows: when the time window is postponed, the driver can drive to the next task and then return to the previous one.  <br>Please note that:<br>*   Valid values are \[0,10\]<br>*   Default value is 0.0.<br>*   It is recommended to use values lower values, in the range of \[0, 1\]. Higher values may adversely impact the solution metrics due to higher number of resulting routes: costs, mileage etc. |
| `options.report_unused_vehicle_reason` | boolean | A flag to allow returning the reasons for vehicles that were not used in the final solution, even when unassigned tasks exist. Default is `false`. When `true`, the reasons for having idle/unassigned vehicles in final solution are present under `unused_vehicles` in the response. |
| `options.webhook` | object | Use this attribute to configure your webhook configurations for receiving status updates about submitted optimization requests. Read more about this attribute in the [Webhook Configurations](#webhook-configurations) section. |
| `options.webhook.url` | string | Specify your webhook URL. Please note only HTTP(s) are supported. The URL provided here will be called by the optimization service using a HTTP POST method along with event payload. |
| `options.webhook.events` | array of string | Specify the subscription that you want to subscribe to i.e. receive them on the webhook `url` configured above. Currently, "JOB_CREATED", "JOB_COMPLETED" and "JOB_FAILED" type events are supported. |
| `options.webhook.timeout` | integer | Specify a timeout period, in seconds. The timeout specified here will be used for retries - repeat event notifications - if a successful acknowledgement from the webhook URL is not received within the specified duration. Please note that:<br>*   Default values is 10 seconds.<br>*   The valid range of values that can be provided is \[1, 60\].<br>*   The optimization service will attempt a maximum of 3 retries, with each attempt occurring after a successive `timeout` period. |
| `solution` | array of object | This attribute is related to the re-optimization feature. It allows for the previous optimization result to be provided in case new orders are received and the solution needs to be re-planned. The `solution` attribute should contain the same routes as the previous optimization result. `solution` attribute is an array of objects with each object corresponding to one route. |
| `solution[].vehicle` | string | Specify the ID of the vehicle that was assigned to the route. This field is mandatory when using the `solution` attribute and providing an empty string would result in error. The IDs are case-sensitive.<br>**Note:** Since the vehicles can be configured using either a string or an integer ID, please ensure that the same value type is provided for this field as was used in the original request. |
| `solution[].cost` | integer | Specify the cost of the route. |
| `solution[].steps` | array of object | Describe the steps in this route. |
| `solution[].steps[].type` | string | Specify the type of the step. |
| `solution[].steps[].id` | string | The ID of the step. This field is mandatory for all steps except for `start` and `end` type.<br>Please note that the ID provided here must also be present in either the `jobs` or the `shipments` objects.<br>**Note:** We have modified the data type of this field. The latest change is backward compatible and both integer and string type IDs are valid for this field, as long as they match the IDs of the jobs or shipments already configured. |
| `solution[].steps[].arrival` | integer | Specify the time at which the vehicle arrives at the `step` location. If `time_windows` is provided, then `arrival` will be an UNIX timestamp expressed in seconds. Otherwise, it will be the total duration, in seconds, elapsed since the start of the route.<br>Please note that arrival is mandatory when using the `solution` object. |
| `solution[].steps[].duration` | integer | Specify the drive time, in seconds, from the start of the route up until the start of the `step`. Please note that the value of this parameter accumulates with each step. |
| `solution[].steps[].location` | array of number | Specify the location coordinates of the step in the \[latitude, longitude\] format. Alternatively, `location_index` property can also be used to specify the location of the step.<br>Please note that either `location` or `location_index` is mandatory. |
| `solution[].steps[].location_index` | integer | Specify the index (in the `location` array) of the location coordinates where the step is performed. The valid range of values is \[0, length of `location` array). Alternatively, `location` property can also be used to specify the location.<br>Please note that either `location` or `location_index` is mandatory. |
| `solution[].steps[].service` | integer | Specify the service time, in seconds, at this step. |
| `solution[].steps[].waiting_time` | integer | Specify the wait time of the vehicle at this step, in seconds. |
| `solution[].steps[].load` | array of integer | Specify the load on the vehicle after completing this step. In case of multiple dimensions, please specify the load for each type. |
| `solution[].steps[].description` | string | Specify the description of this step. |
| `solution[].steps[].setup` | integer | Specify the set-up duration, in seconds, needed at the step. |
| `solution[].steps[].distance` | integer | Specify the distance covered, in meters, from the start of the route up until the current step.<br>Please note that the value of this parameter accumulates with each step. In case , the `travel_cost: air_distance`, then the distance here should be the straight line distance. |
| `solution[].duration` | integer | Specify the total drive duration of the route, in seconds. |
| `solution[].distance` | integer | Specify the total distance of the route, in meters. |
| `solution[].geometry` | string | Specify the geometry of this route encoded in polyline format. |
| `solution[].service` | integer | Specify the total service time for the route, in seconds. |
| `solution[].waiting_time` | integer | Specify the total waiting time of the vehicle on the route, in seconds. |
| `solution[].priority` | integer | Specify the sum of priorities of all tasks on the route. |
| `solution[].delivery` | array of integer | Specify the total quantities, for each dimension (or unit), of deliveries performed in the route. |
| `solution[].pickup` | array of integer | Specify the total quantities, for each dimension (or unit), of pickups performed in the route. |
| `solution[].description` | string | Specify the description of the assigned vehicle. |
| `solution[].setup` | integer | Specify the total set-up duration, in seconds, needed for the tasks on the route. |
| `unassigned` | object | `unassigned` attribute is related to the re-optimization feature. This attribute should contain the tasks that were not assigned during an earlier optimization process. Please note that the `unassigned` part in request should be consistent with the `unassigned` part in the previous optimization result.<br>Users can reduce the number of unassigned tasks in the re-optimized solution, by following strategies such as:<br>*   Extending the time windows for vehicles or tasks to give more flexibility<br>*   Adding more vehicles to the optimization problem<br>*   Adjusting the priority of different tasks to balance the workload more evenly<br>*   Modifying other constraints or parameters to make the problem more solvable<br>Ultimately, the goal is to minimize the number of unassigned tasks while still meeting all the necessary constraints and objectives. |
| `unassigned.jobs` | array of string | Specify the unassigned job IDs from the previous optimization result. Please note the IDs should also be present in the `jobs` part of the input.<br>**Note:** We have modified the data type of this field. However, the latest change is backward compatible and both integer and string type job IDs are valid for this field, as long as they match the IDs of the jobs already configured. Providing mixed value types in the array, will lead to an error. |
| `unassigned.shipments` | array of array of string | Specify the unassigned shipment pickup & delivery IDs from the previous optimization result. Both the pickup & delivery steps of a shipment should be part of the same array.<br>**Note:** We have modified the data type of this field. However, the latest change is backward compatible and both integer and string type shipment IDs are valid for this field, as long as they match the IDs of the shipments already configured. Providing mixed value types in the array, will lead to an error. |
| `description` | string | Define the optimization job using any custom message. This description is returned as is in the response. |
| `relations` | array of object | `relations` attribute is an array of individual relation objects. `type` parameter and `steps` object are mandatory when using this attribute.<br>Please note:<br>*   The soft constraints are **not** effective when using the `relations` attribute.<br>*   In case a given relation can't be satisfied, the optimizer will flag all the tasks involved in that "relation" as unassigned.<br>*   Since the `relations` feature is suited for associating more than one tasks in desired sequences or routes, the outcome when only 1 task is provided for a relation can be non-optimal or unexpected.<br>Read more about this attribute in the [Relations Object](#relations-object) section. |
| `relations[].type` | string | Specifies the type of relation constraint. The following types are supported:<br>*   `in_same_route`: Ensures that all `steps` are covered in the same route in solution.<br>*   `in_sequence`: Ensures that all steps are in the same route and their sequence matches the order specified in the `steps` field. Insertion of new steps between the `steps` specified, is allowed.<br>*   `in_direct_sequence`: Similar to `in_sequence`, but insertion of new `steps` is not allowed in the final route.<br>*   `precedence`: Restricts the travel time between the first step and second step. If the precedence requirement cannot be satisfied, then the task specified at the second step will not be assigned. Only 2 steps can be specified in a single `precedence` type relations. Please use multiple `precedence` relations to apply restrictions on more than 2 tasks.<br>*   `pinned`: Pins given `steps` to the specified vehicle. When pinned, the `steps` can not be left unassigned and will override any penalty or cost considerations which otherwise, could have left the `steps` unassigned. Please note:<br>    *   Providing a `vehicle` input when using this relations type is mandatory.<br>    *   Any `steps` part of a pinned type relation cannot be part of any other relation.<br>    *   There is no partial success for pinned `steps`. The entire optimization request fails if any of the pinned tasks can not be fulfilled.<br>    *   It is recommended to "pin" all `steps` to be done by same vehicle using a single relation.<br>If the `vehicle` field is specified in the relations input, all steps will be served by that particular vehicle. Otherwise, the route can be allocated to any feasible vehicle.<br>Please note that the `type` field is mandatory when using the `relations` object. |
| `relations[].steps` | array of object | The `steps` property specifies the tasks or steps that are part of the relation and must be carried out in a manner defined in the `type` parameter. Please note you can add any number of steps here, except when relation type is `precedence` where only 2 tasks can be added. |
| `relations[].steps[].type` | string | Specifies the type of the step. The `start` and `end` step types have to be the first and last steps, respectively, in a relation.<br>Please note that the `type` is mandatory when using the `relations` object. |
| `relations[].steps[].id` | string | This represents the ID of the task and should be consistent with the input IDs provided in the `jobs` or `shipments` objects for a given step. The `id` is required for all steps other than `start` and `end`. |
| `relations[].vehicle` | string | Specifies the ID of the vehicle that would fulfill the steps. This field is mandatory when using `type = pinned`. Providing the same vehicle ID to multiple ‘relations’ is prohibited. The vehicle ID provided here should be consistent with ID provided in the `vehicles` attribute. |
| `relations[].max_duration` | integer | This attribute is effective only when `precedence` type relation is used. `max_duration` restricts the travel time of the vehicle to go from location of first task to the location of second task specified in `steps` object. The unit for this parameter is seconds. It accepts values greater than 0 only.<br>This attribute is helpful in modeling scenarios where a given task has to be done within a limited duration of another task.<br>Please note that `max_duration` is a hard constraint. Hence, if aggressive durations are provided such that the second task cannot be reached within the specified `max_duration`, it might be done before the first task (usually in case of `jobs`) or remain un-assigned (usually in case of `shipments`). |
| `relations[].min_duration` | integer | This attribute is effective only when `precedence` type relation is used. Use `min_duration` to enforce a minimum time-gap between the two tasks specified in `steps` object. When specified, the second task will get completed after a gap of `min_duration` with respect to the first task. The unit for this parameter is seconds.<br>This attribute is helpful in modeling scenarios where a given task has to be done only after/before a minimum duration of another task.<br>Please note that `min_duration` is implemented as a soft constraint and it can be violated in presence of other relation types. The optimizer will tend to provide solutions where `min_duration` is not violated, but it is not guaranteed. |
| `relations[].id` | integer | **Deprecated! Please use the** `vehicle` **parameter to specify the vehicle ID.**<br>Specifies the ID of the vehicle that would fulfil the steps. ID should be consistent with input IDs provided in the `vehicles` object. |
| `cost_matrix` | array of array of integer | An array of arrays to denote the user-defined costs of traveling between each pair of geographic coordinates mentioned in the `location` array. The number of arrays should be equal to the number of coordinate points mentioned in the `location` array and each array should contain the same number of elements as well. Please note that `cost_matrix` is effective only when `travel_cost=customized`. Read more about this attribute in the [Custom Cost Matrix](#custom-cost-matrix) section. |
| `zones` | array of object | An array of objects to specify geometry of all the zones involved. Each object corresponds to a single zone. A valid zone can be a [geoJSON](https://datatracker.ietf.org/doc/html/rfc7946#page-9) polygon, multi-polygon or a geofence created using [NextBillion.ai](http://NextBillion.ai)’s [Geofence API](https://docs.nextbillion.ai/docs/tracking/api/geofence).<br>Please note that<br>*   Each zone should have a geometry specified either through`geometry` or through the `geofence_id` parameter.<br>*   When zone IDs are not provided for individual tasks (jobs or shipments) then the API will automatically allocate zones based on the task’s geolocation and the geometries of the zones provided here. Otherwise, if the zone IDs are provided while configuring individual tasks, the zone IDs will override the geometries provided here.<br>*   `zones` input becomes mandatory when `options.grouping.route_grouping.zone_source` is set to "custom_definition". |
| `zones[].id` | integer | Provide an ID for the zone. This field is mandatory when adding zones. |
| `zones[].geometry` | object | It is a [geoJSON object](https://datatracker.ietf.org/doc/html/rfc7946#page-9) with details of the geographic boundaries of the zone. Only “Polygon” and “MultiPolygon” geoJSON types are supported.<br>Please note that one of `geometry` or `geofence_id` should be provided. |
| `zones[].geometry.type` | string | Type of the geoJSON geometry. Should always be `Polygon` or `MultiPolygon`. |
| `zones[].geometry.coordinates` | array of array of number | An array of coordinates in the \[longitude, latitude\] format, representing the zone boundary. |
| `zones[].geofence_id` | string | Provide the ID of a pre-created geofence using the [Geofence API](https://docs.nextbillion.ai/docs/tracking/api/geofence).<br>Please note that one of `geometry` or `geofence_id` should be provided. |
| `distance_matrix` | array of array of integer | An array of arrays to denote the user-defined distances, in meters, for travelling between each pair of geographic coordinates mentioned in the `location` array. When this input is provided, actual distances between the locations will be ignored in favor of the values provided in this input for any distance calculations during the optimization process. The values provided here will also be used for cost calculations when `travel_cost` is “distance”.<br>The number of arrays in the input should be equal to the number of coordinate points mentioned in the `location` array and each array, in turn, should contain the same number of elements as well. Please note that`duration_matrix` is mandatory when using`distance_matrix`. |
| `duration_matrix` | array of array of integer | An array of arrays to denote the user-defined durations, in seconds, for travelling between each pair of geographic coordinates mentioned in the `location` array. When this input is provided, actual durations between the locations will be ignored in favor of the values provided in the matrix for any ETA calculations during the optimization process. The values provided in the matrix will also be used for cost calculations when `travel_cost` is “duration”.<br>The number of arrays in the input should be equal to the number of coordinate points mentioned in the `location` array and each array, in turn, should contain the same number of elements as well.<br>Please note that, unlike `distance_matrix`, `duration_matrix` can be used independently in following cases:<br>*   when `travel_cost` is “duration”<br>*   when `travel_cost` is “customized” and a `cost_matrix` is provided. |

### Response Schema

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | A unique ID which can be used in the Optimization GET method to retrieve the result of optimization. |
| `message` | string | Displays an acknowledgement message once the job is submitted. |
| `status` | string | A string indicating the state of the response. On successful responses, the value will be `Ok`. Indicative error messages/codes are returned in case of errors. See the [API Error Codes](#api-error-codes) section below for more information. |
| `warnings` | array of string | Display the warnings for the given input parameters, values and constraints. |

## Retrieve Optimized Solution

GET

https://api.nextbillion.io/optimization/v2/result?id={id}&key={your_api_key}

  

Use this method to retrieve the optimized solution for the optimization tasks created using the method listed in *Build an Optimization Request* or *Re-optimize An Existing Solution* sections above.

A point worth highlighting here is that the optimizer uses traffic conditions at the time of making the request to prepare a solution. Slight changes in traffic conditions can cause the optimizer to prefer different routes and possibly different sequences in which to fulfill the jobs or shipments. Therefore, different optimization requests made with similar task or constraint configuration are expected to return different optimized solutions.

### Request Parameters

| Name | Required | Format and Usage | Description |
|------|----------|------------------|-------------|
| `key` | Yes | Type: `string`<br>Format: 32 bit alphanumeric character<br>Example: key=API_KEY | A key is a unique identifier that is required to authenticate a request to the API. |
| `id` | Yes | Type: `string` | The unique ID that was returned on successful submission of the Optimization POST request. |

### Response Schema

| Field | Type | Description |
|-------|------|-------------|
| `description` | string | Returns the `description` of the optimization job as given in the input POST optimization request. This field will not be present in the response if no `description` was provided in the input request. |
| `request_created_time` | integer | Returns an UNIX timestamp, in seconds precision, when the optimization input request was created. |
| `solution_created_time` | integer | Returns an UNIX timestamp, in seconds precision, when the optimizer finished creating an optimized solution for the input request. |
| `result` | object | An object containing the details of the optimized routes. |
| `result.code` | integer | A custom code representing the status of the result. A code other than 0, represents an internal error. In case of codes other than 0, please verify the parameter values, constraints and locations. If the issue does not resolve, please reach out to NextBillion at [support@nextbillion.ai](mailto:support@nextbillion.ai). |
| `result.summary` | object | An object to describe the summarized result of the optimization request. This object can be useful to quickly get an overview of the important result parameters. |
| `result.summary.cost` | integer | Returns the total cost of all the routes returned in the solution. The unit of cost type depends on the value of `travel_cost` attribute in the optimization request. |
| `result.summary.routes` | integer | Returns the total number of routes in the solution. |
| `result.summary.unassigned` | integer | Returns the number of unfulfilled tasks in the solution. |
| `result.summary.duration` | integer | Returns the total drive time, in seconds, needed to cover all routes. Please note that it does not include the service, setup or the waiting durations elapsed on these routes. |
| `result.summary.distance` | number | Returns the total distance of all routes, in meters. It is equal to the sum of distances of individual routes. |
| `result.summary.setup` | integer | Returns the total setup time, in seconds, of all assigned tasks. It is equal to the sum of setup time of individual tasks that were assigned. |
| `result.summary.service` | integer | Returns the total service time, in seconds, for all the routes in the solution. It is equal to the sum of service time of individual tasks that were assigned and the service plus handling time spent loading/unloading items at designated depots by all vehicles. |
| `result.summary.waiting_time` | integer | Returns the sum of durations spent waiting, in seconds, by vehicles on all routes. |
| `result.summary.priority` | integer | Returns the sum of priorities of all tasks that were assigned. |
| `result.summary.delivery` | array of integer | Returns the sum of all quantities that were delivered in the optimized solution. If quantities of different dimensions were delivered, then a matching number of elements is returned in the `delivery` array.<br>Please note that when both `shipments` and `jobs` are provided, this field corresponds to the sum of quantities delivered as part of all the assigned `shipments` and `jobs` . |
| `result.summary.pickup` | array of integer | Returns the sum of all quantities that were picked-up in the optimized solution. If quantities of different dimensions were picked-up, then a matching number of elements is returned in the `pickup` array.<br>Please note that when both `shipments` and `jobs` are provided, this field corresponds to the sum of quantities picked-up as part of all the assigned `shipments` and `jobs` . |
| `result.summary.revenue` | integer | Returns the revenue earned by completing all the assigned tasks. Overall profit earned by following the suggested route plan can be inferred by subtracting the `cost` of the solution from the reported `revenue`. |
| `result.summary.total_visit_lateness` | integer | Returns the total duration, in seconds, that tasks across all routes were delayed from starting after their scheduled time windows had passed. |
| `result.summary.num_late_visits` | integer | Returns the total number of tasks across all routes that failed to start within their scheduled time windows. |
| `result.summary.total_vehicle_overtime` | integer | Returns the total overtime duration, in seconds, accumulated by vehicles across all routes while working beyond their scheduled shift durations. |
| `result.summary. num_vehicle_overtime` | integer | Returns the total number of vehicles across all routes that worked beyond their shift timings to fulfill additional tasks. |
| `result.unassigned` | array of object | An array of objects containing the details of unassigned tasks in the optimized solution. Each object represents one task. |
| `result.unassigned[].id` | string | Returns the ID of the unassigned task. The ID returned is the same as that provided for the given task in the `jobs` or the `shipments` part in the input POST optimization request.<br>**Note:** Since both integer and string value types are supported for task IDs, the value type returned for this field will depend on the value type provided in the input request for the unassigned task. |
| `result.unassigned[].type` | string | Returns the type of the task that was unassigned. Will always belong to one of `job`, `pickup`, or `delivery`. |
| `result.unassigned[].location` | array of number | Returns the location of the unassigned tasks in the \[latitude, longitude\] format. |
| `result.unassigned[].reason` | string | Returns the most likely reason due to which the task remained unassigned. The optimization service can capture the following causes of tasks remaining unassigned, among others:<br>*   unmatched `skills` of the tasks<br>*   insufficient `capacity` of vehicle to accommodate the tasks<br>*   `time_window` requirements of the tasks or the vehicles<br>*   violation of vehicle’s `max_tasks` or `max_stops` constraints<br>*   violation of vehicle’s `max_distance` or `max_travel_time` constraints<br>*   task unassigned due to zone constraints<br>*   task unassigned due to depot constraints<br>*   task unassigned due to load type incompatibility constraints<br>*   task unassigned due to max time in vehicle constraint<br>*   task unassigned as it is unprofitable<br>*   task unassigned due to low outsourcing cost<br>*   task unassigned due to infeasible conditions specified in `relations` attribute |
| `result.unassigned[].outsourcing_cost` | integer | Returns the cost of outsourcing the task. This is the same value as provided in the input. The field is present only if a `outsourcing_cost` was provided for the unassigned task. |
| `result.unused_vehicles` | array of object | Returned when `report_unused_vehicle_reason` was set as "true" in the input and there exist unassigned tasks along with idle/unused vehicles in the final solution. |
| `result.unused_vehicles[].vehicle` | string | Returns the ID of the vehicle. |
| `result.unused_vehicles[].reasons` | array of string | Returns all reasons which caused the given vehicle to remain idle or unused in the final solution. Please note:<br>*   The `reasons` are aggregated for each vehicle and represent a universal, non-repeating set of reasons due to which the vehicle remained unassigned.<br>*   Feasibility check is at an individual task level. The `reasons` do not account for a group or combination of tasks that remained unassigned. |
| `result.unused_vehicles[].feasible_unassigned` | boolean | Indicates the category of reasons which caused the vehicle to remain unassigned.<br>A `false` value indicates that the vehicle could not be used due to capability or hard-constraints related reasons (skill, capacity, time windows, zones, max\_tasks etc).<br>Whereas, a `true` value indicates the vehicle was not used to due to cost/objective related reasons, but was absolutely capable of fulfilling at least one of the unassigned tasks. |
| `result.routes` | array of object | An array of objects containing the details of each route in the optimized solution. Each object represents one route. |
| `result.routes[].vehicle` | string | Returns the ID of the vehicle that was assigned to the route. The value type will be same as the value type provided in the input request. |
| `result.routes[].cost` | integer | Returns the cost of the route. The unit of cost type depends on the value of `travel_cost` attribute in the optimization request. |
| `result.routes[].steps` | array of object | This attribute contains the details of all the steps involved in the route. It is an array of objects with each object representing one step. |
| `result.routes[].steps[].id` | string | Returns the ID of the task. The ID returned here are the same values that were provided for the given task in the `jobs` or the `shipments` objects of the input POST optimization request.<br>**Note:** Since both integer and string value types are supported for job IDs, the value type returned for this field will depend on the value type provided in the input request. |
| `result.routes[].steps[].type` | string | Returns the type of the step. In case the step type is `start` , `break`, `layover` or `end`, the `steps` object will not have the `id` field. |
| `result.routes[].steps[].arrival` | integer | Returns the time at which the vehicle arrives at the `step` location. If `time_windows` is provided for the task it will be returned as an UNIX timestamp expressed in seconds. When `time_windows` is not provided, it is returned as the total duration, in seconds, elapsed since the start of the route.<br>Please note it includes all the other durations as well (setup, service, waiting). |
| `result.routes[].steps[].duration` | integer | Returns the total drive time, in seconds, from the start of the route up until the start of the `step`. Please note that this value does not include any other category of durations (service, wait, setup) and the value of this parameter accumulates with each step. |
| `result.routes[].steps[].location` | array of number | Returns the location coordinates of the step in the \[latitude, longitude\] format.<br>The index of this location is also returned by the `location_index` parameter. |
| `result.routes[].steps[].estimated_location` | array of number | Returns the coordinates of the location where the driver can take a break. It represents only an _estimate_ and _not the actual location_ where the break must be taken. Please note that this field is available in the response only for `break` step type. Additionally, a missing `estimated_location` field for a `break` step means that the location could not determined reliably. |
| `result.routes[].steps[].projected_location` | array of number | In case this step is part of a task group, this field returns the location coordinates of the point, in \[latitude, longitude\] format, which was used as a common stop for all grouped tasks. |
| `result.routes[].steps[].location_index` | integer | Returns the index (in the `location` array) of the location coordinates where the step is performed. The index will always be in the range of \[0, length of `location` array).<br>Actual coordinates are also returned by the `location` parameter. |
| `result.routes[].steps[].load` | array of integer | Returns the load on the vehicle after completing this step. In case of multiple dimensions, loads of each type are returned by a matching number of elements in the array. |
| `result.routes[].steps[].service` | integer | Returns the service time, in seconds, for the task when the step type is not `start` or `end`.<br>When the step type is `start` or `end` , the field also returns the service time plus `handling_duration`, in seconds, spent at the depot when if the vehicle is starting or completing the trip at one of the depots. |
| `result.routes[].steps[].waiting_time` | integer | Returns the wait time of the vehicle at this step, in seconds. |
| `result.routes[].steps[].setup` | integer | Returns the setup time, in seconds, for the task. |
| `result.routes[].steps[].late_by` | string | Returns the amount of time, in seconds, by which the vehicle is late when arriving at this step. Please note this field is present only when there is a non-zero value for vehicle lateness, otherwise it is not present in the response. |
| `result.routes[].steps[].description` | string | Returns the description of this step. The description returned here are the same values that were provided for the given task in the `jobs` or the `shipments` objects of the input POST optimization request. |
| `result.routes[].steps[].distance` | integer | Returns the distance covered, in meters, from the start of the route and up until the current step.<br>Please note that the value of this parameter accumulates with each step. In case , the `travel_cost: air_distance`, then the distance here represents straight line distance. |
| `result.routes[].steps[].snapped_location` | array of number | Returns the coordinates after snapping the location of this step to a nearby road. Please note that this field will not be available in the response when custom duration or distance matrix were used for cost calculations. |
| `result.routes[].steps[].run` | integer | When a vehicle is configured to make multiple runs to the depot (via `max_depot_runs`), this field returns the iteration to which the step belongs to. Each run will begin with a "start" step from the depot's location and conclude with an "end" step at either the last task's or the configured end location. |
| `result.routes[].steps[].depot` | string | For step type "start" or "end", this field returns the ID of the depot relevant to that step. For "start" steps, the field will contain the ID of the depot from which the vehicle commenced its journey. Conversely, for "end" steps, the field will hold the ID of the depot where the vehicle concluded its trip.<br>Please note that `start_depot_ids` or `end_depot_ids` input for the vehicle must be configured to get this field in the response for respective step types in a route. |
| `result.routes[].steps[].split_indicator` | integer | Indicates that the step relates to a sub-task of a "job" that was split across multiple vehicles. It represents an unique identifier for each part of the task. The load associated with this split part is indicated in the corresponding `pickup` or `delivery` field. This field does not indicate the positional sequence of the split step. |
| `result.routes[].description` | string | Return the description of the assigned vehicle. It would be the same as that provided in the `description` field of `vehicles` part of the input POST optimization request. |
| `result.routes[].distance` | number | Returns the total distance of the route, in meters. |
| `result.routes[].duration` | integer | Returns the total drive duration of the route, in seconds. |
| `result.routes[].geometry` | string | Returns the geometry of this route encoded in polyline format. |
| `result.routes[].pickup` | array of integer | Returns the total quantities, for each dimension (or unit), of pickups performed in the route. Please note that when both `shipments` and `jobs` are provided, this field corresponds to the sum of quantities picked-up as part of the assigned `shipments` and `jobs` on the route. |
| `result.routes[].delivery` | array of integer | Returns the total quantities, for each dimension (or unit), of deliveries performed in the route. Please note that when both `shipments` and `jobs` are provided, this field corresponds to the sum of quantities delivered as part of the assigned `shipments` and `jobs` on the route. |
| `result.routes[].priority` | integer | Returns the sum of priorities of all tasks on the route. |
| `result.routes[].service` | integer | Returns the total time, in seconds, spent on the route's tasks and depots. This includes the service time at each task or depot, plus any `handling_duration` applied at the depots. |
| `result.routes[].vehicle_overtime` | integer | Returns the total vehicle overtime for the route, in seconds. Please note this field is present only when there is a non-zero value for vehicle overtime, otherwise it is not present in the response. |
| `result.routes[].waiting_time` | integer | Returns the total waiting time of the vehicle on the route, in seconds. |
| `result.routes[].setup` | integer | Returns the total setup time, in seconds, for the tasks assigned on the route. |
| `result.routes[].revenue` | integer | Returns the revenue earned by fulfilling the task on this route. Please note this field is present only when the revenue inputs are provided in the input, otherwise it is not present in the response. |
| `result.routes[].profile` | string | Returns the profile of the vehicle. |
| `result.routes[].adopted_capacity` | array of integer | Returns the capacity configuration of the vehicle that was used for this route. This field would return either the vehicle's `capacity` or one of the `alternative_capacities` provided in the input request. |
| `result.routes[].penalty` | object | Returns the details about the penalties applied to the route. |
| `result.routes[].penalty.min_stop_load` | integer | Returns the penalty applied to the route when one or more delivery tasks with loads lesser than the given `min_stop_load` threshold of the vehicle are assigned to it. This field will not be present in the response if both `min_stop_load_unit_penalty` and `min_stop_load_fixed_penalty` are not provided. |
| `result.routes[].penalty.depot_throughput` | integer | Returns the total of throughput penalties applied for this route. Throughput penalties can be applied either when `max_vehicles` or `max_load` limits of depot are exceeded. |
| `result.routes[].penalty.deadhead` | integer | Returns the total deadhead penalty incurred on the given route based on the deadhead constraints and penalties provided in the input. It contains the sum of penalties applied due to presence of `max_deadhead_distance` & `max_deadhead_duration` limitations. |
| `result.routes[].penalty.visit_lateness` | integer | Returns the penalty applied to the route because of the vehicle being late to fulfill scheduled tasks. |
| `result.routes[].penalty.sequence_order` | integer | Returns the penalty applied to the route when the jobs with `sequence_order` configured were not fulfilled at the requested sequence relative to other sequenced jobs. |
| `result.routes[].penalty.vehicle_overtime` | integer | Returns the penalty applied to the route when vehicle was required to work beyond its regular shift timings. |
| `result.routing_profiles` | object | Returns all the routing profiles used in the solution. If no routing profiles were provided in the input or if the vehicles tagged to profiles were not used in the solution, the "default" routing properties are returned. Default routing properties are indicated by `options.routing` in the input. |
| `result.error` | string | Returns the error message for unfulfilled optimization jobs. This field will not be present in the response in case there are no errors. |
| `status` | string | It indicates the overall status or result of the API request denoting whether the operation was successful or did it encounter any errors. |
| `message` | string | Returns the message in case of errors or failures, otherwise a blank string is returned. |

## Re-optimize An Existing Solution

POST

https://api.nextbillion.io/optimization/re_optimization?key={your_api_key}

Use this method to re-optimize an existing solution using the unique ID obtained when the original request was submitted via the *Build an Optimization Request* method.

When re-optimizing you can provide the details of tasks or vehicles to be modified, newly added or removed completely from the original solution. If a task or order doesn’t need to be changed in the re-optimized solution it can be left out of the re-optimization request.

After you successfully submit a re-optimization request, you'll receive a unique reference ID. Use the new reference ID with the *Retrieve Optimized Solution* method to get the new, re-optimized solution.

### Request Parameter

| Name | Required | Format and Usage | Description |
|------|----------|------------------|-------------|
| `key` | Yes | Type: `string`<br>Format: 32 bit alphanumeric character<br>Example: key=API_KEY | A key is a unique identifier that is required to authenticate a request to the API. |

### Request Body

| Field | Type | Description |
|-------|------|-------------|
| `existing_request_id` | string | Specify the unique request ID that needs to be re-optimized. |
| `vehicle_changes` | object | This section gathers information on modifications to the number of vehicles or individual vehicle configurations for re-optimizing an existing solution. Any vehicle from the original solution not specified here will be reused without alteration during the re-optimization process. |
| `vehicle_changes.add` | array of object | An array of objects to collect the details of the new vehicles to be added for re-optimization. Each object represents one vehicle. Please make sure the IDs provided for new vehicles are unique with respect to the IDs of the vehicles in the original request. |
| `vehicle_changes.add[].id` | string | Specify a unique ID for the vehicle. The IDs are case-sensitive. |
| `vehicle_changes.add[].description` | string | Specify a custom description for this vehicle. It will be returned in the response as-is. |
| `vehicle_changes.add[].start_index` | integer | Specify the index of the vehicle’s starting point in the `location` array. The valid value range is \[0, length of `location` array).<br>Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicle_changes.add[].start_depot_ids` | array of string | Specify the depots from which the vehicle can start. It is assumed that the vehicles can load the goods, which are to be delivered during the trip, when starting from the given depot. If certain delivery jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles starting from those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Pick-up type jobs which have depots configured, can not by fulfilled by vehicles who have only the start depots configured.<br>*   In case multiple depots are provided, then the vehicle starts from the depot which is nearest to the first task that it has to perform.<br>*   Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicle_changes.add[].end_index` | integer | Specify the index of the vehicle’s final stop point in the `location` array. The valid value range is \[0, length of locations).<br>Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicle_changes.add[].end_depot_ids` | array of string | Specify the depots where the vehicle should end its trip. It is assumed that the vehicles will unload the goods, which were picked-up during the trip, upon arriving the given depot. If certain pickup jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles ending their trips at those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Delivery type jobs which have depots configured, can not by fulfilled by vehicles who have only the end depots configured.<br>*   In case multiple depots are provided, then the vehicle ends the trip at the depot which is nearest to the last task that it performs.<br>*   Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicle_changes.add[].capacity` | array of integer | `capacity` attribute is used to define multidimensional capacities of the vehicle.<br>It is recommended to keep the dimensions of `capacity` consistent with the dimensions provided in quantity related attributes of `jobs` and `shipments` objects.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicle_changes.add[].alternative_capacities` | array of array of integer | An array of alternate capacity configurations for the vehicle. Each array should have same number of dimensions as those configured when specifying task loads/quantities. Multiple arrays can also be specified to add more than one alternate capacity configurations for a given vehicle. These capacities can not be shared / merged.<br>**Example:** An alternate capacity of \[ \[4,1\] , \[3,3\] \] indicates that the vehicle can either take 4 units of first dimension and a single unit of second dimension or else, 3 units each of both the dimensions. |
| `vehicle_changes.add[].time_window` | array of integer | `time_window` field is used to describe the time period during which a vehicle is available to perform assigned tasks. The time_window should be specified in the format of \[start_timestamp,end_timestamp\] and each timestamp must be expressed as an UNIX timestamp in seconds.<br>Please observe that it accepts only a single time window for the vehicle. It is important to note this difference with respect to the `time_windows` field used for `shipments` and `jobs`, which is a two-dimensional array used to describe the multiple time windows for each individual shipment or job. |
| `vehicle_changes.add[].skills` | array of integer | It is a multi-dimensional object that can be used to define multiple skills and abilities of drivers or vehicles.<br>Please note that only those vehicles with all the skills needed for a job/shipment will be assigned to fulfill that task.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicle_changes.add[].max_tasks` | integer | Describe the maximum number of tasks that can be assigned to this vehicle. It should be a positive integer. |
| `vehicle_changes.add[].breaks` | array of object | The `breaks` attribute is used to provide details of breaks that a driver can take during their route. For each break, multiple time windows can be provided during which the break can actually be taken. Please note that:<br>*   All breaks are treated as mandatory by the optimization engine. If they are feasible, then all of them will be part of vehicle's trip.<br>*   Only one of `breaks` or `layover_config` is allowed for a vehicle at a time. |
| `vehicle_changes.add[].breaks[].id` | integer | Specify an ID for the break. It should be a positive integer. |
| `vehicle_changes.add[].breaks[].time_windows` | array of array of integer | Describe the possible time slots for the driver's break period to start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that<br>*   Individual time window should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\].<br>*   All time windows of all breaks should be inside the vehicle's time window. |
| `vehicle_changes.add[].breaks[].description` | string | Add a custom description for the break. |
| `vehicle_changes.add[].breaks[].service` | integer | Specify the break duration, in seconds. |
| `vehicle_changes.add[].costs` | object | The `cost` attribute is used to define the cost of using the vehicle. It is a positive integer value with no specific unit of its own, but assumes the unit as per the value of `travel_cost` parameter.<br>*   When the `travel_cost` parameter is set to `distance` then `cost` will be in meters.<br>*   When the `travel_cost` parameter is set to `duration` then `cost` will be in seconds.<br>*   When the `travel_cost` is set to `customized` then `cost` will not have any unit, but during calculations it will be considered at its face value.<br>*   When the `travel_cost` is set to `air_distance` then `cost` will be in meters.<br>`cost` parameter is critical in determining the number of vehicles to be used for optimization. The optimization engine will prefer using vehicles which help in lowering the cost for a particular route, if other parameters (location, time, etc) favor the configuration.<br>Please note that:<br>*   When only the `fixed` vehicle cost is provided, it will be added to the `travel_cost` of the optimized route to arrive at the overall cost of the route.<br>*   When only the `per_hour` or `per_km` cost is provided for a vehicle, then the cost of the route to which the vehicle is assigned, is calculated using only the given `per_hour` or `per_km` cost and not the `travel_cost` of the route.<br>*   When `per_hour` or `per_km` is provided along with `fixed` cost for a vehicle, then the cost of the route to which the vehicle is assigned, is equal to the sum of `fixed` and calculated `per_hour` or the `per_km` costs.<br>*   `per_order` cost is always added to the overall cost of the route to which the vehicle is assigned. |
| `vehicle_changes.add[].costs.fixed` | integer | Specify a fixed cost for using a vehicle. It should be a positive integer. Default value is 0. |
| `vehicle_changes.add[].costs.per_hour` | integer | Define the cost for one hour of drive time of the vehicle. When `per_hour` cost is used, the final vehicle cost is determined based on the given value, instead of travel duration of the route.<br>Please note that<br>*   `per_hour` cost is effective only when `travel_cost` is `duration`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_hour` costs are ineffective when using `options.grouping` configurations. |
| `vehicle_changes.add[].costs.per_km` | integer | Define the cost incurred by the vehicle for travelling a distance of one kilometer (km). When `per_km` cost is used, the final vehicle cost is determined based on the given value, instead of distance travelled on the trip.<br>Please note that<br>*   `per_km` cost is effective only when `travel_cost` is `distance`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_km` costs are ineffective when using `options.grouping` configurations. |
| `vehicle_changes.add[].costs.per_order` | integer | Define the cost incurred by the vehicle for fulfilling one order. A job or a shipment, both are considered as a single order. When `per_order` cost is defined, the final vehicle cost is calculated as the sum of total costs of fulfilling the orders assigned to the vehicle and any other costs that the vehicle incurs (travel_cost, fixed cost, per_km or per_hour costs). |
| `vehicle_changes.add[].costs.min_stop_load_fixed_penalty` | integer | Specify the fixed penalty to be applied in case the vehicle is assigned to any delivery task with a load below the specified `min_stop_load` threshold. If all the tasks assigned to the vehicle have loads more than the specified `min_stop_load` threshold, this fixed penalty is not applied. |
| `vehicle_changes.add[].costs.min_stop_load_unit_penalty` | array of integer | Defines the penalty applied per unit of load shortfall when a task’s load is lower than the vehicle’s configured `min_stop_load`. As a result, higher penalty values make the optimizer increasingly reluctant to assign low-load tasks to vehicles with higher minimum load expectations, while still preserving flexibility when capacity or feasibility constraints require such assignments. |
| `vehicle_changes.add[].costs.deadhead_duration_penalty` | integer | Specify a penalty to be applied for each unit of deadhead duration exceeding the specified `max_deadhead_duration` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_duration` is not provided. |
| `vehicle_changes.add[].costs.deadhead_distance_penalty` | integer | Specify a penalty to be applied for each unit of deadhead distance exceeding the specified `max_deadhead_distance` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_distance` is not provided. |
| `vehicle_changes.add[].speed_factor` | number | A positive number indicating the factor by which the vehicle’s speed should be adjusted , relative to normal speed, affecting the driving durations consequently. When `speed_factor` is greater than 1, effective travel time will be less than the normal travel duration. Similarly, when `speed_factor` is less than 1, effective travel time will be more than the normal travel duration. Please note that the `speed_factor` value supports values greater than 0 upto a maximum of 5.0, with a precision of two digits after the decimal point.<br>For example, a normal trip duration of 1hr would be considered as a trip with duration of 30min if the `speed_factor` is 2.<br>Using this attribute will have an effect on the vehicle’s arrival time at task locations (allocate task `time_windows` accordingly) and can affect the cost of the route as well (when `travel_cost=duration`). |
| `vehicle_changes.add[].layover_config` | object | Use this object to configure continuous driving time limitations and subsequent rest duration for the driver. Please note that only one of `layover_config` or `breaks` is allowed for a vehicle, at a time. |
| `vehicle_changes.add[].layover_config.max_continuous_time` | integer | Define the maximum time, in seconds, that a driver can drive without taking a break. This field is mandatory when using the `layover_config` attribute. Please note that accumulation of driving time is not interrupted by service time, setup or waiting time when fulfilling tasks, unless `include_service_time` is set to true.<br>It is worth highlighting that, if different `max_continuous_time` durations are used then optimizer might choose vehicles with lower `max_continuous_time` because layover time is not affecting its objectives. |
| `vehicle_changes.add[].layover_config.layover_duration` | integer | Specify the duration, in seconds, for which the driver should rest after driving continuously for the duration provided in `max_continuous_time`. This field is mandatory when using the `layover_config` attribute.<br>Please note that the `layover_duration` will be added to the total service time and will impact arrival time of vehicle/driver at task’s location, but it won’t influence the `cost` or `duration` of the routes. |
| `vehicle_changes.add[].layover_config.include_service_time` | boolean | Choose if the optimizer should count the `service_time` spent while fulfilling tasks towards continuous working time of the driver. If set to `false` (default setting), only the driving time is considered to schedule the next break. When set to `true`, drive time and `service_time` are added together to determine the next break schedule. |
| `vehicle_changes.add[].allowed_zones` | array of integer | Specifies the zones where the vehicle is allowed to fulfil any tasks. Please note the following:<br>*   If this parameter is provided, then the vehicle can fulfil tasks only in the given zones but, it is restricted from taking up tasks anywhere else.<br>*   Providing an empty array implies that there are no allowed zones. Consequently, the vehicle can only fulfill tasks without specified zones that are outside of any defined zone polygon boundaries.<br>*   If the parameter itself is not provided in the input, then the vehicle is allowed to complete tasks in all zones as well as outside them. |
| `vehicle_changes.add[].restricted_zones` | array of integer | Specifies the zones where the vehicle is restricted from fulfilling any tasks. Although, the vehicle can be routed through such zones. Please note:<br>*   If this parameter is provided, then the vehicle is restricted from fulfilling tasks belonging to the given zones. Vehicle is allowed to fulfil tasks from everywhere else.<br>*   If an empty array is provided or if the parameter itself is not provided then zone based restrictions do not apply on the vehicle. |
| `vehicle_changes.add[].max_distance` | integer | Specify the total distance, in meters, that the vehicle can travel. This is a constraint on the driving distance of the vehicle.<br>In case `distance_matrix` is also provided in the input, then this constraint is applied on the distance driven as per the custom distance values instead of actual distance values. |
| `vehicle_changes.add[].max_travel_time` | integer | Specify the total duration, in seconds, that the vehicle can be driven for. This is a constraint on the driving duration of the vehicle only and any wait, service or setup times spent towards the job is not counted against this constraint.<br>In case `duration_matrix` is also provided in the input, then this constraint is applied on the drive duration as per the custom duration values instead of actual duration values. |
| `vehicle_changes.add[].max_stops` | integer | Specify the maximum number of stops that the vehicle can make. Whenever the vehicle makes a stop during a trip, it is counted against the “max_stop” constraint. Vehicles stopping for breaks or layovers will not be counted against this constraint. |
| `vehicle_changes.add[].profile` | string | Specify the profile for this vehicle. The routing properties of the profile specified here must be defined within `routing.profiles` under `options`. If no profile is specified, then default routing profile is used. |
| `vehicle_changes.add[].max_working_time` | integer | Specify the maximum duration, in seconds, that the vehicle can work for on the assigned route. Please note that all types of driver activities during the route—service, waiting, setup, and driving—contribute against the specified maximum duration. |
| `vehicle_changes.add[].volume` | object | Specify the dimensions of the vehicle's loading compartment. These inputs will be used to decide which cargo can be loaded into the vehicle based on their dimensions and alignment orientations. Please note that if a vehicle is not provided with the `volume` input, it can not be assigned to tasks with `volume` specified. |
| `vehicle_changes.add[].volume.width` | number | Compartment width, in meters. |
| `vehicle_changes.add[].volume.depth` | number | Compartment length, in meters. |
| `vehicle_changes.add[].volume.height` | number | Compartment height, in meters. |
| `vehicle_changes.add[].max_depot_runs` | integer | Specify the maximum number of times the vehicle can return to the designated depot in order to reload items/cargo for completing additional tasks. Please note that:<br>*   `start_depot_id` is required for the vehicle when specifying `max_depot_runs`.<br>*   `relations` , `layover_config` , `depots.throughput` and deadhead constraints ( `max_deadhead_duration` and `max_deadhead_distance` ) can not be used along with `max_depot_runs.` |
| `vehicle_changes.add[].max_deadhead_distance` | integer | Specify the maximum distance, in meters, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_distance` and `max_depot_runs` can not be used simultaneously. |
| `vehicle_changes.add[].max_deadhead_duration` | integer | Specify the maximum duration, in seconds, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_duration` and `max_depot_runs` can not be used simultaneously. |
| `vehicle_changes.add[].min_stop_load` | array of integer | Specifies the minimum load threshold that should be preferred to serve at a stop. When a task’s load is lower than this threshold, the optimizer applies a penalty (as defined by `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty` ) instead of strictly rejecting the assignment. This allows users to discourage inefficient assignments for heavy vehicles by not assigning very light loads, while still keeping them feasible when no better alternatives exist. Please note that:<br>*   the number of elements in the `min_stop_load` array, should be exactly the same as those in the vehicle’s capacity input.<br>*   the `min_stop_load` threshold is effective only for “delivery” type `jobs`.<br>*   when multiple tasks are grouped together to share a single stop, the effective load used for `min_stop_load` calculations at that stop will be the sum of the loads of all tasks that are grouped.<br>*   if `min_stop_load` is provided without specifying the penalties `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty`), the stop load thresholds do not impact route choices. |
| `vehicle_changes.add[].depot` | integer | **Deprecated! Please use the** `start_depot_ids` **and** `end_depot_ids` **to configure the originating and culminating depots for the vehicle, respectively.**<br>The `depot` attribute specifies the ID of the depot that is assigned to the vehicle.<br>Please note that if `depot` is specified, then the depot’s location will act as the starting point for the vehicle.<br>There is no restriction on the number of vehicles that can be assigned to a depot but one vehicle can only have one depot. |
| `vehicle_changes.add[].max_travel_cost` | integer | **Deprecated! Please use the** `max_distance` or `max_travel_time` **parameters to limit the vehicle’s driving distance or driving durations respectively.**<br>It restricts the maximum “cost” that a vehicle can incur while operating. This parameter is linked to `travel_cost` parameter, which determines whether the `max_travel_cost` value will be considered as `distance` (in meters) or `duration` (in seconds) or `customized`.<br>For example, if the `travel_cost` attribute is set to `distance`, the `max_travel_cost` value will be considered as the maximum allowable distance that a vehicle can travel in the optimized solution.<br>If the `travel_cost` parameter is set to `duration`, then the `max_travel_cost` value will be considered as the maximum allowable time that a vehicle can drive in the optimized solution.<br>If the `travel_cost` is `customized` then the value provided for `max_travel_cost` will be compared directly with the custom cost of the route to determine if the vehicle can be assigned for that route or not. Please note that `max_travel_cost`, in this case, will be considered abstract (unit-less) and at face value.<br>Setting a value for `max_travel_cost` ensures the vehicle does not exceed its operational limits, which can result in increased fuel costs, longer delivery times, or potential vehicle breakdowns. |
| `vehicle_changes.remove` | array of string | An array of vehicle IDs to be removed when during re-optimization. All vehicle IDs provided must have been part of the original request. |
| `vehicle_changes.modify` | array of object | An array of objects to collect the modified details of existing vehicles used in the original request. Each object represents one vehicle. Please make sure all the vehicle IDs provided here are same as the ones in the original request. |
| `vehicle_changes.modify[].id` | string | Specify a unique ID for the vehicle. The IDs are case-sensitive. |
| `vehicle_changes.modify[].description` | string | Specify a custom description for this vehicle. It will be returned in the response as-is. |
| `vehicle_changes.modify[].start_index` | integer | Specify the index of the vehicle’s starting point in the `location` array. The valid value range is \[0, length of `location` array).<br>Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicle_changes.modify[].start_depot_ids` | array of string | Specify the depots from which the vehicle can start. It is assumed that the vehicles can load the goods, which are to be delivered during the trip, when starting from the given depot. If certain delivery jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles starting from those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Pick-up type jobs which have depots configured, can not by fulfilled by vehicles who have only the start depots configured.<br>*   In case multiple depots are provided, then the vehicle starts from the depot which is nearest to the first task that it has to perform.<br>*   Please note that if either of the `start_index` or `start_depot_ids` is not provided, the vehicle starts from the location of the first task on its route. |
| `vehicle_changes.modify[].end_index` | integer | Specify the index of the vehicle’s final stop point in the `location` array. The valid value range is \[0, length of locations).<br>Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicle_changes.modify[].end_depot_ids` | array of string | Specify the depots where the vehicle should end its trip. It is assumed that the vehicles will unload the goods, which were picked-up during the trip, upon arriving the given depot. If certain pickup jobs can be serviced only by specific depots (`jobs.depot_ids`), then the vehicles ending their trips at those depots only can fulfil such jobs. Jobs which do not have any pickup / delivery steps or do not have depots configured will be not impacted by setting this property.<br>**Note:**<br>*   Delivery type jobs which have depots configured, can not by fulfilled by vehicles who have only the end depots configured.<br>*   In case multiple depots are provided, then the vehicle ends the trip at the depot which is nearest to the last task that it performs.<br>*   Please note that if either of the `end_index` or `end_depot_ids` is not provided, the vehicle ends the trip at the location of the last task on its route. |
| `vehicle_changes.modify[].capacity` | array of integer | `capacity` attribute is used to define multidimensional capacities of the vehicle.<br>It is recommended to keep the dimensions of `capacity` consistent with the dimensions provided in quantity related attributes of `jobs` and `shipments` objects.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicle_changes.modify[].alternative_capacities` | array of array of integer | An array of alternate capacity configurations for the vehicle. Each array should have same number of dimensions as those configured when specifying task loads/quantities. Multiple arrays can also be specified to add more than one alternate capacity configurations for a given vehicle. These capacities can not be shared / merged.<br>**Example:** An alternate capacity of \[ \[4,1\] , \[3,3\] \] indicates that the vehicle can either take 4 units of first dimension and a single unit of second dimension or else, 3 units each of both the dimensions. |
| `vehicle_changes.modify[].time_window` | array of integer | `time_window` field is used to describe the time period during which a vehicle is available to perform assigned tasks. The time_window should be specified in the format of \[start_timestamp,end_timestamp\] and each timestamp must be expressed as an UNIX timestamp in seconds.<br>Please observe that it accepts only a single time window for the vehicle. It is important to note this difference with respect to the `time_windows` field used for `shipments` and `jobs`, which is a two-dimensional array used to describe the multiple time windows for each individual shipment or job. |
| `vehicle_changes.modify[].skills` | array of integer | It is a multi-dimensional object that can be used to define multiple skills and abilities of drivers or vehicles.<br>Please note that only those vehicles with all the skills needed for a job/shipment will be assigned to fulfill that task.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `vehicle_changes.modify[].max_tasks` | integer | Describe the maximum number of tasks that can be assigned to this vehicle. It should be a positive integer. |
| `vehicle_changes.modify[].breaks` | array of object | The `breaks` attribute is used to provide details of breaks that a driver can take during their route. For each break, multiple time windows can be provided during which the break can actually be taken. Please note that:<br>*   All breaks are treated as mandatory by the optimization engine. If they are feasible, then all of them will be part of vehicle's trip.<br>*   Only one of `breaks` or `layover_config` is allowed for a vehicle at a time. |
| `vehicle_changes.modify[].breaks[].id` | integer | Specify an ID for the break. It should be a positive integer. |
| `vehicle_changes.modify[].breaks[].time_windows` | array of array of integer | Describe the possible time slots for the driver's break period to start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that<br>*   Individual time window should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\].<br>*   All time windows of all breaks should be inside the vehicle's time window. |
| `vehicle_changes.modify[].breaks[].description` | string | Add a custom description for the break. |
| `vehicle_changes.modify[].breaks[].service` | integer | Specify the break duration, in seconds. |
| `vehicle_changes.modify[].costs` | object | The `cost` attribute is used to define the cost of using the vehicle. It is a positive integer value with no specific unit of its own, but assumes the unit as per the value of `travel_cost` parameter.<br>*   When the `travel_cost` parameter is set to `distance` then `cost` will be in meters.<br>*   When the `travel_cost` parameter is set to `duration` then `cost` will be in seconds.<br>*   When the `travel_cost` is set to `customized` then `cost` will not have any unit, but during calculations it will be considered at its face value.<br>*   When the `travel_cost` is set to `air_distance` then `cost` will be in meters.<br>`cost` parameter is critical in determining the number of vehicles to be used for optimization. The optimization engine will prefer using vehicles which help in lowering the cost for a particular route, if other parameters (location, time, etc) favor the configuration.<br>Please note that:<br>*   When only the `fixed` vehicle cost is provided, it will be added to the `travel_cost` of the optimized route to arrive at the overall cost of the route.<br>*   When only the `per_hour` or `per_km` cost is provided for a vehicle, then the cost of the route to which the vehicle is assigned, is calculated using only the given `per_hour` or `per_km` cost and not the `travel_cost` of the route.<br>*   When `per_hour` or `per_km` is provided along with `fixed` cost for a vehicle, then the cost of the route to which the vehicle is assigned, is equal to the sum of `fixed` and calculated `per_hour` or the `per_km` costs.<br>*   `per_order` cost is always added to the overall cost of the route to which the vehicle is assigned. |
| `vehicle_changes.modify[].costs.fixed` | integer | Specify a fixed cost for using a vehicle. It should be a positive integer. Default value is 0. |
| `vehicle_changes.modify[].costs.per_hour` | integer | Define the cost for one hour of drive time of the vehicle. When `per_hour` cost is used, the final vehicle cost is determined based on the given value, instead of travel duration of the route.<br>Please note that<br>*   `per_hour` cost is effective only when `travel_cost` is `duration`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_hour` costs are ineffective when using `options.grouping` configurations. |
| `vehicle_changes.modify[].costs.per_km` | integer | Define the cost incurred by the vehicle for travelling a distance of one kilometer (km). When `per_km` cost is used, the final vehicle cost is determined based on the given value, instead of distance travelled on the trip.<br>Please note that<br>*   `per_km` cost is effective only when `travel_cost` is `distance`. Consequently, both `per_hour` and `per_km` can not be effective simultaneously for a given vehicle.<br>*   `per_km` costs are ineffective when using `options.grouping` configurations. |
| `vehicle_changes.modify[].costs.per_order` | integer | Define the cost incurred by the vehicle for fulfilling one order. A job or a shipment, both are considered as a single order. When `per_order` cost is defined, the final vehicle cost is calculated as the sum of total costs of fulfilling the orders assigned to the vehicle and any other costs that the vehicle incurs (travel_cost, fixed cost, per_km or per_hour costs). |
| `vehicle_changes.modify[].costs.min_stop_load_fixed_penalty` | integer | Specify the fixed penalty to be applied in case the vehicle is assigned to any delivery task with a load below the specified `min_stop_load` threshold. If all the tasks assigned to the vehicle have loads more than the specified `min_stop_load` threshold, this fixed penalty is not applied. |
| `vehicle_changes.modify[].costs.min_stop_load_unit_penalty` | array of integer | Defines the penalty applied per unit of load shortfall when a task’s load is lower than the vehicle’s configured `min_stop_load`. As a result, higher penalty values make the optimizer increasingly reluctant to assign low-load tasks to vehicles with higher minimum load expectations, while still preserving flexibility when capacity or feasibility constraints require such assignments. |
| `vehicle_changes.modify[].costs.deadhead_duration_penalty` | integer | Specify a penalty to be applied for each unit of deadhead duration exceeding the specified `max_deadhead_duration` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_duration` is not provided. |
| `vehicle_changes.modify[].costs.deadhead_distance_penalty` | integer | Specify a penalty to be applied for each unit of deadhead distance exceeding the specified `max_deadhead_distance` for the vehicle. Default value is 0. Please note that this is ineffective when a `max_deadhead_distance` is not provided. |
| `vehicle_changes.modify[].speed_factor` | number | A positive number indicating the factor by which the vehicle’s speed should be adjusted , relative to normal speed, affecting the driving durations consequently. When `speed_factor` is greater than 1, effective travel time will be less than the normal travel duration. Similarly, when `speed_factor` is less than 1, effective travel time will be more than the normal travel duration. Please note that the `speed_factor` value supports values greater than 0 upto a maximum of 5.0, with a precision of two digits after the decimal point.<br>For example, a normal trip duration of 1hr would be considered as a trip with duration of 30min if the `speed_factor` is 2.<br>Using this attribute will have an effect on the vehicle’s arrival time at task locations (allocate task `time_windows` accordingly) and can affect the cost of the route as well (when `travel_cost=duration`). |
| `vehicle_changes.modify[].layover_config` | object | Use this object to configure continuous driving time limitations and subsequent rest duration for the driver. Please note that only one of `layover_config` or `breaks` is allowed for a vehicle, at a time. |
| `vehicle_changes.modify[].layover_config.max_continuous_time` | integer | Define the maximum time, in seconds, that a driver can drive without taking a break. This field is mandatory when using the `layover_config` attribute. Please note that accumulation of driving time is not interrupted by service time, setup or waiting time when fulfilling tasks, unless `include_service_time` is set to true.<br>It is worth highlighting that, if different `max_continuous_time` durations are used then optimizer might choose vehicles with lower `max_continuous_time` because layover time is not affecting its objectives. |
| `vehicle_changes.modify[].layover_config.layover_duration` | integer | Specify the duration, in seconds, for which the driver should rest after driving continuously for the duration provided in `max_continuous_time`. This field is mandatory when using the `layover_config` attribute.<br>Please note that the `layover_duration` will be added to the total service time and will impact arrival time of vehicle/driver at task’s location, but it won’t influence the `cost` or `duration` of the routes. |
| `vehicle_changes.modify[].layover_config.include_service_time` | boolean | Choose if the optimizer should count the `service_time` spent while fulfilling tasks towards continuous working time of the driver. If set to `false` (default setting), only the driving time is considered to schedule the next break. When set to `true`, drive time and `service_time` are added together to determine the next break schedule. |
| `vehicle_changes.modify[].allowed_zones` | array of integer | Specifies the zones where the vehicle is allowed to fulfil any tasks. Please note the following:<br>*   If this parameter is provided, then the vehicle can fulfil tasks only in the given zones but, it is restricted from taking up tasks anywhere else.<br>*   Providing an empty array implies that there are no allowed zones. Consequently, the vehicle can only fulfill tasks without specified zones that are outside of any defined zone polygon boundaries.<br>*   If the parameter itself is not provided in the input, then the vehicle is allowed to complete tasks in all zones as well as outside them. |
| `vehicle_changes.modify[].restricted_zones` | array of integer | Specifies the zones where the vehicle is restricted from fulfilling any tasks. Although, the vehicle can be routed through such zones. Please note:<br>*   If this parameter is provided, then the vehicle is restricted from fulfilling tasks belonging to the given zones. Vehicle is allowed to fulfil tasks from everywhere else.<br>*   If an empty array is provided or if the parameter itself is not provided then zone based restrictions do not apply on the vehicle. |
| `vehicle_changes.modify[].max_distance` | integer | Specify the total distance, in meters, that the vehicle can travel. This is a constraint on the driving distance of the vehicle.<br>In case `distance_matrix` is also provided in the input, then this constraint is applied on the distance driven as per the custom distance values instead of actual distance values. |
| `vehicle_changes.modify[].max_travel_time` | integer | Specify the total duration, in seconds, that the vehicle can be driven for. This is a constraint on the driving duration of the vehicle only and any wait, service or setup times spent towards the job is not counted against this constraint.<br>In case `duration_matrix` is also provided in the input, then this constraint is applied on the drive duration as per the custom duration values instead of actual duration values. |
| `vehicle_changes.modify[].max_stops` | integer | Specify the maximum number of stops that the vehicle can make. Whenever the vehicle makes a stop during a trip, it is counted against the “max_stop” constraint. Vehicles stopping for breaks or layovers will not be counted against this constraint. |
| `vehicle_changes.modify[].profile` | string | Specify the profile for this vehicle. The routing properties of the profile specified here must be defined within `routing.profiles` under `options`. If no profile is specified, then default routing profile is used. |
| `vehicle_changes.modify[].max_working_time` | integer | Specify the maximum duration, in seconds, that the vehicle can work for on the assigned route. Please note that all types of driver activities during the route—service, waiting, setup, and driving—contribute against the specified maximum duration. |
| `vehicle_changes.modify[].volume` | object | Specify the dimensions of the vehicle's loading compartment. These inputs will be used to decide which cargo can be loaded into the vehicle based on their dimensions and alignment orientations. Please note that if a vehicle is not provided with the `volume` input, it can not be assigned to tasks with `volume` specified. |
| `vehicle_changes.modify[].volume.width` | number | Compartment width, in meters. |
| `vehicle_changes.modify[].volume.depth` | number | Compartment length, in meters. |
| `vehicle_changes.modify[].volume.height` | number | Compartment height, in meters. |
| `vehicle_changes.modify[].max_depot_runs` | integer | Specify the maximum number of times the vehicle can return to the designated depot in order to reload items/cargo for completing additional tasks. Please note that:<br>*   `start_depot_id` is required for the vehicle when specifying `max_depot_runs`.<br>*   `relations` , `layover_config` , `depots.throughput` and deadhead constraints ( `max_deadhead_duration` and `max_deadhead_distance` ) can not be used along with `max_depot_runs.` |
| `vehicle_changes.modify[].max_deadhead_distance` | integer | Specify the maximum distance, in meters, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_distance` and `max_depot_runs` can not be used simultaneously. |
| `vehicle_changes.modify[].max_deadhead_duration` | integer | Specify the maximum duration, in seconds, that the vehicle can accumulate as deadhead travel on a route. The scope for deadhead travel calculations is limited to only the first leg (start location / depot to first task location) and last leg (last task location to end location / depot) of the journey on any route. Following considerations apply on the deadhead calculations:<br>*   This is a soft constraint<br>*   In case of delivery type `jobs` the first leg will not be part of deadhead calculations as the vehicle carries the load to be delivered and hence, not traveling empty. Similarly, the last leg of the route will not be considered for deadhead calculations when pickup type `jobs` are present on the route.<br>*   For `shipments`, both the first leg journey and last leg journey be part of deadhead calculations.<br>*   `max_deadhead_duration` and `max_depot_runs` can not be used simultaneously. |
| `vehicle_changes.modify[].min_stop_load` | array of integer | Specifies the minimum load threshold that should be preferred to serve at a stop. When a task’s load is lower than this threshold, the optimizer applies a penalty (as defined by `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty` ) instead of strictly rejecting the assignment. This allows users to discourage inefficient assignments for heavy vehicles by not assigning very light loads, while still keeping them feasible when no better alternatives exist. Please note that:<br>*   the number of elements in the `min_stop_load` array, should be exactly the same as those in the vehicle’s capacity input.<br>*   the `min_stop_load` threshold is effective only for “delivery” type `jobs`.<br>*   when multiple tasks are grouped together to share a single stop, the effective load used for `min_stop_load` calculations at that stop will be the sum of the loads of all tasks that are grouped.<br>*   if `min_stop_load` is provided without specifying the penalties `costs.min_stop_load_unit_penalty` and `costs.min_stop_load_fixed_penalty`), the stop load thresholds do not impact route choices. |
| `vehicle_changes.modify[].depot` | integer | **Deprecated! Please use the** `start_depot_ids` **and** `end_depot_ids` **to configure the originating and culminating depots for the vehicle, respectively.**<br>The `depot` attribute specifies the ID of the depot that is assigned to the vehicle.<br>Please note that if `depot` is specified, then the depot’s location will act as the starting point for the vehicle.<br>There is no restriction on the number of vehicles that can be assigned to a depot but one vehicle can only have one depot. |
| `vehicle_changes.modify[].max_travel_cost` | integer | **Deprecated! Please use the** `max_distance` or `max_travel_time` **parameters to limit the vehicle’s driving distance or driving durations respectively.**<br>It restricts the maximum “cost” that a vehicle can incur while operating. This parameter is linked to `travel_cost` parameter, which determines whether the `max_travel_cost` value will be considered as `distance` (in meters) or `duration` (in seconds) or `customized`.<br>For example, if the `travel_cost` attribute is set to `distance`, the `max_travel_cost` value will be considered as the maximum allowable distance that a vehicle can travel in the optimized solution.<br>If the `travel_cost` parameter is set to `duration`, then the `max_travel_cost` value will be considered as the maximum allowable time that a vehicle can drive in the optimized solution.<br>If the `travel_cost` is `customized` then the value provided for `max_travel_cost` will be compared directly with the custom cost of the route to determine if the vehicle can be assigned for that route or not. Please note that `max_travel_cost`, in this case, will be considered abstract (unit-less) and at face value.<br>Setting a value for `max_travel_cost` ensures the vehicle does not exceed its operational limits, which can result in increased fuel costs, longer delivery times, or potential vehicle breakdowns. |
| `job_changes` | object | This section gathers information on modifications to the number of jobs or their individual requirements for re-optimization. Any job from the original solution not specified here will be re-planned without alteration during the re-optimization process. |
| `job_changes.add` | array of object | An array of objects to collect the details of the new jobs to be added during re-optimization. Each object represents one job. Please make sure the IDs provided for new jobs are unique with respect to the IDs of the jobs in the original request. |
| `job_changes.add[].id` | string | Provide an unique ID for the job. The IDs are case-sensitive. |
| `job_changes.add[].description` | string | Add a custom description for the job. |
| `job_changes.add[].location_index` | integer | An integer denoting the index (in the `location` array) of the location coordinates where the job needs to be performed. The valid range of values is \[0, length of `location` array).<br>Please note the `location_index` is mandatory when using the `jobs` object. |
| `job_changes.add[].delivery` | array of integer | In case the job involves a delivery step, use this attribute to describe delivery quantity. This attribute supports multidimensional quantities, to support delivering quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the quantity of delivery will be added to the assigned vehicle’s initial load.<br>In case depots are being added, the delivery configured here can be fulfilled by vehicles starting from specific depots. Refer to `depot_ids` and `vehicles.start_depot_ids` to know more. |
| `job_changes.add[].pickup` | array of integer | In case the job involves a pickup step, use this attribute to describe pickup quantity. This attribute supports multidimensional quantities, to support picking up quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the vehicle will continue to carry the picked-up quantity until its last stop.<br>In case depots are being added, the pickup configured here can be fulfilled by vehicles ending at specific depots. Refer to `depot_ids` and `vehicles.end_depot_ids` to know more. |
| `job_changes.add[].service` | integer | Use this attribute to define the time duration, in seconds, needed to complete the job. Default value is 0. |
| `job_changes.add[].time_windows` | array of array of integer | Define time periods within which this job should be started. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `job_changes.add[].skills` | array of integer | Define the skills needed to complete the job. This attribute supports multidimensional skills allowing users to add multiple skills.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `job_changes.add[].priority` | integer | Specify the priority of this job. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this job will be assigned or not, but has nothing to do with the sequence of job fulfilment. |
| `job_changes.add[].setup` | integer | Specify the job set-up duration, in seconds. `setup` is the one-time effort needed apart from working on the original task - for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `job_changes.add[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this job belongs to. The job can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this job. Please note following points about job zones:<br>*   If zone IDs are provided for any one of the jobs, then all other jobs should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Jobs can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a job is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of those zones.<br>*   Jobs not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `job_changes.add[].depot_ids` | array of string | Specify the depots which can be used to fulfil this job. In case of a pickup job, the assigned vehicle will deliver the goods to the depot specified here, at the end of its trip. Conversely, in case of delivery jobs, the vehicle will load the goods from the depot specified here, before starting the trip.<br>**Note:**<br>*   If multiple IDs are provided for this field then any of the given depots can be used to fulfil the job.<br>*   If this field is not provided then the given job can be fulfilled by any vehicle (subject to other constraints configured in the input).<br>*   If the job does not have any delivery or pick-up step configured then depots configuration will not have any impact on the given job. |
| `job_changes.add[].load_types` | array of string | Use this parameter to specify the type of loads for the given job. Once this property is configured, the job can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that job’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this job to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, `load_types` might be ignored. |
| `job_changes.add[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the job’s load type. Once this property is configured, the job can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this job. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that current job’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this job to a vehicle which has served any task with `load_types` as either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `job_changes.add[].sequence_order` | integer | Use this parameter to prioritize completing a task relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `job_changes.add[].revenue` | integer | Specify the revenue earned by completing this job. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this job after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the job.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a job is negative, it will remain unassigned whatsoever. |
| `job_changes.add[].outsourcing_cost` | integer | Specify the cost of keeping this job unassigned, namely, the cost of outsourcing the job. When provided, the optimizer weighs the cost of assigning the job against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned jobs is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the job can not be outsourced, then the optimizer tries to fulfill the job irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a job. Also, the `outsourcing_cost` would override the priority settings of the job. |
| `job_changes.add[].follow_lifo_order` | boolean | Specify whether the job route should follow LIFO (last in, first out). Use this parameter when `pickup` or `delivery` jobs are involved and the loading or unloading sequence of cargo is important. The default is `false`. |
| `job_changes.add[].max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a job after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `job_changes.add[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the task. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a job consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total length, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `job_changes.add[].volume.width` | number | Cargo width, in meters. |
| `job_changes.add[].volume.depth` | number | Cargo length, in meters. |
| `job_changes.add[].volume.height` | number | Cargo height, in meters. |
| `job_changes.add[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `job_changes.add[].joint_order` | integer | Specify a joint order group ID that this job is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each job in a single joint order group will be fulfilled by a unique vehicle.<br>*   Jobs belonging to a joint order group can be served in any sequence.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `job_changes.add[].split` | object | An object to configure the rules for splitting the job into multiple sub-jobs. Please note that:<br>*   It is applicable only to `jobs` with:<br>    *   a `delivery` or `pickup` quantity specified.<br>    *   have only 1 load dimension (only element in the `delivery` or `pickup` array). Multi-dimension loads are not supported.<br>*   There is no partial completion for a splittable job - either all sub-jobs are fulfilled or none of them.<br>*   Each split part of the task is assigned a unique integer identifier in the range 0 ≤ identifier < total parts. These identifiers are available in the optimized result as `split_indicator`. |
| `job_changes.add[].split.can_be_split` | boolean | Specify if a pickup or a delivery type job can be split into multiple sub-tasks. Default value is "false". |
| `job_changes.add[].split.max_split` | integer | The maximum number of parts/sub-tasks that this job can be split into. This field is mandatory when `can_be_split = true` and must have a minimum value of 2. |
| `job_changes.add[].split.quant` | number | The minimum quantity allowed for each split sub-task, expressed as a ratio of the original job load (e.g., `0.25` ensures each split is ≥ 25% of the total). If omitted, the solver splits greedily based on available vehicle capacity. Please note that it is applicable only for tasks with single-dimensional load only. |
| `job_changes.remove` | array of string | An array of job IDs to be removed when during re-optimization. All job IDs provided must have been part of the original request. |
| `job_changes.modify` | array of object | An array of objects to collect the modified details of existing jobs used in the original request. Each object represents one job. Please make sure all the job IDs provided here are same as the ones in the original request. |
| `job_changes.modify[].id` | string | Provide an unique ID for the job. The IDs are case-sensitive. |
| `job_changes.modify[].description` | string | Add a custom description for the job. |
| `job_changes.modify[].location_index` | integer | An integer denoting the index (in the `location` array) of the location coordinates where the job needs to be performed. The valid range of values is \[0, length of `location` array).<br>Please note the `location_index` is mandatory when using the `jobs` object. |
| `job_changes.modify[].delivery` | array of integer | In case the job involves a delivery step, use this attribute to describe delivery quantity. This attribute supports multidimensional quantities, to support delivering quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the quantity of delivery will be added to the assigned vehicle’s initial load.<br>In case depots are being added, the delivery configured here can be fulfilled by vehicles starting from specific depots. Refer to `depot_ids` and `vehicles.start_depot_ids` to know more. |
| `job_changes.modify[].pickup` | array of integer | In case the job involves a pickup step, use this attribute to describe pickup quantity. This attribute supports multidimensional quantities, to support picking up quantities of different units/dimensions. It is recommended to keep the dimensions of quantity for pickup/delivery consistent when defining them in `jobs` and `vehicles` (in `capacity` attribute).<br>Please note that the vehicle will continue to carry the picked-up quantity until its last stop.<br>In case depots are being added, the pickup configured here can be fulfilled by vehicles ending at specific depots. Refer to `depot_ids` and `vehicles.end_depot_ids` to know more. |
| `job_changes.modify[].service` | integer | Use this attribute to define the time duration, in seconds, needed to complete the job. Default value is 0. |
| `job_changes.modify[].time_windows` | array of array of integer | Define time periods within which this job should be started. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `job_changes.modify[].skills` | array of integer | Define the skills needed to complete the job. This attribute supports multidimensional skills allowing users to add multiple skills.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `job_changes.modify[].priority` | integer | Specify the priority of this job. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this job will be assigned or not, but has nothing to do with the sequence of job fulfilment. |
| `job_changes.modify[].setup` | integer | Specify the job set-up duration, in seconds. `setup` is the one-time effort needed apart from working on the original task - for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `job_changes.modify[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this job belongs to. The job can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this job. Please note following points about job zones:<br>*   If zone IDs are provided for any one of the jobs, then all other jobs should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Jobs can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a job is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of those zones.<br>*   Jobs not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `job_changes.modify[].depot_ids` | array of string | Specify the depots which can be used to fulfil this job. In case of a pickup job, the assigned vehicle will deliver the goods to the depot specified here, at the end of its trip. Conversely, in case of delivery jobs, the vehicle will load the goods from the depot specified here, before starting the trip.<br>**Note:**<br>*   If multiple IDs are provided for this field then any of the given depots can be used to fulfil the job.<br>*   If this field is not provided then the given job can be fulfilled by any vehicle (subject to other constraints configured in the input).<br>*   If the job does not have any delivery or pick-up step configured then depots configuration will not have any impact on the given job. |
| `job_changes.modify[].load_types` | array of string | Use this parameter to specify the type of loads for the given job. Once this property is configured, the job can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that job’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this job to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, `load_types` might be ignored. |
| `job_changes.modify[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the job’s load type. Once this property is configured, the job can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this job. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that current job’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this job to a vehicle which has served any task with `load_types` as either groceries or food.<br>Note:<br>*   This parameter is effective only when a pickup / delivery is configured for the job.<br>*   If the job is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `job_changes.modify[].sequence_order` | integer | Use this parameter to prioritize completing a task relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `job_changes.modify[].revenue` | integer | Specify the revenue earned by completing this job. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this job after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the job.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a job is negative, it will remain unassigned whatsoever. |
| `job_changes.modify[].outsourcing_cost` | integer | Specify the cost of keeping this job unassigned, namely, the cost of outsourcing the job. When provided, the optimizer weighs the cost of assigning the job against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned jobs is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the job can not be outsourced, then the optimizer tries to fulfill the job irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a job. Also, the `outsourcing_cost` would override the priority settings of the job. |
| `job_changes.modify[].follow_lifo_order` | boolean | Specify whether the job route should follow LIFO (last in, first out). Use this parameter when `pickup` or `delivery` jobs are involved and the loading or unloading sequence of cargo is important. The default is `false`. |
| `job_changes.modify[].max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a job after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `job_changes.modify[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the task. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a job consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total length, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `job_changes.modify[].volume.width` | number | Cargo width, in meters. |
| `job_changes.modify[].volume.depth` | number | Cargo length, in meters. |
| `job_changes.modify[].volume.height` | number | Cargo height, in meters. |
| `job_changes.modify[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `job_changes.modify[].joint_order` | integer | Specify a joint order group ID that this job is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each job in a single joint order group will be fulfilled by a unique vehicle.<br>*   Jobs belonging to a joint order group can be served in any sequence.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `job_changes.modify[].split` | object | An object to configure the rules for splitting the job into multiple sub-jobs. Please note that:<br>*   It is applicable only to `jobs` with:<br>    *   a `delivery` or `pickup` quantity specified.<br>    *   have only 1 load dimension (only element in the `delivery` or `pickup` array). Multi-dimension loads are not supported.<br>*   There is no partial completion for a splittable job - either all sub-jobs are fulfilled or none of them.<br>*   Each split part of the task is assigned a unique integer identifier in the range 0 ≤ identifier < total parts. These identifiers are available in the optimized result as `split_indicator`. |
| `job_changes.modify[].split.can_be_split` | boolean | Specify if a pickup or a delivery type job can be split into multiple sub-tasks. Default value is "false". |
| `job_changes.modify[].split.max_split` | integer | The maximum number of parts/sub-tasks that this job can be split into. This field is mandatory when `can_be_split = true` and must have a minimum value of 2. |
| `job_changes.modify[].split.quant` | number | The minimum quantity allowed for each split sub-task, expressed as a ratio of the original job load (e.g., `0.25` ensures each split is ≥ 25% of the total). If omitted, the solver splits greedily based on available vehicle capacity. Please note that it is applicable only for tasks with single-dimensional load only. |
| `shipment_changes` | object | This section gathers information on modifications to the number of shipments or their individual requirements for re-optimization. Any shipment from the original solution not specified here will be re-planned without alteration during the re-optimization process. |
| `shipment_changes.add` | array of object | An array of objects to collect the details of the new shipments to be added during re-optimization. Each object represents one shipment. Please make sure the IDs provided for new shipments are unique with respect to the IDs of the shipments in the original request. |
| `shipment_changes.add[].pickup` | object | Specify the details of the pickup step of the shipment. |
| `shipment_changes.add[].pickup.id` | string | Indicate the ID of this shipment pickup step. An error will be reported if there are duplicate IDs for multiple shipment pick-ups. The IDs are case-sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipment_changes.add[].pickup.description` | string | Specify a custom description for the shipment pickup step. |
| `shipment_changes.add[].pickup.location_index` | integer | Indicate the index of the location for this shipment pickup. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array). |
| `shipment_changes.add[].pickup.service` | integer | Provide the time duration, in seconds, needed to complete the shipment pickup. Default value is 0. |
| `shipment_changes.add[].pickup.time_windows` | array of array of integer | Describe time periods within which the shipment pickup should be start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\] |
| `shipment_changes.add[].pickup.setup` | integer | Specify the set-up duration, in seconds, for the pickup. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipment_changes.add[].pickup.sequence_order` | integer | Use this parameter to prioritize completing the shipment pickup relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment pickups's sequence order must be lesser than or equal to its corresponding delivery's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipment_changes.add[].pickup.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment pickup after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipment_changes.add[].delivery` | object | Specify the details of the delivery step of the shipment. |
| `shipment_changes.add[].delivery.id` | string | Indicate the ID of this shipment delivery step. An error will be reported if there are duplicate IDs for multiple shipment deliveries. The IDs are case sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipment_changes.add[].delivery.description` | string | Specify a custom description for the shipment delivery step. |
| `shipment_changes.add[].delivery.location_index` | integer | Indicate the index of location for this shipment delivery. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array).<br>Please note `location_index` is mandatory when using the `shipment` attribute. |
| `shipment_changes.add[].delivery.service` | integer | Provide the time duration, in seconds, needed to complete the shipment delivery. Default value is 0. |
| `shipment_changes.add[].delivery.time_windows` | array of array of integer | Describe time periods within which the shipment delivery should start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `shipment_changes.add[].delivery.setup` | integer | Specify the set-up duration, in seconds, for the delivery. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipment_changes.add[].delivery.sequence_order` | integer | Use this parameter to prioritize completing the shipment delivery relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment delivery's sequence order must be greater than or equal to its corresponding pickup's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipment_changes.add[].delivery.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment delivery after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipment_changes.add[].amount` | array of integer | This parameter defines the quantity that needs to be shipped. This attribute supports multidimensional quantities, to support shipment of quantities of different units/dimensions. It is recommended to keep the dimensions of `amount` in `shipments` and that of `capacity` in `vehicles` consistent.<br>Please note that the `amount` will be added to the assigned vehicle’s initial load.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipment_changes.add[].skills` | array of integer | Define the skills needed to complete the shipment. This attribute supports multidimensional skills allowing users to add multiple skills for a shipment.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipment_changes.add[].priority` | integer | Describe the priority of this shipment. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this shipment will be assigned or not, but has nothing to do with the sequence of fulfilling shipments. |
| `shipment_changes.add[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this shipment belongs to. The shipment can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this shipment. If the pickup and delivery steps belong to different zones, then a vehicle should be allowed to fulfil tasks in both zones to take up such shipments. Please note following points about shipment zones:<br>*   If zone IDs are provided for any one of the shipments, then all other shipments should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Shipment steps can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a shipment pickup or delivery location is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of the overlapping zones, provided the vehicle is allowed to fulfill tasks in the zone containing the complementing shipment step.<br>*   Shipments not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `shipment_changes.add[].load_types` | array of string | Use this parameter to specify the type of loads for the given shipment. Once this property is configured, the shipment can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this shipment to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `load_types` might be ignored. |
| `shipment_changes.add[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the shipment’s load type. Once this property is configured, the shipment can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this shipment. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this shipment to a vehicle which has served any task with `load_types` as either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `shipment_changes.add[].max_time_in_vehicle` | integer | Use this parameter to limit the drive time for which a shipment stays in the vehicle. The time-in-vehicle calculations start once the pickup leg of shipment is completed after serving any setup and service time that may have been configured for it. For the delivery leg, time-in-vehicle calculations wouldn’t consider any setup and service time that needs to be served for completing the delivery. The service or setup times of other tasks performed in between will also be not accumulated against the time-in-vehicle limit.<br>Please note that this property would be overridden if any `relations` configuration is used except for “precedence” type. If “precedence” type relations is used then `max_time_in_vehicle` will override it. |
| `shipment_changes.add[].revenue` | integer | Specify the revenue earned by completing this shipment. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this shipment after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the shipment.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a shipment is negative, it will remain unassigned whatsoever. |
| `shipment_changes.add[].outsourcing_cost` | integer | Specify the cost of keeping this shipment unassigned, namely, the cost of outsourcing the shipment. When provided, the optimizer weighs the cost of assigning the shipment against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned shipments is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the shipment can not be outsourced, then the optimizer tries to fulfill the shipment irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a shipment. Also, the `outsourcing_cost` would override the priority settings of the shipment. |
| `shipment_changes.add[].follow_lifo_order` | boolean | Specify whether the shipment route should follow LIFO (last in, first out). Use this parameter when the loading or unloading sequence of cargo is important. The default value is \`false\`. |
| `shipment_changes.add[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the shipment. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a shipment consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total depth, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `shipment_changes.add[].volume.width` | number | Cargo width, in meters. |
| `shipment_changes.add[].volume.depth` | number | Cargo length, in meters. |
| `shipment_changes.add[].volume.height` | number | Cargo height, in meters. |
| `shipment_changes.add[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `shipment_changes.add[].joint_order` | integer | Specify a joint order group ID that this shipment is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each shipment in a single joint order group will be fulfilled by a unique vehicle.<br>*   Shipments belonging to a joint order group can be served in any sequence while maintaining the pickup -> delivery sequence for an individual shipment.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `shipment_changes.remove` | array of string | An array of shipment IDs to be removed when during re-optimization. All shipment IDs provided must have been part of the original request. |
| `shipment_changes.modify` | array of object | An array of objects to collect the modified details of existing shipments used in the original request. Each object represents one shipment. Please make sure all the shipment IDs provided here are same as the ones in the original request. |
| `shipment_changes.modify[].pickup` | object | Specify the details of the pickup step of the shipment. |
| `shipment_changes.modify[].pickup.id` | string | Indicate the ID of this shipment pickup step. An error will be reported if there are duplicate IDs for multiple shipment pick-ups. The IDs are case-sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipment_changes.modify[].pickup.description` | string | Specify a custom description for the shipment pickup step. |
| `shipment_changes.modify[].pickup.location_index` | integer | Indicate the index of the location for this shipment pickup. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array). |
| `shipment_changes.modify[].pickup.service` | integer | Provide the time duration, in seconds, needed to complete the shipment pickup. Default value is 0. |
| `shipment_changes.modify[].pickup.time_windows` | array of array of integer | Describe time periods within which the shipment pickup should be start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\] |
| `shipment_changes.modify[].pickup.setup` | integer | Specify the set-up duration, in seconds, for the pickup. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipment_changes.modify[].pickup.sequence_order` | integer | Use this parameter to prioritize completing the shipment pickup relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment pickups's sequence order must be lesser than or equal to its corresponding delivery's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipment_changes.modify[].pickup.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment pickup after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipment_changes.modify[].delivery` | object | Specify the details of the delivery step of the shipment. |
| `shipment_changes.modify[].delivery.id` | string | Indicate the ID of this shipment delivery step. An error will be reported if there are duplicate IDs for multiple shipment deliveries. The IDs are case sensitive. Please note `id` is mandatory when using the `shipments` attribute. |
| `shipment_changes.modify[].delivery.description` | string | Specify a custom description for the shipment delivery step. |
| `shipment_changes.modify[].delivery.location_index` | integer | Indicate the index of location for this shipment delivery. The index references the locations present in the `location` array. The valid range of value is \[0, length of `location` array).<br>Please note `location_index` is mandatory when using the `shipment` attribute. |
| `shipment_changes.modify[].delivery.service` | integer | Provide the time duration, in seconds, needed to complete the shipment delivery. Default value is 0. |
| `shipment_changes.modify[].delivery.time_windows` | array of array of integer | Describe time periods within which the shipment delivery should start. The time periods should be expressed as a UNIX timestamp in seconds.<br>Please note that the time periods should not overlap with each other and should always follow the format of \[start_timestamp, end_timestamp\]. |
| `shipment_changes.modify[].delivery.setup` | integer | Specify the set-up duration, in seconds, for the delivery. `setup` is the one-time effort needed apart from working on the original task- for example, effort to record some information for compliance, or effort to set-up the equipment, or perform any other action for completing all steps required to fulfil the job.<br>Please note that `setup` time is applied only once for a given task location. `setup` time, unlike `service` time, is not repeated in case there are multiple tasks at the same location. |
| `shipment_changes.modify[].delivery.sequence_order` | integer | Use this parameter to prioritize completing the shipment delivery relative to certain other tasks. A task configured with a `sequence_order` of 2 will be done after the task with `sequence_order` of 1, but before the task with `sequence_order` of 3. Valid range of values for this input is \[0,100\].<br>Please note that:<br>*   The shipment delivery's sequence order must be greater than or equal to its corresponding pickup's sequence order.<br>*   Only the tasks within the same route are compared and ordered as per their `sequence_order`.<br>*   Tasks without a `sequence_order` are not involved in the comparison.<br>*   Following is the precedence of `sequence_order` when used along side some of the other constraints:<br>    *   `relations` are prioritized over `sequence_order` comparisons.<br>    *   `sequence_order` will override `order_grouping` configurations. |
| `shipment_changes.modify[].delivery.max_visit_lateness` | integer | It determines the allowable delay, in seconds, to begin a shipment delivery after its designated time window has concluded. Please note that this parameter would override the `constraint.max_visit_lateness` (global) if both are specified. |
| `shipment_changes.modify[].amount` | array of integer | This parameter defines the quantity that needs to be shipped. This attribute supports multidimensional quantities, to support shipment of quantities of different units/dimensions. It is recommended to keep the dimensions of `amount` in `shipments` and that of `capacity` in `vehicles` consistent.<br>Please note that the `amount` will be added to the assigned vehicle’s initial load.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipment_changes.modify[].skills` | array of integer | Define the skills needed to complete the shipment. This attribute supports multidimensional skills allowing users to add multiple skills for a shipment.<br>Read more about the behavior of this attribute in the [Multi-Dimensional Parameters](#multi-dimensional-parameters) section. |
| `shipment_changes.modify[].priority` | integer | Describe the priority of this shipment. The valid values are in the range of \[0, 100\]. Default value is 0.<br>Please note that setting a priority will only decide whether this shipment will be assigned or not, but has nothing to do with the sequence of fulfilling shipments. |
| `shipment_changes.modify[].zones` | array of integer | An array of integers specifying the IDs of the zone(s) that this shipment belongs to. The shipment can be fulfilled by all vehicles which are allowed to complete tasks in the zone(s) assigned to this shipment. If the pickup and delivery steps belong to different zones, then a vehicle should be allowed to fulfil tasks in both zones to take up such shipments. Please note following points about shipment zones:<br>*   If zone IDs are provided for any one of the shipments, then all other shipments should also be specified with zone IDs. Zone IDs provided here will override any zone geometries provided in the `zones` attribute and these IDs will be used for allocating appropriate vehicles.<br>*   Shipment steps can be auto-allocated to zones if this parameter is not specified while the zone geometries (either `zones.geometry` or `zones.geofence_id`) are provided.<br>*   If a shipment pickup or delivery location is located in an area where 2 or more zones overlap, it can be assigned to a vehicle permitted in _any_ of the overlapping zones, provided the vehicle is allowed to fulfill tasks in the zone containing the complementing shipment step.<br>*   Shipments not falling in any zones can be fulfilled by only those vehicles which are allowed to take up tasks outside zones as well. Refer to `vehicles` attribute for more information. |
| `shipment_changes.modify[].load_types` | array of string | Use this parameter to specify the type of loads for the given shipment. Once this property is configured, the shipment can not be served by a vehicle which has serviced any task whose load is incompatible with any of the`load_types` provided in this input. The load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load characteristics belong to either one or both types. Consequently, the optimizer will assign this shipment to a vehicle which has served other tasks whose `incompatible_load_types` do not contain either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `load_types` might be ignored. |
| `shipment_changes.modify[].incompatible_load_types` | array of string | Use this parameter to specify the type of loads which are incompatible with the shipment’s load type. Once this property is configured, the shipment can only be serviced by a vehicle which has not serviced any other task with an incompatible `load_types` . Add multiple load types to indicate all the types which are incompatible for this shipment. The incompatible load type considerations are ignored for the first task of the route.<br>For example, an input value of \[“groceries”, “food”\] means that shipment’s load is incompatible with both groceries and food type of loads. Consequently, the optimizer will not assign this shipment to a vehicle which has served any task with `load_types` as either groceries or food.<br>Please note that if the shipment is part of any `relations` then, configured `incompatible_load_types` might be ignored. |
| `shipment_changes.modify[].max_time_in_vehicle` | integer | Use this parameter to limit the drive time for which a shipment stays in the vehicle. The time-in-vehicle calculations start once the pickup leg of shipment is completed after serving any setup and service time that may have been configured for it. For the delivery leg, time-in-vehicle calculations wouldn’t consider any setup and service time that needs to be served for completing the delivery. The service or setup times of other tasks performed in between will also be not accumulated against the time-in-vehicle limit.<br>Please note that this property would be overridden if any `relations` configuration is used except for “precedence” type. If “precedence” type relations is used then `max_time_in_vehicle` will override it. |
| `shipment_changes.modify[].revenue` | integer | Specify the revenue earned by completing this shipment. The optimizer uses the `revenue` input to identify the potential profit earned by fulfilling this shipment after taking into account the costs incurred to do so. The`options.objective` and `vehicles.costs` input are taken into account to identify the costs of fulfilling the shipment.<br>In general, the optimizer will prefer fulfilling the tasks with higher profits over the tasks with lower profits, should it need to reject some tasks in order to honor other constraints. In case the profit from fulfilling a shipment is negative, it will remain unassigned whatsoever. |
| `shipment_changes.modify[].outsourcing_cost` | integer | Specify the cost of keeping this shipment unassigned, namely, the cost of outsourcing the shipment. When provided, the optimizer weighs the cost of assigning the shipment against the cost of keeping it unassigned and chooses a solution with lower cost. In the solution, the `outsourcing_cost` of unassigned shipments is added to the total cost of the solution.<br>If the `outsourcing_cost` is not provided, which is to say that the shipment can not be outsourced, then the optimizer tries to fulfill the shipment irrespective of the cost incurred, subject to other constraints.<br>Please note that `revenue` and `outsourcing_cost` can not be specified simultaneously for a shipment. Also, the `outsourcing_cost` would override the priority settings of the shipment. |
| `shipment_changes.modify[].follow_lifo_order` | boolean | Specify whether the shipment route should follow LIFO (last in, first out). Use this parameter when the loading or unloading sequence of cargo is important. The default value is \`false\`. |
| `shipment_changes.modify[].volume` | object | Specify the dimensions and alignment configurations for the cargo associated with the shipment. These inputs will be used to arrange the items into the loading compartment of the vehicle to utilize the three-dimensional space. If a shipment consists of several different items, each with its own dimensions, please specify the final characteristics for the task: total height, total depth, total width.<br>Please note that vehicles which contain the `volume` input, will only be considered for arranging such items. |
| `shipment_changes.modify[].volume.width` | number | Cargo width, in meters. |
| `shipment_changes.modify[].volume.depth` | number | Cargo length, in meters. |
| `shipment_changes.modify[].volume.height` | number | Cargo height, in meters. |
| `shipment_changes.modify[].volume.alignment` | string | Refers to the orientation of the cargo in the loading compartment. It supports the following values:<br>*   **" "** : A blank space to indicate that the dimension check for the cargo should be skipped. This is also the default value.<br>*   **strict :** In this orientation, the cargo must fit within the vehicle’s dimensions exactly as is—no rotation is allowed. All dimensions of the cargo must be less than or equal to the corresponding dimensions of the vehicle. If any dimension exceeds that of the vehicle, the cargo cannot be loaded.<br>*   **parallel :** With parallel orientation, the cargo can be rotated around any one of the axes to help it fit into the loading compartment. For example, if the cargo is wider than the vehicle, it can still be loaded by rotating it around the vertical axis (so the width aligns with the vehicle’s depth) or the horizontal axis (so the width aligns with the vehicle’s height). Using this orientation, even a cargo whose one dimension is larger than the corresponding dimension of the vehicle but smaller than other dimensions, can also be loaded.<br>*   **fixed_bottom :** In this orientation, the cargo can only be rotated around the vertical axis, meaning its base stays fixed and it cannot be tilted or turned over. The height of the cargo remains aligned with the vehicle’s height and cannot be adjusted. As a result, if the cargo’s height exceeds the vehicle’s available height, it cannot be loaded into the compartment. |
| `shipment_changes.modify[].joint_order` | integer | Specify a joint order group ID that this shipment is associated with. Tasks having the same joint order group ID are treated as a single unit: either all tasks in the group are assigned, or none are. Users can add tasks of both `jobs` and `shipments` types to a single joint order group by using the same unique ID. Please note that:<br>*   Each shipment in a single joint order group will be fulfilled by a unique vehicle.<br>*   Shipments belonging to a joint order group can be served in any sequence while maintaining the pickup -> delivery sequence for an individual shipment.<br>*   Joint order settings will not be effective if \`solution\` or \`relations\` attributes are also provided in the input request. |
| `locations` | array of string | Provide the list of locations to be used during re-optimization process. Please note that<br>*   Providing the location input overwrites the list of locations used in the original request.<br>*   The location_indexes associated with all tasks and vehicles (both from the original and new re-optimization input requests) will follow the updated list of locations.<br>As a best practice:<br>1.  Don't provide the `locations` input when re-optimizing, if the original set contains all the required location coordinates.<br>2.  If any new location coordinates are required for re-optimization, copy the full, original location list and update it in the following manner before adding it to the re-optimization input:<br>    1.  Ensure to not update the indexes of locations which just need to be "modified".<br>    2.  Add new location coordinates towards the end of the list. |
| `options` | object | A set of options that can be used to configure re-optimization webhook settings for receiving status updates about submitted re-optimization requests. Read more about this attribute in the [Webhook Configurations](#webhook-configurations) section. |
| `options.webhook` | object | Use this attribute to configure your webhook configurations for receiving status updates about submitted optimization requests. Read more about this attribute in the [Webhook Configurations](#webhook-configurations) section. |
| `options.webhook.url` | string | Specify your webhook URL. Please note only HTTP(s) are supported. The URL provided here will be called by the optimization service using a HTTP POST method along with event payload. |
| `options.webhook.events` | array of string | Specify the subscription that you want to subscribe to i.e. receive them on the webhook `url` configured above. Currently, "JOB_CREATED", "JOB_COMPLETED" and "JOB_FAILED" type events are supported. |
| `options.webhook.timeout` | integer | Specify a timeout period, in seconds. The timeout specified here will be used for retries - repeat event notifications - if a successful acknowledgement from the webhook URL is not received within the specified duration. Please note that:<br>*   Default values is 10 seconds.<br>*   The valid range of values that can be provided is \[1, 60\].<br>*   The optimization service will attempt a maximum of 3 retries, with each attempt occurring after a successive `timeout` period. |

### Response Schema

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | A unique ID which can be used in the Optimization GET method to retrieve the result of optimization. |
| `message` | string | Displays an acknowledgement message once the job is submitted. |
| `status` | string | A string indicating the state of the response. On successful responses, the value will be `Ok`. Indicative error messages/codes are returned in case of errors. See the [API Error Codes](#api-error-codes) section below for more information. |
| `warnings` | array of string | Display the warnings for the given input parameters, values and constraints. |
  
[Route Optimization API Examples

To see all the examples related to Route Optimization API, click the banner.](https://docs.nextbillion.ai/optimization/route-optimization-api/tutorials)
  

## Object Overview

### Location Object

Locations object - `locations` - is used to describe locations that will be used for route optimization. A maximum of 2k locations can be added to this object.

 

| Index | Location |
| --- | --- |
| 0 | 51.388997,-0.119022 |
| 1 | 51.391915,-0.103666 |
| 2 | 51.369777,-0.10438 |
| 3 | 51.365014,-0.105654 |
| 4 | 51.351818,-0.014773 |

With respect to the example above, if in the "vehicles" property, the `start_index` parameter is set to 2, then 51.369777,-0.10438 would be considered as the starting coordinates for that vehicle.

### Job Object

`jobs` object describes a particular job or a task that needs to be completed as part of the overall optimization process. It contains various properties of a job such as the job `id`, the index of the location where the job needs to be performed, the service duration, multidimensional quantities for pickup and delivery, available time windows, mandatory skills required, the priority of the job, and a description of the job.

Properties of a `jobs` object provide important information to the optimization algorithm, such as time constraints and resource requirements for each job, which helps generate an optimized route plan. It is important to note here that all delivery-related amounts for jobs are loaded at vehicle start, while all pickup-related amounts for jobs are brought back to the last stop of the vehicle. Therefore, the vehicles should have appropriate capacity to handle job pickup and deliveries accordingly.

### Vehicle Object

The Vehicle object describes the characteristics and constraints of a vehicle that will be used in a multi-vehicle routing problem. Some points to consider about `vehicles` object:

1. The users can also set a start or an end location of their choice as long as it is present in the locations object. The vehicle’s start and end locations can be different from job locations.
2. In order to request a round trip, you can specify both the start_index and end_index with the same location index.
3. `capacity` parameter describes the maximum multidimensional quantities a vehicle can carry.

### Relations Object

`relations` object is used to configure relationships between jobs and shipments that should be honored in the optimized solution. With this object users can customize the algorithm to emulate real-world constraints like control the sequence of certain jobs/shipments in the solution or ensure certain jobs/shipments are covered on the same route. It allows you to specify various types of relations and their corresponding constraints for the steps. However when using the `relations` object, please be mindful of the following considerations:

* Soft constraints parameters like `max_vehicle_overtime` and `max_visit_lateness` will not be available in input requests when the `relations` object is used.
* If certain relations require multiple steps (e.g., jobs) to be on the same route, the `vehicle` assigned to that route must have enough capacity and the required skills to serve all the jobs on the route. The optimization service would return an error, otherwise.
* If a `relations` input requires a `delivery` step to occur before a `pickup` step for a `shipment`, an error message is returned, as it violates the shipment's logical order.
* For `shipments`, both the `pickup` and `delivery` steps should exist within the same `relations`. An error message is reported if a `relations` contains only one `shipment` step.

#### Sample Relations Object

```json
{
"relations": [
  {
    "type": "in_direct_sequence",
    "steps": [
      {
        "type": "start"
      },
      {
        "type": "pickup",
        "id": 25
      },
      {
        "type": "job",
        "id": 3
      },
      {
        "type": "delivery",
        "id": 25
      },
      {
        "type": "end"
      }
    ],
    "vehicle": 1
  }
]
}
```

### Custom Cost Matrix

This feature enables the optimization algorithm to consider a user-defined `cost` of traveling between different locations. Users can set the `travel_cost` parameter of `objective` property to `customized` to ensure that the algorithm considers the custom cost values for each traveling between locations.

To utilize the "cost_matrix" object, you need to provide a 2D array with 'n' rows and 'n' columns where `n` represents the total number of locations. Each element of the array represents the cost of traveling from one location to another. The optimization algorithm would prefer the routes with lower relative costs over the routes with higher relative costs. Therefore, the custom cost matrix can be used to influence the optimized route that the algorithm returns. For example, if you have three locations (A, B, C), the cost_matrix would be a 3x3 array:

```
`cost_matrix`: [
				[0, 10, 5],
				[10, 0, 8],
				[5, 8, 0]
			   ]
```

In this example, the first row represents the cost of traveling from location A to location A,A to B & A to C, the second row represents the cost of traveling to different locations starting from point B to A and so on. Subsequently, for the given example, the cost of traveling from location A to B is 10, from A to C is 5, from B to A is 10, from B to C is 8, and so on.

Few points to consider regarding the use of `cost_matrix` :

* The cost values should always be non-negative integers.
* The cost values do not have any unit. Users can consider the cost of traveling from one location to another as abstract but relative weights.
* Please ensure to match the index between `locations` and `cost_matrix` objects. This means that the costs associated with coordinates at index *i* in `locations` object should be added in a row at index *i* in the `cost_matrix` object as well.
* Using custom costs for a subset of total locations is not allowed. Either it should be used for all locations or not used at all. To ignore a particular location and prevent it from being included in the optimization, you can assign a very large value to the corresponding row and column in the `cost_matrix`. This ensures that the optimizer avoids that location in the routing solution.
* When the `travel_cost` is set to `customized`, the optimization algorithm takes the customized cost matrix into account when calculating the overall `cost` of a route.
* `max_travel_cost` feature allows you to set a maximum travel cost for a route. When a customized cost matrix is used in the optimization request, the total cost of a route is calculated based on the values provided in the customized cost matrix. The `max_travel_cost` feature ensures that the calculated cost of a route does not exceed a specified value. By combining the customization of the `cost_matrix` and the `max_travel_cost` feature, you can optimize routes based on your desired cost factors while also ensuring that the routes remain within specific cost constraints.

#### Sample Cost Matrix Object

```json
{
    "cost_matrix":
      [
        [0,4,22,9999],
        [4,0,12,33],
        [22,12,0,45],
        [9999,33,45,0]
      ]
  }
```

## Multi-Dimensional Parameters

### Capacity

The Capacity parameter in [Vehicle Object](#request-body) is used to describe multidimensional quantities of capacity. In this context, multi-dimension refers to the fact that a single vehicle can carry loads defined in different units. For example, a vehicle may have a capacity of 10 cubic meters for volume, 1000 kg for weight, and 6 pallets for a number of items. These are three different dimensions of capacity, and each has its own value. By specifying Capacity as an array of integers, we can provide values for each dimension of capacity that a vehicle possesses. This information is then used by the optimization algorithm to ensure that the total capacity required by all shipments assigned to a vehicle does not exceed its capacity in any of the dimensions.

**Example**: Let's say a construction company has a fleet of trucks that are used to transport multiple things, such as bricks, cement, and even construction workers. Each truck has a different capacity for weight, volume, and number of persons it can carry.

In this case, the capacity parameter can be used to describe the multidimensional quantities for each truck. For example, a truck may have a capacity of 100 kg weight, 10 cubic meters of volume, and can carry 5 construction workers. The capacity parameter can be defined as [100, 10, 5] to represent these values respectively.

By leveraging the capacity in multiple dimensions, the solver can optimize job/shipment assignment to appropriate vehicles ensuring better customer service and efficient transportation.

### Amount

Amount parameter in `shipments` object is used to describe multidimensional quantities of a shipment. The term "multi-dimensional" refers to the fact that a single shipment can have amounts defined in different units. Continuing with our example of the construction company above, let’s say a truck needs to pick up 50 kg of bricks, and 2 cubic meters of cement from a construction material supplier’s location. When defining the shipment we define this input as

```
“amount”: [50,2,0]
```

0 for the construction worker dimension. Next, if we have another stop to pick up 3 construction worker, then we can define the amount as

```
“amount”: [0,0,3]
```

If the other parameters, like distance, time_windows, location of other trucks etc. are favorable then these 2 pickups can be assigned to the same vehicle with “capacity”: [100,10,5] like in this example.

Amount parameter is useful for optimizing delivery routes and determining the most efficient way to transport goods based on multiple dimensions of quantity.

### Skills

Skills parameter in the [Vehicles Object](#vehicle-object) describes the skills that a driver or vehicle possesses in different units. The term "multi-dimension" refers to the fact that a single driver or vehicle may have different skills or abilities, each of which could be measured in different units or quantities.

For example, let's say we have a fleet of delivery vehicles. One of these vehicles may have the following skills:

* Skill ID ‘101’: Capacity to carry 10 large boxes
* Skill ID ‘102’: Ability to transport goods at a temperature of -10 degrees Celsius
* Skill ID ‘103’: Ability to transport hazardous materials in a specific type of container

In this case, the Skills parameter would be set as an array of integers, with each element corresponding to a particular skill or ability. For instance, the skills parameter for the vehicle described above might be set as follows:

```
"skills": [101, 102, 103]
```

Here, the first element (101) corresponds to the vehicle's capacity to carry 10 large boxes, the second element (102) corresponds to its ability to transport goods at a temperature of -10 degrees Celsius, and the third element (103) corresponds to its ability to transport hazardous materials in a specific type of container.

By including `skills` attribute in the optimization API, users can optimize their delivery routes based on specific skills and abilities of their drivers and vehicles, helping to ensure that each delivery is made efficiently and safely.

#### Skills Restrictions

Use skills to describe a problem where not all tasks can be served by all vehicles. Job skills are mandatory, i.e. a job can only be served by a vehicle that has all its required skills. In other words: job j is eligible for vehicle v if j.skills is included in v.skills.
This definition implies in particular that:

* a task without skills can be served by any vehicle;
* a vehicle without skills can only serve tasks with no particular need (i.e. without skills as well).
* a job with multiple skills will be assigned to vehicles matching all the skills. The job will not be assigned to vehicles with partially matching skills.

In order to ease modeling problems with no skills required, not providing the skills key defaults to providing an empty array.

## Webhook Configurations

NextBillion.ai’s Route Optimization API now supports **webhook-based job status notifications**, giving users an automated and reliable way to track long-running optimization requests. Instead of repeatedly polling the GET status endpoint, you can configure a webhook URL to receive real-time alerts whenever an optimization job reaches a specific state such as completed or failed. This not only reduces the overhead of continuous polling but also enables faster, event-driven workflows within your application.

To enable webhook notifications, simply configure your callback endpoint using the `options.webhook` attribute while building your optimization request (see [Build an Optimization Request](#build-an-optimization-request) for full details). Once configured, the optimizer service automatically sends a POST request to your webhook URL whenever the job transitions to an event type you’ve subscribed to.

Each callback contains a structured JSON payload with the `event` name, the corresponding optimization `request_id`, and the event `timestamp`. This allows your backend to reliably trigger follow-up actions—such as fetching the completed solution, updating internal systems, or notifying downstream services.

Below is an example of a JSON payload sent when an optimization request completes:

```
{
  "event": "JOB_COMPLETED",
  "request_id": "xxxxx",
  "timestamp": 1731489600
}
```

## API Query Limits

* Nextbillion.ai allows a maximum rate limit of 300 queries per minute or 5 queries/second for continuous requests.

  *Note*: We can increase the quota if needed on request. Contact [support@nextbillion.ai](mailto:support@nextbillion.ai) for more details.
* At any point the maximum number of pending requests that the queue can hold is 25, for a given API key. New requests for the same key can be submitted once some of the pending requests are resolved.
* A maximum of 4000 locations can be added to the `locations` object
* A maximum of 4000 tasks can be added in an optimization problem. Number of tasks is calculated as number of jobs + 2 \* (number of shipments).
* Maximum value that can be provided for `truck_weight` is 100,000 kg.
* Maximum dimensions for `truck_size` are 5000 cm for length, 5000 cm for width, 1000 cm for height.
* When using `avoid=bbox`, the maximum perimeter allowed for the bounding box is 500 kilometers.
* The maximum number of routing profiles allowed are based on the number of locations being specified in the input. For number of input locations between

  * 1 and 100, the maximum number of profiles allowed, including the default routing configurations, are 15.
  * 100 and 600, the maximum number of profiles allowed, including the default routing configurations, are 6.
  * 600 and 1200, the maximum number of profiles allowed, including the default routing configurations, are 2.
  * If the number of locations in the input are more than 1200, then only profile can be specified.
* When using `traffic_timestamp` or truck related parameters in the `routing` property of `options` attribute, please expect a higher request processing time, especially if the number of locations provided in the request is also high.

## API Error Codes

| Response Code | Description | Additional Notes |
| --- | --- | --- |
| 200 | Normal success case. | Normal success case. |
| 400 | Input validation failed. | There is a missing or an invalid parameter or a parameter with an invalid value type is added to the request. |
| 401 | APIKEY not supplied or invalid. | This error occurs when the wrong API key is passed in the request or the key is missing altogether. |
| 403 | APIKEY is valid but does not have access to requested resources. | You might be querying for a geographical region which is not valid for your account or requesting a service which is not enabled for you. |
| 404 | Requested host/path not found. | This error occurs when a malformed hostname is used. |
| 413 | Request entity too large | This error is caused when the length of input request URI or the request body is too large. Please modify the request. Reach out to [support@nextbillion.ai](mailto:support@nextbillion.ai) if the issue still persists. |
| 422 | Could not process the request. | A feasible solution could not be generated for the given set of locations or parameter configuration. |
| 429 | Too many requests. | QPM reached or API request count quota reached. |
| 500 | Internal Service error. | There was an internal issue with NextBillion.ai services. You can reach out to [support@nextbillion.ai](mailto:support@nextbillion.ai) for an explanation. |
