Vehicle properties

Vehicle or courier ID

Each vehicle or courier must have a unique numeric or string ID set in the id field. The ID must be unique within a single service request. When exporting to Track & Trace, this identifier is used as the courier's username.

You can also specify the vehicle's or the courier's numeric or string ID from your tracking system in the ref field and the courier's mobile phone number in the phone field so that they can be contacted from Track & Trace.

Vehicle or courier capacity

In RouteQ you can define the vehicle capacity in terms of the maximum weight or cargo the vehicle/courier can transport over a single route.

To determine the vehicle or courier carrying capacity, use the capacity field (you can specify just one option):

  • capacity.weight_kg: Weight in kilograms or bulk weight.

  • The volume, which is measured in cubic meters and set as the product of dimensions:

    • capacity.volume.width_m: Width in meters.

    • capacity.volume.depth_m: Depth in meters.

    • capacity.volume.height_m: Height in meters.

    If you don't know the dimensions, you can set the volume value in one field and enter 1 in the other fields.

  • capacity.units: Number of units (pallets, boxes, kegs).

For more information about weight determination, see Weight and volume.

Note.

Please note that if the order weight is set in kilograms or as a volume weight, the vehicle capacity must be set in the same units. Similarly, if the order weight is set as the number of units, the vehicle capacity must specify the maximum number of units in each vehicle.

Additionally, you can set the maximum load of a vehicle as a percentage of the specified load capacity. To do this, use the limits request field:

  • limits.volume_perc: A percentage of the value specified in capacity.volume.width_m * capacity.volume.depth_mcapacity.volume.height_m.

  • limits.weight_perc: A percentage of the value specified in capacity.weight_kg.

  • limits.volume_perc: A percentage of the value specified in capacity.volume.

To indicate that overload is allowed relative to a given value, specify a value greater than 100. To leave spare load capacity, for example, to allow for the inaccurate estimation of order dimensions, specify a value less than 100. For example, a value of 110 allows for 10% overload and a value of 90 allows for a maximum load of 90% the specified load capacity.

The vehicle capacity (based on the limits) is a hard restriction that won't be violated. Note that, when calculating the vehicle load, the system takes into account the orders for pickup and delivery. For more information, see Pickup and delivery.

Note.

You can use the vehicle capacity to indirectly manage the number of orders that should be added to it. For example, if you set the volume per order to 1 unit (regardless of the actual size of the order) and the vehicle capacity to 10 units, then each vehicle will be assigned no more than 10 orders.

Example

There are two vehicles with a load capacity of 1.5 tons (Vehicle 1) and 3 tons (Vehicle 2) and three orders for delivery with a weight of 1 ton, 1.2 tons, and 1.4 tons, respectively.

When optimizing routes, the 1.2-ton order is placed in Vehicle 1 and the 1-ton and 1.4-ton orders are placed in Vehicle 2.

API request (JSON) API response View on map

Custom capacity units

Vehicle capacity in custom units.

The custom unit is set by two parameters:

  • capacity.custom.<sequential number>.name: Name of the custom unit.

  • capacity.custom.<serial number>.size: Vehicle carrying capacity in custom units.

By default, carrying capacity in the capacity.custom.<sequential number>.size parameter isn't limited.

You can set multiple custom units and assign any names to them.

Attention.

The name of the custom unit for the vehicle should be the same as the one given for the order.

If custom capacity units are specified for orders or explicitly specified for some vehicles, but not for others, then the vehicles with unspecified units will be taken to have unlimited carrying capacity in custom units.

Example of filling out Excel file sheets for a custom price parameter (order cost):

Order cost
shipment_size.custom.0.name shipment_size.custom.0.size
price 100
Order cost
shipment_size.custom.0.name shipment_size.custom.0.size
price 100

Example 1

This example shows the weight, volume, and number of cargo units. You can also set the order cost and the limit on the total order cost per vehicle using the location.shipment_size.custom and vehicle.capacity.custom parameters, respectively.

You can see that there are 2 vehicles transporting 1 order each. However, their weight, volume and number of units is small, because their order cost is close to the vehicle's limit.

API request (JSON) API response View on map

Example 2

The same as example 1, but the maximum number of orders that the courier can transport is also specified. The restriction is described using the parameters location.shipment_size.custom.0 and vehicle.capacity.custom.1. Each vehicle can now carry no more than 5 orders.

You can see that the number of orders in three cars has changed. Now one vehicle carries one order, and orders cannot be added due to the total cost limit. For the rest, maximum utilization by total cost in each vehicle was achieved, and it was possible to maintain the limit on the number of orders.

API request (JSON) API response View on map

Vehicle properties

You can specify vehicle properties in the vehicle.specs field. The following parameters can be specified:

  • width: Vehicle width in meters.

  • height: Vehicle height in meters.

  • length: Vehicle length in meters.

  • max_weight: Maximum vehicle weight in tons.

  • max_weight_kg: Maximum vehicle weight in kilograms (rounded up to the ton when addressing the planning task).

Note.

If you set the vehicle.specs.max_weight and vehicle.specs.max_weight_kg parameters simultaneously in the planning task, the solution will use vehicle.specs.max_weight.

The minimum value is 0 for all the listed properties.

Attention.

You can specify these parameters only for trucks (routing_mode = truck).

Load handling time at depot

The loading or unloading time at the depot may depend both on orders and vehicle properties (for example, dimensions or equipment).

To specify the amount of additional time required for loading at the depot, use the vehicle.depot_extra_service_duration_s parameter. The time is set in seconds.

Note.

The time assigned in the vehicle.depot_extra_service_duration_s parameter is summed up with the depot handling time.

Example

2 vehicles with the same load capacity are delivering 13 large orders. The handling time at the depot depot.service_duration_s is 5 minutes (300 seconds). Additional time is set for loading orders into a vehicle at the depot vehicle.depot_extra_service_duration_s: 30 minutes (1800 seconds). As a result of planning, each vehicle will spend 35 minutes at the depot before starting their routes.

API request (JSON) API response View on map

Vehicle started not from the depot

By default, vehicles and couriers start from the depot. However, sometimes they need to start the route from another point (for example, from their home or parking spot). That's a usual task in the case of sales representatives, service engineers, and other specialists who don't deliver goods, but provide services.

You can implement this requirement using the property vehicle.start_at. In this case, the courier or vehicle will start their route from the specified point with the type garage, rather than from the depot.

Visiting the depot before the start of the working day

At the beginning of the working day, couriers may need to visit the depot to get their orders there. Use the property vehicle.visit_depot_at_start to enable this. If you specify true, the courier or the vehicle must visit the depot before starting the delivery (this is default behavior). Otherwise, they can immediately start delivering orders. To learn more, see Start or end of the route at an arbitrary point.

Example 1

Delivery is carried out by three cars:

  • The first one starts the delivery from the depot.

  • The second one starts and ends the route without visiting the depot. The starting point for the courier is order 6, which has the garage type.

  • The third one starts the route not from the depot, but from order 4 (the garage type), but must visit the depot before starting the delivery.

API request (JSON) API response View on map

Example 2

Delivery is carried out by three cars:

  • The first one starts the delivery from the depot.

  • The second and the third vehicles start and end the route without visiting the depot. Orders 1 and 7 have the pickup type, and the algorithm selects them as the first route points.

Three separate routes are planned in the solution because of the orders' priorities.

API request (JSON) API response View on map

Start from one of several depots

A courier can start from one of several depots. These depots have to be listed in the depot_id field (depots that the courier can visit) or starting_depot_id (depots from which the courier can start their route). These lists can overlap. If there are several depots, the algorithm will choose the optimal depot to start from.

Note.

If the fields depot_id and starting_depot_id are not entered for a courier, they start from the first depot in the depots list.

If you use the delivery from one of several depots functionality, a courier will be able to pick up orders from any depot they can visit.

You can additionally set the allow_different_depots_in_route and max_middle_depots parameters for a courier. For more information, see Choosing the optimal depot to start from.

Additional loading at an intermediate depot

For a courier to be able to visit additional depots for reloading orders while following the route, set the allow_different_depots_in_route = true parameter. These depots have to be listed in the depot_id field (depots that the courier can visit) or middle_depot_id (depots for reloading). Depot lists can overlap. If there are orders in several depots, the algorithm will select the optimal depot for reloading.

If the courier can stop at intermediate depots for reloading only at the beginning of the route (before completing the first order), set depots_only_at_run_beginning = true (the default is false).

You can additionally set the max_middle_depots parameter for a courier. For more information, see Visiting an additional depot.

Returning to a depot at the end of the route or run

By default, the courier completes the route at the depot where they started. To allow the courier to visit several depots along the route, set allow_different_depots_in_route = true. In this case, the courier can end the route at a depot other than the first one.

Depots where a courier can end their route are specified in the depot_id field (depots that the courier can visit) or ending_depot_id field (depots from which the courier can complete their route). These lists can overlap. If there are several depots, the algorithm will choose the optimal depot to complete the route at.

To have the courier end the route at the same depot where they started, set finish_route_in_starting_depot = true (the default is false). If the courier starts the route not from a depot (visit_depot_at_start = false), they are to return to the depot they stopped at during the second run of the route.

To have the courier end each run at the same depot where that run started, set finish_run_in_starting_depot = true (the default is false). To allow the courier to change from depots between runs, set can_change_depot_between_runs = true (see Start of a new run from a different depot).

Note.

Parameters finish_route_in_starting_depot = true and finish_run_in_starting_depot = true are only viable if allow_different_depots_in_route = true.

If the courier doesn't have to return to the depot after all the orders are completed, use the return_to_depot = false option.

Example 1.1

Two couriers are to deliver two orders: one is a delivery order that needs to be picked up from Depot 1, and the other one is a pickup order to be delivered to Depot 2. The couriers can only make 1 run each, starting at any depot and ending the route at any depot. Both couriers are allowed to stop at different depots during one run, but they cannot stop at intermediate depots.

The solution uses only one courier: they leave Depot 1 after picking up the delivery order, deliver it, pick up the pickup order, and deliver it to Depot 2, where they end the route.

API request (JSON) API response View on map

Example 1.2

The same as in example 1.1, but the couriers need to end the route at the same depot where they started (finish_route_in_starting_depot = true).

The solution uses both couriers. Courier 1 leaves Depot 1 after picking up the delivery order, delivers it, and returns to Depot 1. The second courier leaves Depot 2, picks up the pickup order, and returns with it to Depot 2.

API request (JSON) API response View on map

Returning to any point at the end of the route

If your work scenario needs to take into account the distance of the last order from the courier's parking spot (or home address, for example), you can implement it as follows:

  • Create a point with the garage type (the locations.type field). This point will only be used to end the routes.

  • For a courier who needs to return “home” or to the “parking spot” at the end of their working day, enter the ID of this point in the vehicle.finish_at field.

In the solution, all vehicles or couriers that have the finish_atproperty specified return to the specified point. If the option to return to the depot is enabled (vehicle.return_to_depot = true), the route will first go the depot and then to the parking spot.

Example

The example below uses two vehicles with different load capacities and four orders with different weights. Two vehicles are used for delivery because of the weight restrictions. Vehicle 2 doesn't have to return to the depot after it delivers the last order.

Note.

Note that in the RouteQ response, vehicle 2 completes the route at the last order location.

API request (JSON) API response View on map

Start or end of the route as close to the depot as possible

You can plan a route so that the courier starts or finishes on the order that is closest to or furthest from the depot. For example, if you expect to get new orders in the morning, then it would be better to start the route with the orders closest to the depot. That way, it will be easier for the courier to return to the depot to pick them up. On the other hand, by starting the route with the farthest order, the courier would finish closer to the depot in the evening.

If you are not using advanced cost settings, set the following parameters:

  • first_edges_penalty_factor: A penalty for the distance from the depot to the first order, the default is 0. If the value is greater than 0, the algorithm minimizes this distance, and if the value is less than 0, it maximizes it.

  • last_edges_penalty_factor: A penalty for the distance from the depot to the last order, the default is 0. If the value is greater than 0, the algorithm minimizes this distance, and if the value is less than 0, it maximizes it.

If penalty values are high, routes may be suboptimal in terms of mileage. If penalty values are low, then the first or last order of a route may be selected in violation of any requirements provided it saves on mileage.

If you are using advanced cost settings, use the keywords from the Travel from or to the depot group.

Example

In the example below, there is 1 courier and 10 orders. Two penalties are set: first_edges_penalty_factor = 2 and last_edges_penalty_factor = -2. Planning produces a route that begins with the order closest to the depot and ends with the furthest order.

API request (JSON) API response View on map

Vehicle or courier shifts

You can define one or more work shifts for a vehicle. Use the vehicle.shifts field to define the shifts.

A shift is a time range when the vehicle is allowed to operate. Shift time includes the loading time at the depot, traveling time, and handover time at order locations.

You can also restrict the maximum shift duration.

To use one or more shifts in Excel, define the following fields:

  • shifts.0.time_window: The time window corresponding to the vehicle's operating hours.

  • shifts.0.hard_window: The hard time window flag.

  • shifts.0.service_duration_s: Time between shifts (in seconds). For example, it can be the time needed to replace the driver or exchange documents.

In the case of a soft time window, you can set additional penalties:

  • For time window violation:
    • shifts.0.penalty.out_of_time.fixed: A fixed penalty for one-time violation of the shift's time window.
    • shifts.0.penalty.out_of_time.minute: A penalty per minute of the shift's time window violation.
  • For early departure:
    • shifts.0.penalty.early.fixed: A fixed penalty for one-time start of work before the shift's time window.
    • shifts.0.penalty.out_of_time.minute: A penalty per minute of work start before the shift's time window.
  • For late arrival:
    • shifts.0.penalty.late.fixed: A fixed penalty for one-time work completion later than the shift's time window.
    • shifts.0.penalty.late.minute: A penalty per minute of work end after the shift's time window.

To limit permissible violations of the shift's time window, you can set a hard window around a soft one.

Note.

Note that to define multiple shifts, you need multiple Excel fields with an increasing numeric index.

For example, shifts.0.time_window refers to the first shift, and shifts.1.time_window refers to the second shift.

Example

The request to RouteQ includes one vehicle with three shifts (morning, afternoon, and evening) and three orders, of which one order has a delivery time in the morning, and two others in the evening.

Note.

Note that the RouteQ response will only use the morning and evening shifts, since there are no delivery orders for the day shift.

API request (JSON) API response View on map

Multiple vehicle runs per day

By default, a vehicle or courier starts and ends their route at a depot, completing exactly one route during a working day (shift).

If a vehicle can return to the depot anytime during the work shift to pick up additional orders, limit the number of runs using one of the parameters:

  • vehicle.shifts.N.max_runs: The maximum number of runs per shift.
  • vehicle.max_runs: The maximum number of runs for all a vehicle's shifts.

You can limit either the number of runs per shift or the total number of runs, but not both parameters at the same time.

If no shifts are set for a vehicle, then max_runs is used as a limit on the total number of runs (1 by default).

If shifts are set for a vehicle, and at the same time:
  • max_runs is specified for the vehicle, then this value is used as a limit for each shift (for example, the vehicle can perform all the runs in one shift). The number of vehicle runs can be lower than the number of shifts.
  • max_runs is specified for shifts, then the total number of runs is added up across shifts.
  • max_runs is not specified, then the vehicle can make as many runs as it has shifts (one run per shift).
Note.

If vehicle.max_runs = 0, then the number of shifts (if specified) or 1 (if no shifts are specified) is used instead.

If some shifts aren't used but are defined in the request, they're counted as 1 run.

Example

The example below uses one vehicle with the limited carrying capacity of 2 tons and three orders with a weight of 0.8 tons. The vehicle is allowed to do two runs. This means that after completing two orders, the vehicle can return to the depot to pick up and deliver another order.

API request (JSON) API response View on map

Limit the number of stops per shift

When planning a route, you can specify the minimum and maximum number of stops in the route. This can be useful, for example, to limit the maximum vehicle workload per day or, on the contrary, make sure that the vehicle gets on the route with a certain minimum number of stops.

For this, RouteQ uses the minimal_stops and maximal_stops shift parameters. You can set the number of stops for each vehicle.

The restriction is not strict and may be violated. If the limit on the minimum number of stops is violated, a penalty applies. The penalty is specified in the following shift fields: penalty.stop_lack.fixed (for making fewer stops than the minimum number) and penalty.stop_lack.per_stop (for each stop missing under the minimum number).

In the same way, if the limit on the maximum number of stops is violated, a penalty applies. The penalty is specified in the following shift fields: penalty.stop_excess.fixed (for making more stops than the maximum number) and penalty.stop_excess.per_stop (for each stop above the maximum number).

Usually when you restrict the number of stops, the solution metrics degrade since the solution favors restrictions at the cost of the optimal route.

Note.

By default, the minimal_stops limit applies to all specified vehicles. When you specify more vehicles than necessary, and the penalty.stop_lack penalty value is too high, planning results may be suboptimal.

To limit the minimum number of stops per shift and build an effective route at the same time, use the ignore_min_stops_for_unused option (see Counting the minimum number of stops only for couriers).

Example 1

In the example, the route is built for 3 vehicles that deliver to 15 points. Since there are no restrictions for the route, the route is built the usual way.

API request (JSON) API response View on map

Example 2

This example has the same conditions as example 1, but sets the limit of 4 minimum stops per vehicle. As a result, the routes changed so that each vehicle visited at least 4 delivery locations.

API request (JSON) API response View on map

Example 3

This example has the same conditions as example 1, but sets the limit of 5 maximum stops per vehicle. In the result, orders are distributed evenly among all vehicles, even though several orders are located next to each other and can be completed by one vehicle.

API request (JSON) API response View on map

Maximum shift duration

Sometimes you may need to extend the courier's working hours. But you also need to limit the maximum shift length and set the window you want to fit into. Let's day you have a 14-hour time window for courier delivery (for example, from 8:00 to 22:00), but each courier shouldn't work more than 8 hours.

RouteQ helps you schedule shifts with hard time windows and preferred lengths. In this case, the courier's shift length doesn't affect the work start time. It only affects the time that they spend completing orders.

The maximum shift length can be set as a soft restriction shifts.N.max_duration_s that can be violated for a penalty or as a hard restriction shifts.N.hard_max_duration_s that can't be violated:

  • When planning with a soft restriction, the workload that doesn't fit into one courier's preferred shift is distributed among others or to the same courier, but with penalties for violating the shift length. All orders that can't be completed in max_duration_s are added to the route with the penalty specified in the shift.penalty.late field (if applicable) or in the shift.penalty.out_of_time field all other times. The total route penalty for violating the maximum shift length is shown in the API response in the overtime_penalty field. If the estimated order cost including penalties is higher than the cost of completing the order by another courier, the order is handed over to another courier.

  • When planning with a hard restriction, the courier's shift never exceeds the hard_max_duration_s value.

If you use both restrictions, the hard one can't be less than the soft one. By default, max_duration_s is 2 days, and hard_max_duration_s is 30 days.

Example 1

Let's say the shift window shifts.N.time_window is from 8:00 to 23:00. By default, routes will be built to use the minimum number of couriers.

If you specify max_duration_s = 14400, the load is distributed between couriers, and each of them works for approximately 4 hours (the shift length is set in seconds). Some couriers may still work more than 4 hours, because it's less costly to pay for extra hours than to hand over the order to another courier.

As a result of planning, orders are distributed among three couriers. One courier's shift went over 4 hours. The penalty amount is shown in the API response in the overtime_penalty field.

API request (JSON) API response View on map

Example 2

The same as in Example 1, but with hard restrictions on the maximum shift length: hard_max_duration_s = 14400. When planning, all couriers are given shifts that are 4 hours or less. As a result, the number of couriers increased to 4.

API request (JSON) API response View on map

Maximum mileage per shift

In some cases, you need to limit the mileage per vehicle. For example:

  • The planning includes hired cars, and their rate implies limited mileage.

  • You can assign specific vehicles for far-away points. Then you can limit the mileage for other vehicles.

The shifts.max_mileage_km parameter determines the maximum vehicle mileage per shift. The entire mileage is taken into account, including:

  • Traveling from the depot or starting point to the first point from the order list.

  • Returning to the depot or end point of the route from the last point in the order list.

The restriction is soft: the algorithm may violate it. Penalties are set in the fields:

  • shifts.penalty.max_mileage.fixed: A fixed penalty for exceeding the maximum mileage (1000 by default).

  • shifts.penalty.max_mileage.km: A penalty per each kilometer in excess of the maximum mileage (100 by default).

If the maximum mileage per run is critical to you, and the vehicle can do several runs per shift, create multiple identical shifts (see Example 2).

If the courier uses public transit, only the walking part of the route is returned as the mileage.

Example 1

The mileage limit per courier is 50 km. A big penalty is applied in case of violation. In the result, the planned mileage on any route doesn't exceed 50 km.

API request (JSON) API response View on map

Example 2

There is one courier and each their run must be limited by 50 km. For this, the courier must have several shifts with the same time windows and mileage restrictions. The result includes 3 routes, each one less than 50 km long.

API request (JSON) API response View on map

Route grouping

To set the preferred area of work for a vehicle so that the route includes orders near a certain location, use the global_proximity_attraction_point parameter. In the parameter value, specify the location id with the garage type. This is used as a “hotspot”: the algorithm aims to reduce the total distance between orders on the route and this location.

The proximity of routes to the hotspot is determined by the options.global_proximity_factor option: the greater its value, the denser the grouping. For more information about this option, see Grouped routes.

The maximum distance from the route locations to the “hotspot” is stored in the max_distance_to_attraction_point_m parameter, which can be used to calculate the cost of the route. The total sum of distances from all orders to the “hotspot” on the route affects the penalty for insufficient route grouping.

Other ways to group orders geographically
  • You can use the global_proximity_factor option to build grouped routes without setting a “hotspot”. This option only works for vehicles that don't have the global_proximity_attraction_point parameter set.
  • By using geofences for vehicles, you can set restrictions on delivery zones. The geofence restriction can't be violated. In contrast, the route grouping settings are a more flexible tool.

Example 1

Three vehicles have to deliver 15 orders. The route is calculated based on the order weight and vehicle capacity. There are no other restrictions on the route.

API request (JSON) API response View on map

Example 2

The same as in example 1, but each courier has a set “hotspot” that shows their preferred area of work. As a result, the routes are more grouped. The maximum distance from the order to the “hotspot” on the route is 20,663 m.

API request (JSON) API response View on map

Example 3

The same as in example 2, but one of the couriers has a different “hotspot”. Because orders are regrouped, the location of routes on the map has changed. The maximum distance from the order to the “hotspot” increased to 28,528 m.

API request (JSON) API response View on map

Vehicle or courier cost

You can specify different cost-of-use components for each vehicle in the query to RouteQ. To set the cost-of-use for the vehicle or courier, use the optional vehicle.cost field.

RouteQ lets you define the following main cost components:

  • cost.fixed: The fixed cost-of-use for the vehicle.

  • cost.hour: The cost per hour of work.

  • cost.km: The cost per kilometer of mileage.

  • cost.location: The cost per visit of one order.

  • cost.run: The cost per run.

  • cost.tonne_km: The cost per ton-kilometer of transport work.

In this case, the cost at which the algorithm selects the optimal routing option is used. That's not the actual rate for using the vehicle, but rather the algorithm's settings.

You can also set the cost-of-use for the vehicle or courier as an arithmetic expression. For more information, see Advanced cost settings.

Cost values

Please note that some components of vehicle cost are already set by default:

  • cost.fixed = 3000

  • cost.hour = 100

  • cost.km = 8

They apply in the following cases:

  • If you use Excel and leave these fields blank.

  • If you make an API request and don't fill in the vehicle.cost field.

The default values often need to be adjusted. For example, adjust them in the following business cases:

Always set cost.hour and cost.km to values other than 0, otherwise, the routes will be chaotic. That happens because the algorithm optimizes the total cost. If the cost per hour or kilometer equals 0, the route will cost the same with any mileage.

The cost of a ton-kilometer of transport work

Heavily loaded vehicles use more fuel and wear out faster. That's why routes for transporting heavy goods need to be built in such a way that the vehicle travels the minimal possible distance while heavily loaded.

RouteQ uses the cost.tonne_km property to do this. It determines the cost of one kilometer for each ton of cargo in the vehicle. Default value: 0.

The total amount of transport work in ton-kilometers is returned to the total_transport_work_tonne_km field of the API response, and its total cost is in the total_transport_work_cost field.

Example 1

You need to deliver 3 cargos weighing 100, 200, and 2000 kg. The cost.tonne_km cost per ton-kilometer is set to zero. As a result, the heaviest order was delivered last: the vehicle load wasn't taken into account when building the route, and based on other criteria, this option was optimal.

API request (JSON) API response View on map

Example 2

The source data is the same, but cost.tonne_km = 8. The resulting solution is optimized, taking the load into account: the heaviest order is unloaded first.

API request (JSON) API response View on map

Advanced cost settings

You can set the cost-of-use for the vehicle or courier as an arithmetic expression. When planning, you can calculate the cost with one expression in the vehicles.cost field or use multiple expressions in nested fields:

  • cost.route: For a route.
  • cost.shift: For a shift.
  • cost.run: For a run.
Attention.

If the vehicle.cost field has formulas, then the algorithm calculates the cost-of-use for the vehicle or courier based only on these formulas. Standard cost components are included in the calculation only if they are explicitly specified in the formulas.

The expression can use keywords and mathematical notation given in the tables below. To check the expression, use an HTTP request.

Keywords for route parameters

Group Keyword and explanation
Runs
  • run_index_in_route: The run number in the route, starting with 1. Only for runs.
  • run_count_in_route: The number of runs in the route. Only for routes.
  • run_index_in_shift: The run number in the shift, starting with 1. Only for runs.
  • run_count_in_shift: The number of runs in the shift. Only for runs or shifts.
  • runs: The number of runs. If the variable is used for a run, then its value is 1. For a shift, it's runs = run_count_in_shift, and for the entire route, runs = run_count_in_route.
Shifts
  • shift_index_in_route: The shift number in the route, starting with 1. Empty shifts are skipped and not counted.
  • shift_count_in_route: The number of used (non-empty) shifts in the route.
Orders
  • locations: The number of orders.
  • total_custom_value: The sum of the custom_value field values (additional order parameter) for all orders in a route.
  • max_custom_value: The maximum value of the custom_value field for all orders in a route.
Duration
  • duration_h: The total duration of routes, in hours.
  • transit_duration_h: The duration of traveling.
  • service_duration_h: The duration of handling orders.
  • wait_duration_h: The waiting duration.
  • rest_duration_h : The rest duration.
Distance
  • distance_km: The total length of routes, in km.
  • max_distance_from_depot_m: The distance from the depot to the farthest location in the route.
  • max_distance_to_garage_m: The maximum distance to a garage at the end of the route.
  • max_distance_to_attraction_point_m: The maximum distance from the route locations to the “hotspot” specified in global_proximity_attraction_point. If the option isn't set, max_distance_to_attraction_point_m = 0.
Transport work transport_work_tonne_km: The transport work, in ton-kilometers.
Stops
  • stops: The number of stops (neighboring locations with the same coordinates are considered one stop).
  • unique_stops: The number of stops with unique coordinates.
Depots middle_depots: The number of intermediate depots on the route.
Start and end of the route
  • start_route_time_s: The start time of the route in seconds from the beginning of the day.
  • finish_route_time_s: The end time of the route in seconds from the beginning of the day.
Travel from or to the depot
  • first_edges_distance_km: The total length of the way to the first order for all routes, in km.
  • last_edges_distance_km: The total length of the way from the last order for all routes, in km.
  • first_edges_duration_h: The total duration of the way to the first order for all routes, in hours.
  • last_edges_duration_h: The total duration of the way from the last order for all routes, in hours.

These parameters are used to implement the same scenarios as those found in penalties for the start or end of the route as close to the depot as possible.

Travel between orders
  • max_edge_distance_m: The maximum distance between orders for all routes, in meters.
  • max_edge_duration_h: The maximum duration of travel between orders for all routes, in hours.
Travel with and without orders
  • empty_distance_km: The distance traveled without orders (empty runs), in km.
  • non_empty_distance_km: The distance traveled with at least one order, in km.
Capacity
  • utilization_cbm: The maximum load capacity of the vehicle.
  • utilization_units: The maximum order load capacity of the vehicle.
  • utilization_kg: The maximum load weight of the vehicle.
  • min_free_units: The minimum free space in the vehicle.
  • min_free_weight_kg: The minimum free weight in the vehicle.
  • min_free_volume_cbm: The minimum free volume in the vehicle.
  • total_weight_kg: The total weight of transported cargo.
  • total_units: The total amount of transported cargo.
  • total_volume_cbm: The total volume of transported cargo.
Trailer
  • trailer_used: If a trailer is used on the route, trailer_used = 1. If it isn't used, trailer_used = 0.
  • trailer_duration_h: The total duration of trailer use, in hours.
  • trailer_distance_km: The distance traveled with the trailer, in km.
Walking routes
  • walking_transit_duration_h: The time spent walking.
  • driving_transit_duration_h: The time spent driving.
  • walking_distance_km: The distance the courier walked.
  • driving_distance_km: The distance the courier drove.
Group Keyword and explanation
Runs
  • run_index_in_route: The run number in the route, starting with 1. Only for runs.
  • run_count_in_route: The number of runs in the route. Only for routes.
  • run_index_in_shift: The run number in the shift, starting with 1. Only for runs.
  • run_count_in_shift: The number of runs in the shift. Only for runs or shifts.
  • runs: The number of runs. If the variable is used for a run, then its value is 1. For a shift, it's runs = run_count_in_shift, and for the entire route, runs = run_count_in_route.
Shifts
  • shift_index_in_route: The shift number in the route, starting with 1. Empty shifts are skipped and not counted.
  • shift_count_in_route: The number of used (non-empty) shifts in the route.
Orders
  • locations: The number of orders.
  • total_custom_value: The sum of the custom_value field values (additional order parameter) for all orders in a route.
  • max_custom_value: The maximum value of the custom_value field for all orders in a route.
Duration
  • duration_h: The total duration of routes, in hours.
  • transit_duration_h: The duration of traveling.
  • service_duration_h: The duration of handling orders.
  • wait_duration_h: The waiting duration.
  • rest_duration_h : The rest duration.
Distance
  • distance_km: The total length of routes, in km.
  • max_distance_from_depot_m: The distance from the depot to the farthest location in the route.
  • max_distance_to_garage_m: The maximum distance to a garage at the end of the route.
  • max_distance_to_attraction_point_m: The maximum distance from the route locations to the “hotspot” specified in global_proximity_attraction_point. If the option isn't set, max_distance_to_attraction_point_m = 0.
Transport work transport_work_tonne_km: The transport work, in ton-kilometers.
Stops
  • stops: The number of stops (neighboring locations with the same coordinates are considered one stop).
  • unique_stops: The number of stops with unique coordinates.
Depots middle_depots: The number of intermediate depots on the route.
Start and end of the route
  • start_route_time_s: The start time of the route in seconds from the beginning of the day.
  • finish_route_time_s: The end time of the route in seconds from the beginning of the day.
Travel from or to the depot
  • first_edges_distance_km: The total length of the way to the first order for all routes, in km.
  • last_edges_distance_km: The total length of the way from the last order for all routes, in km.
  • first_edges_duration_h: The total duration of the way to the first order for all routes, in hours.
  • last_edges_duration_h: The total duration of the way from the last order for all routes, in hours.

These parameters are used to implement the same scenarios as those found in penalties for the start or end of the route as close to the depot as possible.

Travel between orders
  • max_edge_distance_m: The maximum distance between orders for all routes, in meters.
  • max_edge_duration_h: The maximum duration of travel between orders for all routes, in hours.
Travel with and without orders
  • empty_distance_km: The distance traveled without orders (empty runs), in km.
  • non_empty_distance_km: The distance traveled with at least one order, in km.
Capacity
  • utilization_cbm: The maximum load capacity of the vehicle.
  • utilization_units: The maximum order load capacity of the vehicle.
  • utilization_kg: The maximum load weight of the vehicle.
  • min_free_units: The minimum free space in the vehicle.
  • min_free_weight_kg: The minimum free weight in the vehicle.
  • min_free_volume_cbm: The minimum free volume in the vehicle.
  • total_weight_kg: The total weight of transported cargo.
  • total_units: The total amount of transported cargo.
  • total_volume_cbm: The total volume of transported cargo.
Trailer
  • trailer_used: If a trailer is used on the route, trailer_used = 1. If it isn't used, trailer_used = 0.
  • trailer_duration_h: The total duration of trailer use, in hours.
  • trailer_distance_km: The distance traveled with the trailer, in km.
Walking routes
  • walking_transit_duration_h: The time spent walking.
  • driving_transit_duration_h: The time spent driving.
  • walking_distance_km: The distance the courier walked.
  • driving_distance_km: The distance the courier drove.

Route metrics are calculated using the following formulas:

  • total route duration transit_duration_h = walking_transit_duration_h + driving_transit_duration_h
  • total route length distance_km = walking_distance_km + driving_distance_km

The calculation of variables that are used in routes with walking parts is influenced by the transportation method:

  • walking: The entire route is traveled on foot, and the distance driving_distance_km and duration driving_transit_duration_h equal 0.
  • transit:
    • driving_distance_km = 0: It's assumed that the courier visited all orders on foot (there isn't enough data to calculate the distance traveled by public transport).
    • driving_transit_duration_h is calculated based on other data received when solving the problem (it may be non-zero).

Mathematical notation and functions

Mathematical notations Explanation
Numbers

Integers (positive, negative), rational.

Use a dot as a separator for decimals.

Arithmetic operations +, -, *, /
Parentheses (…)
Mathematical functions
  • max()/min(): With an arbitrary number of operands.
  • Round(): Rounding to an integer.
  • Ceil(): Rounding to a larger integer.
  • Floor(): Rounding to a smaller integer.
  • Abs(): Calculating the absolute value (modulus) of a number.
  • RoundTo()/CeilTо()/FloorTo(): Rounding fractions to the digit that a user sets, for example, (RoundTo(x, 100) == 100*Round(x/100)).
Logical functions bool(): Converts any nonzero real number to 1.0, and zero number to 0.0.
Comparison operations <, >, =
Logical operations
  • &: Logical AND.
  • |: Logical OR.
  • !: Logical negation.
Functions
  • has_location(<condition>): Checks whether any stops in the route (run, shift) match the criteria.
  • has_order(<condition>): Checks whether any orders (pickup or delivery) in the route (run, shift) match the criteria.
  • order_count(<condition>): Returns the number of orders ( (pickup or delivery) in the route (run, shift) that match the criteria.
  • stop_count(<condition>): Returns the number of stops (pickup, delivery or dropoff) in the route (run, shift) that match the criteria. In a multi-order, all orders will be counted as one stop.
  • location_count(<condition>): Returns the number of stops of any type in the route (run, shift) that match the criteria. In a multi-order, each order will be counted as a separate stop.
Function conditions

The following functions can only be used inside the has_location, has_order, order_count, stop_count, and location_count function conditions:

  • in_zone(<zone name>): Checks if the stop is in the specified zone.
  • has_load_type(<name of the load type>): Checks if the order has the specified load type.
  • has_required_tag(<tag name>): Checks if the order has the specified required tag.
  • has_optional_tag(<tag name>): Checks if the order has the specified optional tag.
  • has_tag(<tag name>): Checks if the order has the specified tag (optional or required).
  • is_order(): Checks if the stop is an order (pickup or delivery).
  • is_pickup(): Checks if the stop is a pickup order.
  • is_delivery(): Checks if the stop is a delivery order.
Mathematical notations Explanation
Numbers

Integers (positive, negative), rational.

Use a dot as a separator for decimals.

Arithmetic operations +, -, *, /
Parentheses (…)
Mathematical functions
  • max()/min(): With an arbitrary number of operands.
  • Round(): Rounding to an integer.
  • Ceil(): Rounding to a larger integer.
  • Floor(): Rounding to a smaller integer.
  • Abs(): Calculating the absolute value (modulus) of a number.
  • RoundTo()/CeilTо()/FloorTo(): Rounding fractions to the digit that a user sets, for example, (RoundTo(x, 100) == 100*Round(x/100)).
Logical functions bool(): Converts any nonzero real number to 1.0, and zero number to 0.0.
Comparison operations <, >, =
Logical operations
  • &: Logical AND.
  • |: Logical OR.
  • !: Logical negation.
Functions
  • has_location(<condition>): Checks whether any stops in the route (run, shift) match the criteria.
  • has_order(<condition>): Checks whether any orders (pickup or delivery) in the route (run, shift) match the criteria.
  • order_count(<condition>): Returns the number of orders ( (pickup or delivery) in the route (run, shift) that match the criteria.
  • stop_count(<condition>): Returns the number of stops (pickup, delivery or dropoff) in the route (run, shift) that match the criteria. In a multi-order, all orders will be counted as one stop.
  • location_count(<condition>): Returns the number of stops of any type in the route (run, shift) that match the criteria. In a multi-order, each order will be counted as a separate stop.
Function conditions

The following functions can only be used inside the has_location, has_order, order_count, stop_count, and location_count function conditions:

  • in_zone(<zone name>): Checks if the stop is in the specified zone.
  • has_load_type(<name of the load type>): Checks if the order has the specified load type.
  • has_required_tag(<tag name>): Checks if the order has the specified required tag.
  • has_optional_tag(<tag name>): Checks if the order has the specified optional tag.
  • has_tag(<tag name>): Checks if the order has the specified tag (optional or required).
  • is_order(): Checks if the stop is an order (pickup or delivery).
  • is_pickup(): Checks if the stop is a pickup order.
  • is_delivery(): Checks if the stop is a delivery order.
Examples of expressions
  • 500 + 500 * has_location(in_zone('West')): If the route has a stop in the West zone, then the expression will return 1000, otherwise, 500.
  • 450 * location_count(in_zone('West') | in_zone('North')): Counts the number of stops in at least one of the two zones (West, North) and returns that number multiplied by 450.
  • 1000 + has_location(in_zone('West') & has_load_type('Freeze')) * 500: If there's at least one stop in the route that's in the West zone and has the Freeze load type at the same time, the expression returns 1500, otherwise, 1000.
  • 100 * (has_location(in_zone('West')) & has_location(in_zone('North'))): If there's at least one stop in the West zone and at least one stop in the North zone (there can be one stop in both zones or two different ones), the expression returns 100.
  • 100 * has_location(in_zone('West') & in_zone('North')): If there's a stop that's in the West and North zones at the same time, the expression returns 100.
  • 100 * location_count(is_pickup() & in_zone('West') & !has_tag('Return')): The expression counts the number of pickup orders that are in the West zone and at the same time don't have the Return tag, and returns their number multiplied by 100.

Solution metrics

If the vehicle or courier have advanced cost settings set, you'll see the following fields in the solution metrics:

  • run_custom_cost: The cost of the run calculated using the cost.run formula.
  • shift_custom_cost: The cost of the shift calculated using the cost.shift formula. Shown only for the first run of the shift.
  • shift_total_custom_cost: The total cost of the shift. It includes the cost of the shift calculated using the formula plus the cost of all the shift's runs. Shown only for the first run of the shift.
  • route_custom_cost: The cost of the route calculated using the cost.route formula. Shown only for the first run of the route.
  • total_custom_cost: The full cost of the route, including the cost of the route calculated using the formula plus the cost of all the shifts. Shown only for the first run of the route, the other runs have it as 0.

Example 1

The task uses the following pricing plan:

  • The basic cost of one multi-order is 170 units.

  • The cost of a multi-order increases by 20 units every 100 kilometers.

  • The courier receives at least 4000 units per shift even if the number of orders is insufficient.

This pricing corresponds to the following cost: 100 * duration_h + 8 * distance_km + max(4000, (170 + 20 * Floor(distance_km / 100)) * unique_stops).

As a result, the cost of using each vehicle is at least 4000. The cost in excess of the shift payment (or delivered orders) is formed based on the total time and route length.

API request (JSON) API response View on map

Example 2

You need to plan a route, provided that the cost depends on the mileage and is determined using the formula:

<vehicle cost> = maximum {<minimum route cost>, <number of points on the route> * <cost of delivery to the point>}

The minimum route cost and cost of delivery to the point are indicated in the table:

Mileage The cost of one multi-order (rubles) The minimum route cost (rubles)
no more than 150 km 510 6000
no more than 450 km 530 7000
no more than 750 km 550 8500
over 750 km 570 11000
Mileage The cost of one multi-order (rubles) The minimum route cost (rubles)
no more than 150 km 510 6000
no more than 450 km 530 7000
no more than 750 km 550 8500
over 750 km 570 11000

When planning, the vehicle cost is calculated using the formula:

max(6000 + (distance_km > 150)*1000 + (distance_km > 450)*1500 + (distance_km > 750)*2500, stops*(510 + min(60, Ceil(max(0, distance_km - 150)/300)*20)))

More about the calculation formula
  • The minimum route cost: 6000 + (distance_km > 150)*1000 + (distance_km > 450)*1500 + (distance_km > 750)*2500
  • The number of points on the route is determined using the stops parameter.
  • The cost of delivery to the point is determined as follows. The minimum multi-order cost is 510, the maximum possible addition to it is 570 - 510 = 60. It's important that the cost of multi-orders increases uniformly in increments 20 for every 300 km of mileage. This can be represented using the formula Ceil(max(0, distance_km - 150)/300)*20. Then the cost of delivery to the point, based on the data from the table, is equal to 510 + min(60, Ceil(max(0, distance_km - 150)/300)*20)).

As a result, vehicle 1 has a route length of more than 150 km, the number of stops is 18 (1 multi-order). The final cost is 9540. Vehicle 2 has a route length of no more than 150 km, the number of stops is 21 (1 multi-order). The total cost is 10,710.

API request (JSON) API response View on map

Example 3

You need to plan the route so as to minimize underloading the vehicle. To do this, you can set an additional vehicle cost in the formula, provided that its load is below a certain limit. For example, when planning vehicles with a load capacity of 3000 kg, load them by at least 80%. Note that we assume that the remaining cost (per hour, per km, for the fact of use) will be set by default. The vehicle cost is calculated using the formula:

3000 + duration_h*100 + distance_km*8 + max(0, 2400 - utilization_kg) * 100

More about the calculation formula
3000, 100, 8 in the first three summands are default values of the cost per use, per hour, and per kilometer, respectively. The formula adds the cost of 100 units for each underloaded kilogram from 2400.

As a result, the algorithm will aim to load all vehicles by at least 80% (if possible).

API request (JSON) API response View on map

Example 4

You need to plan a route, which includes some retail chains that open earlier. The task uses the following pricing plan:

  • The base cost of the route is made up of the time spent and the distance traveled.

  • Routes should be started earlier to avoid morning traffic. To encourage this, a penalty for departing after 8 AM is added to the cost calculation formula.

This pricing corresponds to the following cost: 100 * duration_h + 8 * distance_km + 50 * (start_route_time_s > 28800)

As a result of planning, all vehicles arrive at the depot before 8 AM.

API request (JSON) API response View on map

Calculation of the courier's payout

Calculating the payment the courier receives for completing the route. During planning, you can calculate payouts using one expression in the vehicle.payout field or use multiple expressions in nested fields:

  • payout.route: For a route.
  • payout.shift: For a shift.
  • payout.run: For a run.

In the expressions, you can use the same keywords and mathematical notation you use to calculate the cost of the route for the company (the vehicle.cost field).

Note.

The vehicle.payout field doesn't affect the route optimization, it's calculated after the planning task has been solved.

If the courier has the vehicle.payout field set, you'll see the following fields in the solution metrics:

  • run_payout: Payout for the run calculated using the payout.run formula.
  • shift_payout: Payout for the shift calculated using the payout.shift formula. Shown only for the first run of the shift.
  • shift_total_payout: Total payout for the shift. It includes the payout for the shift calculated using the formula plus the payout for all the shift's runs. Shown only for the first run of the shift.
  • route_payout: Payout for the route calculated using the payout.route formula. Shown only for the first run of the route.
  • total_payout: Full payout for the route, including the payout for the route calculated using the formula plus the payout for all the shifts. Shown only for the first run of the route, the other runs have it as 0.

If the payout field is set for at least one courier, the planning results also have the total_payout metric, which is the total amount to be paid to couriers.

Example 1

Two couriers are delivering 40 orders, each courier makes 2 runs. The couriers' cost for the company is set by the expression in the cost field. For courier 1, the payout for the completed route is calculated using the expression in the payout field: this amount is displayed in the metrics of the first run and is equal to 5000 units. For Courier 2, the payout is not calculated, so the total_payout amount is also equal to 5000 units.

API request (JSON) API response View on map

Example 2

Two couriers are delivering 40 orders. For Courier 1, the payout calculation is set as follows: starting the shift — 3000 units, each kilometer of the route — 10 units, each delivered order — 50 units. If they deliver more than 10 orders during the shift, they receive a bonus of 500 units. For Courier 2, the payout is not calculated.

As a result of planning, Courier 1 makes two runs and delivers 20 orders. For each run, run_payout is applied (1232 and 1053 units), as well as shift_total_payout for the shift (2785 units, including the shift_payout bonus of 500 units) and route_payout for the route (3000 units). In total, the courier gets total_payout of 5785 units.

Excel file API request (JSON) API response View on map

Vehicle tags

When you set up a vehicle or courier in a request to RouteQ, you can define the rules (or tags) for its compatibility with orders.

Compatibility rules may be required if a vehicle has special equipment that's necessary to fulfil a particular order, like an isothermal van for transporting food.

Vehicle and order compatibility rules (vehicle tags) are set in the following fields:

  • vehicle.tags: The vehicle properties that can partially match the properties required to fulfill the order.

  • vehicle.excluded_tags: The vehicle properties that must not match the properties required to fulfill the order.

To set the order tags, use the location.required_tags field in the request.

Attention.

The order tags identify the vehicle characteristics that an order requires, whereas vehicle tags define the actual rules for compatibility of a particular vehicle with different orders.

Vehicle tags can be set as strings or regular expressions. Tags can be separated by commas in strings. In this case, the vehicle can deliver the order if at least one of the listed vehicle tags matches the order tag or if the order has no tags. Regular expressions are used to describe the more complex logic and vehicle/order compatibility rules.

RouteQ uses POSIX Extended regular expression syntax. You can test your regular expressions at Regex101.

Let's look at some real-life cases of using tags.

Example 1

Let's take a use case when a transportation company delivers food and drinks in small bulk quantities. Some foodstuff must be delivered in isothermal trucks only. At the same time, all drinks and some foodstuff can be delivered without refrigerators. In addition, some customers can only accept a cargo if a vehicle is equipped with a tail lift.

To set these order restrictions, specify the following tags in the location.required_tags field:

  • TAIL_LIFT: For orders that can only be unloaded if a vehicle is equipped with a tail lift.

  • ISOTHERMAL_TRUCK: For orders containing goods that require temperature-controlled transportation.

  • NORMAL_TRUCK: For orders that do not require special conditions of transportation.

To set vehicle features, use the following tags in the vehicle.tags field:

  • TAIL_LIFT: For vehicles equipped with a tail lift.

  • ISOTHERMAL_TRUCK: For isothermal vehicles.

  • NORMAL_TRUCK: For regular vehicles without an isothermal van.

Note.

A vehicle may have one or more tags, or it may not have any at all, depending on its actual configuration. The same rule applies to order tags.

API request (JSON) API response View on map

Example 2

Let's take a use case when some orders have a restriction on the vehicle body height due to different height of unloading zones.

For example, there are orders with the restriction on body height of 2 meters, 2.3 meters, and 2.5 meters. Then they should have the appropriate tags: Max_200, Max_230, and Max_250.

For the vehicles, tags are set in a more complex way, since a vehicle up to 2 meters high can deliver any orders, whereas a vehicle up to 2.8 meters high can only deliver some orders. That is, if you only use tags, then at a vehicle's height:

  • Up to 2 meters, the vehicle.tags field will contain all Max_200, Max_230, and Max_250 values.

  • From 2 to 2.3 meters, the vehicle.tags field will contain the Max_230 and Max_250 values.

  • From 2 to 2.3 meters, the vehicle.tags field will contain the Max_250 value.

  • More than 2.5 meters, the vehicle.required_tags field will be empty.

API request (JSON) API response View on map

Example 3

Let's take a use case when some orders have a restriction on the arrival of vehicles with a certain load capacity (the OR condition applies when any of the corresponding vehicles is suitable).

For example, there are vehicles with different load capacity: 1, 3, 9, and 15 tons. Let's fix these characteristics using vehicle.tags tags. Since you'll have to combine these tags when describing orders, let's set them using regular expressions: .*1TON.*, .*3TON.*, .*9TON.* and .*15TON.* (.* means “any substring”).

The vehicle load capacity limit for some orders is from 1 to 15 tons, from 3 to 9 tons, and from 1 to 3 tons. This limit is set for the order by a string with a regular expression that includes tags of all suitable vehicles. That is, the location.required_tags field will contain the following regular expressions at the required load capacity:

  • From 1 to 15 tons: ##1TON##3TON##9TON##15TON##.
  • From 3 to 9 tons: ##3TON##9TON##.
  • From 1 to 3 tons: ##1TON##3TON##.
Note.

The order tags in example 2 are set by a simple list, because the vehicle must have all the listed tags (AND condition). You have to set at least one of the order tags (OR condition) for the vehicle in example 3. To do this, you can use regular expressions or create separate tags for each possible combination of OR conditions.

API request (JSON) API response View on map

Optional tags

When planning, you may sometimes need to consider which vehicles are best to use (or avoid) for certain orders. For example, it's better to give VIP orders to specially trained couriers.

For such requirements, there are optional tags. They're listed in the location.optional_tags field. If preferences can't be met, they may be violated (for example, because of weight restrictions or delivery time). That's the difference between optional tags and required vehicle characteristics.

Note.

If you'd prefer to have vehicles used in a certain zone, set optional geofences for them.

You can use the location.optional_tags.value tag weight to prioritize your preferences. Its value can be positive or negative. When planning, the optional tag is compared to the tags of the vehicle that is delivering the order. If the tag from location.optional_tags matches a vehicle tag from the following lists:

  • vehicle.tags: value is deducted from the route cost.

  • vehicle.excluded_tags: value is added to the route cost.

The value that optional tags add to the route cost is returned in the result.routes.metrics.total_optional_tags_cost field (it can be negative).

Example

You need to deliver 10 orders, some of them have the following optional tags:

  • vip: 6 orders. Its weight varies from 100 to 350 at different points.
  • morning: 3 orders. Its weight at all points is the same — 500.

One of the vehicles has vip and morning tags specified in the vehicle.excluded_tags field. This means that it's best not to give vip-tagged and morning-tagged orders to this courier due to the late start time of the route.

As a result, in most cases the requirements aren't violated: five out of six vip orders are delivered by the courier that doesn't have any limits on the vip tag. There are no violations related to the morning tag.

But one vip order is scheduled for a vehicle with the vip tag in excluded_tags due to capacity restrictions. In the total_optional_tags_cost field for this route, 100 is returned: using an “unsuitable” vehicle increased the cost by 100 units. The preference was violated for the order with the lowest location.optional_tags.value weight.

API request (JSON) API response View on map

Order incompatibility

Orders may have incompatible types, which you can set using the following parameters:

  • options.incompatible_load_types: Sets order incompatibility for all vehicles in the same way. To learn more, see the Order incompatibility section.

  • vehicle.incompatible_load_types: Sets order incompatibility for a specific vehicle by enabling you to take vehicle features into account.

  • vehicle.onboard_incompatible_load_types: When this is set to false (by default), order incompatibility remains in effect throughout the entire run, and when the value is true, then only while the orders are in the vehicle.
Note.

The vehicle.incompatible_load_types parameter has a higher priority and completely redefines the options.incompatible_load_types parameters for this vehicle.

For example, different temperature modes are required to transport milk and ice cream. If the vehicle has one compartment, it can transport either milk or ice cream. If the vehicle has two compartments with different temperature modes, it can transport milk and ice cream at the same time in different compartments. In this case, specify the order incompatibility vehicle.incompatible_load_types for vehicles with one compartment. Don't use this parameter for vehicles with two compartments and don't specify incompatible types options.incompatible_load_types for orders in general.

If orders are incompatible for reasons other than vehicle characteristics, set vehicle.onboard_incompatible_load_types = true. For example, if orders from competing companies shouldn't be transported at the same time, the courier will pick up and deliver each company's orders separately without stopping at a depot. This reduces mileage and time en route.

Example 1

The delivery consists of 4 addresses with the following order types:

  • Order 1 (id = 1): flowers.

  • Order 2 (id = 2): flowers.

  • Order 3 (id = 3): flowers, sweets.

  • Order 4 (id = 4): flowers, ice-cream.

Flowers and sweets are incompatible for delivery in the same vehicle. Moreover, simultaneous delivery of flowers and ice-cream in vehicle 2 is prohibited, but simultaneous delivery of flowers and sweets is permitted. Then the solution will contain delivery of orders 2 and 4 in the first vehicle and delivery of orders 1 and 3 in the second vehicle.

API request (JSON) API response View on map

Example 2.1

You need to have 3 orders from different companies picked up and delivered. Orders 1 and 2 and orders 2 and 3 cannot be delivered together, because they belong to competing companies.

As a result of planning, the courier picks up and delivers orders 1 and 3, then returns to the depot to load and deliver order 2 as part of a new run.

API request (JSON) API response View on map

Example 2.2

The same as in example 2.1, but vehicle.onboard_incompatible_load_types = true.

As a result of planning, the courier picks up and delivers order 2, and then picks up and delivers orders 1 and 3 without visiting the depot. This means less mileage and time en route.

API request (JSON) API response View on map

Geofences

You can set limits for vehicles by delivery zones. You can set zones that the vehicle can deliver orders to using the vehicles.allowed_zones parameter:

  • The vehicle can deliver orders in any zone specified in the allowed_zones parameter.

  • If you don't specify the availability zones, the vehicle can deliver orders without any limits.

  • The order can't be delivered if availability zones are specified for all vehicles, and the order location doesn't fall into any of them.

Set the zones forbidden for delivery using the vehicle.forbidden_zones parameter. The vehicle can't deliver orders to any of the zones specified in the forbidden_zones parameter.

Note.

If the order is located in the intersection of the permitted and forbidden zones, it can't be delivered: the forbidden_zones parameter has a higher priority than the allowed_zones parameter.

When orders are being assigned, geofence incompatibility is taken into account: both the global option and the values set for individual couriers. When planning routes, you can also cancel all limits related to geofences.

Example

This example shows 4 orders and 2 vehicles, 4 geofences are set in the interface. Coordinates automatically determine how orders pertain to geofences:

  • Order 1 — simultaneously in zone1 and zone2.

  • Order 2 — in zone1.

  • Order 3 — simultaneously in zone2 and zone3.

  • Order 4 — in zone4.

The availability of geofences for vehicles determined:

vehicle.allowed_zones vehicle.forbidden_zones
Vehicle 1 zone1, zone2 zone3
Vehicle 2 Zones not determined zone2
vehicle.allowed_zones vehicle.forbidden_zones
Vehicle 1 zone1, zone2 zone3
Vehicle 2 Zones not determined zone2

As a result, Vehicle 1 delivers Orders 1 and 2, Vehicle 2 delivers Order 4. And Order 3 remains unallocated, because its address is located in the zones forbidden for both vehicles.

API request (JSON) API response View on map

Optional geofences

When assigning orders to vehicles, you can make use of optional geofences, which have bonuses or penalties associated with visiting them. You can set one or more such geofences for each vehicle.

Optional geofences represent a soft restriction. They help designate zones that are preferred for delivery (high-priority and low-priority).

Optional geofences are set using the vehicle.optional_zones array:

  • optional_zones.N.zone: Name of the geofence.
  • optional_zones.N.value: If the value is greater than 0, the vehicle receives a bonus for visiting the specified geofence (the value of the parameter is deducted from the route cost), and if it's less than 0, a penalty (the value is added to the route cost).

Example 1

You need to deliver 10 orders with two vehicles. For the first vehicle, the South optional geofence is set, and for the second one, North. Visiting these geofences carries a bonus of 1000 units. As a result, the first vehicle delivers orders in the south, and the second one, in the north. Order 5 is an exception: it belongs to the South geofence, but was delivered by the Courier north vehicle.

Excel file API request (JSON) API response View on map

Example 2

4 couriers have to deliver 27 orders. The city is divided into 4 optional geofences: Northwest, Northeast, Southwest, and Southeast. Each courier has been set one high-priority zone that carries a bonus, two low-priority zones, and one zone that carries a penalty. As a result of planning, couriers end up delivering orders in their high-priority zones. The exceptions are orders 18, 20, and 23 due to vehicle capacity limitations.

Excel file API request (JSON) API response View on map

Incompatible geofences

You can set geofence incompatibility in order to prevent orders belonging to different delivery zones from ending up part of the same courier run.

Using the vehicles.incompatible_zones parameter, the list of such zones can be set both for the entire solution and for a specific courier. Incompatible zones defined for the courier take precedence over globally defined zones. In order for the global restriction options.incompatible_zones not to apply to the courier, set an empty list in the vehicles.incompatible_zones field.

Attention.

When planning in Excel, for the global zone incompatibility restriction not to apply to the courier, put a space in the incompatible_zones.N cells for them (it corresponds to an empty list).

Example

Each of the three couriers must deliver 4 orders to different parts of the city: northwest, southwest, northeast, and southeast. These areas correspond to the following geofences defined during planning: Northwest, Southwest, Northeast, Southeast.

Global geofence incompatibility has been set: southern zones (Southwest and Southeast) are incompatible with the northern ones (Northwest and Northeast). Additionally, two couriers have the vehicles.incompatible_zones parameter set for them: for the first courier, it contains an empty list, and for the second, it makes the western zones (Northwest and Southwest) incompatible with the eastern ones (Northeast and Southeast).

As a result of planning:

  • Courier 1 is unaffected by the global incompatibility, and all the 4 orders from different zones get included in their run.
  • Courier 2 is subject to the zone incompatibility restrictions set for them in the vehicles.incompatible_zones parameter: one run includes orders to the eastern zones, and the other, to the western ones.
  • Courier 3 is subject to the global restrictions: orders to the southern and northern zones get assigned to different runs.

API request (JSON) API response View on map

Transportation method

When building routes, it is assumed by default that a courier uses a passenger car for delivery (load capacity less than 2.5 tons). To specify delivery on foot, by truck, or by public transit, use the vehicle.routing_mode parameter. If all couriers have the same delivery method, you can use the routing option options.routing_mode.

Note.

The vehicle.routing_mode parameter has a higher priority than the options.routing_mode parameter.

Possible values:

  • driving: The default method, routing for vehicles whose load capacity is less than 2.5 tons.

  • truck: Routing for trucks whose default load capacity starts at 2.5 tons. You can specify additional parameters in vehicle characteristics.

  • walking: A pedestrian route. The route uses only roads that can be walked.

  • transit: A route that includes traveling by public transit and walking from the public transit stop to the delivery location.

Example 1

The example below uses the transit transportation method for all couriers. As a result, couriers deliver orders using public transit with optimal order allocation.

API request (JSON) API response View on map

Note.

For the built routes, the mileage is specified only for the distances that couriers walk. The distances traveled by public transit are taken into account for optimization purposes, but are not counted in metrics.

Example 2

The example below uses the transit transportation method for one courier and the driving method for another courier. Orders are distributed among couriers so that the vehicle delivers to locations situated further away from public transit stops or from each other.

API request (JSON) API response View on map

Courier working mode

By default, the service plans a route only with stops that are necessary for cargo delivery. However, couriers often can't work without stopping: they need to have lunch breaks, and you must take these into account when you build routes. Moreover, on long-distance runs, drivers are required to make stops at certain intervals to meet the work and rest requirements.

To control the couriers' working mode, use the vehicle.rest_schedule.breaks object. You can describe simple or complex patterns of rest and maintenance breaks and other activities.

Schedule templates

You can describe breaks separately for each courier or create templates for multiple couriers. Moreover, you can combine individual and template schedules.

To create a template, add the template_rest_schedules parameter to options and specify an array of schedules in it: [{"id": string, "breaks": [...]}].

To use the template, add the rest_schedule_id parameter to vehicles and specify id of the schedule template from options in it.

Break duration

You can set the break duration using the rest_duration_s parameter mandatory for every break.

Parameter Value Example
rest_duration_s Break duration in seconds.

"rest_duration_s": 600

The break should last 10 minutes (600 seconds).

Parameter Value Example
rest_duration_s Break duration in seconds.

"rest_duration_s": 600

The break should last 10 minutes (600 seconds).

Break start conditions

The break start is indicated by the time range (from and to). You can set the break start in several ways that are indicated in the table below.

Parameter Value Example
work_time_range_from_start

Working hours from the start of the route. Includes: travel time, waiting time, and handling time at order locations and at the depots.

The presence and duration of other breaks don't matter.

"work_time_range_from_start": "01:00:00-03:00:00"

Start the break no earlier than in 1 hour and no later than 3 hours after the start of the route.

work_time_range_till_rest Working hours from the last break (or from the start of the route if it's the first break). Includes: travel time, waiting time, and handling time at order locations and at the depots.

"work_time_range_till_rest": "02:00:00-04:00:00"

Start the break no earlier than 2 hours and no later than 4 hours after the shift start (including arrival at the depot, handling time, periods of travel and waiting).

travel_time_range Travel time and waiting time from the start of the route. Handling time is not taken into account.

"travel_time_range": "01:00:00-03:00:00"

Start the break no earlier than 1 hour and no later than 3 hours after the start of the route, taking into account periods and travel and waiting and without taking into account handling time at order locations and at the depots.

continuous_travel_time_range Travel time and waiting time from the completion of the previous order. Handling time is not taken into account.

"continuous_travel_time_range": "02:00:00-03:00:00"

Start the break no earlier than in 2 hours and not later than after 3 hours of continuous travel.

driving_time_range Travel time from the start of the route. Waiting time and handling time are not taken into account.

"driving_time_range": "01:00:00-03:00:00"

Start the break no earlier than 1 hour and no later than 3 hours from the start of the continuous travel.

exact_time_range

Break start time. The break can't be repeated.

The work start time, the presence and duration of other breaks don't matter.

The break won't start if the route ends before the break start time.

"exact_time_range": "17:00:00-20:00:00"

Start a break from 17:00 to 20:00.

Parameter Value Example
work_time_range_from_start

Working hours from the start of the route. Includes: travel time, waiting time, and handling time at order locations and at the depots.

The presence and duration of other breaks don't matter.

"work_time_range_from_start": "01:00:00-03:00:00"

Start the break no earlier than in 1 hour and no later than 3 hours after the start of the route.

work_time_range_till_rest Working hours from the last break (or from the start of the route if it's the first break). Includes: travel time, waiting time, and handling time at order locations and at the depots.

"work_time_range_till_rest": "02:00:00-04:00:00"

Start the break no earlier than 2 hours and no later than 4 hours after the shift start (including arrival at the depot, handling time, periods of travel and waiting).

travel_time_range Travel time and waiting time from the start of the route. Handling time is not taken into account.

"travel_time_range": "01:00:00-03:00:00"

Start the break no earlier than 1 hour and no later than 3 hours after the start of the route, taking into account periods and travel and waiting and without taking into account handling time at order locations and at the depots.

continuous_travel_time_range Travel time and waiting time from the completion of the previous order. Handling time is not taken into account.

"continuous_travel_time_range": "02:00:00-03:00:00"

Start the break no earlier than in 2 hours and not later than after 3 hours of continuous travel.

driving_time_range Travel time from the start of the route. Waiting time and handling time are not taken into account.

"driving_time_range": "01:00:00-03:00:00"

Start the break no earlier than 1 hour and no later than 3 hours from the start of the continuous travel.

exact_time_range

Break start time. The break can't be repeated.

The work start time, the presence and duration of other breaks don't matter.

The break won't start if the route ends before the break start time.

"exact_time_range": "17:00:00-20:00:00"

Start a break from 17:00 to 20:00.

If there are multiple breaks, each range specifies the working range after the end of the previous break. For example, if the first break is 04:00–05:00 and the second break is 02:00–03:00, the first break must start between 4 and 5 hours after work starts, and the second break must start between 2 and 3 hours after the end of the first break.

Break planning conditions

You can specify additional parameters: make a break mandatory or set the minimum working time for the break start.

Parameter Value Example
necessary_route_duration_s The time from the start of the route after which a break must be made. Set in seconds.

"necessary_route_duration_s": 14400

Be sure to start the break after 4 hours (14,400 seconds) have passed from the route start.

route_duration_s The parameter sets the minimum working time at which a break should be scheduled. If the total working time is less, a break isn't scheduled. Set in seconds.

"route_duration_s": 14400

Start the break only if the route lasts at least 4 hours (14,400 seconds).

Parameter Value Example
necessary_route_duration_s The time from the start of the route after which a break must be made. Set in seconds.

"necessary_route_duration_s": 14400

Be sure to start the break after 4 hours (14,400 seconds) have passed from the route start.

route_duration_s The parameter sets the minimum working time at which a break should be scheduled. If the total working time is less, a break isn't scheduled. Set in seconds.

"route_duration_s": 14400

Start the break only if the route lasts at least 4 hours (14,400 seconds).

Combining breaks conditions

Parameter Value Example
before_first_location The possibility of combining a break with other breaks before the first order. The break can only be combined with the breaks whose types are specified in merge_with_types.

"before_first_location": true

The break will be combined with the last break before the first location where the break type is specified in merge_with_types. If there is no such break, this break will be made right before the first location. All such breaks must be in a separate chain.

after_last_location The possibility of combining a break with other breaks after the last order. The break can only be combined with the breaks whose types are specified in merge_with_types.

"after_last_location": true

The break will be combined with the first break after the last location where the break type is specified in merge_with_types. If there is no such break, this break will be made right after the last location. All such breaks must be in a separate chain.

type Break type.

"type": "Lunch"

A “lunch” break.

merge_with_types The parameter sets which break types can be combined with the specified break. You can only use it in combination with after_last_location or before_first_location.

"merge_with_types": ["Lunch", "Sleep"]

You can combine this break with a lunch or a sleep break.

Parameter Value Example
before_first_location The possibility of combining a break with other breaks before the first order. The break can only be combined with the breaks whose types are specified in merge_with_types.

"before_first_location": true

The break will be combined with the last break before the first location where the break type is specified in merge_with_types. If there is no such break, this break will be made right before the first location. All such breaks must be in a separate chain.

after_last_location The possibility of combining a break with other breaks after the last order. The break can only be combined with the breaks whose types are specified in merge_with_types.

"after_last_location": true

The break will be combined with the first break after the last location where the break type is specified in merge_with_types. If there is no such break, this break will be made right after the last location. All such breaks must be in a separate chain.

type Break type.

"type": "Lunch"

A “lunch” break.

merge_with_types The parameter sets which break types can be combined with the specified break. You can only use it in combination with after_last_location or before_first_location.

"merge_with_types": ["Lunch", "Sleep"]

You can combine this break with a lunch or a sleep break.

Break place

Parameter Value Example
at_rest_place An option to have some rest in a location with the rest_place type. If this option is enabled, either all breaks must be in such locations, or all breaks must be outside such locations.

"at_rest_place": true

All breaks will take place in locations with the location.type type equal to rest_place.

Parameter Value Example
at_rest_place An option to have some rest in a location with the rest_place type. If this option is enabled, either all breaks must be in such locations, or all breaks must be outside such locations.

"at_rest_place": true

All breaks will take place in locations with the location.type type equal to rest_place.

Note.

For orders with the rest_place type, you can specify compatibility with vehicles or orders of other types using geofences or the load_types parameter.

Break chains

The rest_schedule can contain many independent breaks break chains. Each chain can contain many breaks with special conditions. The start of a break in every chain depends only on the built route. It doesn't depend on breaks in other chains.

Example Explanation How to set

Chain 1: Rest for 15 minutes after every 3 hours of transit.

Chain 2: Rest for 6 hours 8 hours after the shift started.

Breaks in chain 2 depend only on the shift start. They don't depend on the transit and rest schedule in chain 1.

Chain 1: Rest for 15 minutes after every 3 hours of transit.

Chain 2: Rest for 6 hours after every 8 hours of transit.

The start of the break in chain 2 depends on the transit and rest schedule in chain 1.
Example Explanation How to set

Chain 1: Rest for 15 minutes after every 3 hours of transit.

Chain 2: Rest for 6 hours 8 hours after the shift started.

Breaks in chain 2 depend only on the shift start. They don't depend on the transit and rest schedule in chain 1.

Chain 1: Rest for 15 minutes after every 3 hours of transit.

Chain 2: Rest for 6 hours after every 8 hours of transit.

The start of the break in chain 2 depends on the transit and rest schedule in chain 1.

The order of chains doesn't matter, but you must specify breaks in one chain sequentially.

If the route is completed before the stop (for example, the route is completed in 3 hours, and the stop is scheduled after 4 hours), all the unmade stops are reset.

Example

The route is built with 30-minute rest breaks after 4–4.5 hours of work. 15 hours after the start of the route, a sleep break is planned. As a result, a sleep break is scheduled 1.5 hours after a rest break.

API request (JSON) API response View on map

Penalties

In some cases, RouteQ can plan routes that violate the rest window. To apply penalties for such violations, use the fields penalty.late and penalty.early. If the penalty is higher than the savings resulting from the window violation, the route is planned without violations.

Parameter Value Example
penalty.early.fixed Penalty for an early break start.

"penalty": {"early": {"fixed": 1000}}

Sets a penalty of 1000 for an early break.

penalty.early.minute Penalty for every minute of an early break.

"penalty": {"early": {"minute": 17}}

Sets a penalty of 17 for every minute of an early break.

penalty.late.fixed Penalty for a late break.

"penalty": {"late": {"fixed": 1000}}

Sets a penalty of 1000 for a late break.

penalty.late.minute Penalty for every minute of a late break.

"penalty": {"late": {"minute": 17}}

Sets a penalty of 17 for every minute of a late break.

Parameter Value Example
penalty.early.fixed Penalty for an early break start.

"penalty": {"early": {"fixed": 1000}}

Sets a penalty of 1000 for an early break.

penalty.early.minute Penalty for every minute of an early break.

"penalty": {"early": {"minute": 17}}

Sets a penalty of 17 for every minute of an early break.

penalty.late.fixed Penalty for a late break.

"penalty": {"late": {"fixed": 1000}}

Sets a penalty of 1000 for a late break.

penalty.late.minute Penalty for every minute of a late break.

"penalty": {"late": {"minute": 17}}

Sets a penalty of 17 for every minute of a late break.

Repeat conditions

Parameter Value Example
repeatable The parameter specifies that the break must be repeated. It can only be used for the last break in the chain.

"repeatable": true

The break will be repeated before the shift end.

Parameter Value Example
repeatable The parameter specifies that the break must be repeated. It can only be used for the last break in the chain.

"repeatable": true

The break will be repeated before the shift end.

Example 1

We built a route with a lunch break after 4–5 hours of work in this example. As a result, the algorithm schedules a lunch stop for a courier.

API request (JSON) API response View on map

Example 2

In this example, a route is built between Moscow and St. Petersburg with the first break after 4-4.5 hours, and then with breaks every 2 hours. The algorithm scheduled two breaks.

API request (JSON) API response View on map

Example 3

For two couriers a break is set with the work_time_range_from_start condition in 3–4 hours after the start of work, but only if the total duration route_duration_s is at least 6 hours. The first courier finishes work in 5 hours, so they work without rest. The second courier works for more than 6 hours, so they get one break.

API request (JSON) API response View on map

Example 4

The courier delivers orders to a neighboring city and periodic breaks. Breaks are set every 60–80 minutes of the route (travel_time_range) using the repeat condition repeatable. As a result, the algorithm scheduled two breaks.

API request (JSON) API response View on map

Example 5

As in example 4, but the route lasts several days, and breaks are set for sleep every 12 hours:

  • The repeat condition repeatable is used.

  • The minimum and maximum route duration before rest travel_time_range: "12:00–12:00".

API request (JSON) API response View on map

Example 6

10-minute breaks are set for every 55–60 minutes of continuous traveling continuous_travel_time_range. As a result, a break is scheduled only between points where the travel time is more than 55 minutes.

API request (JSON) API response View on map

Example 7

For couriers, two breaks with the break start condition work_time_range_till_rest are scheduled for 2–3 hours after the last break or start of work if this is the first break.

  • The first break is 20 minutes.

  • The second break is 30 minutes.

The first courier finishes work earlier and gets only the first break. The second courier works longer and gets both breaks.

API request (JSON) API response View on map

Planned route

The user can specify which vehicle should deliver particular orders. This is useful:

  • For additional planning when you have pre-planned routes.

  • When the order requires a specific vehicle.

To specify pre-planned orders for the vehicle, use the vehicle.planned_route option. This option has the following properties:

  • When planning, all orders that you specify in vehicle.planned_route can't be unallocated, even if strict restrictions are violated, such as vehicle capacity or time windows for which hard_window = true.

  • By default, the order sequence set in planned_route isn't fixed. When re-planning, orders can be arranged in a new sequence.

  • If you need to save the route that's specified in planned_route without saving changes (sequence changes and adding new orders), use vehicle.fixed_planned_route = true.

For each order in planned_route, be sure to specify the vehicle shift (even if the vehicle only has 1 shift).

If in planned_route several shifts are specified, you can lock orders for shifts using the fix_planned_shifts = true option. By default, the value is false.

If a courier arrives too early, delivery time of the order is determined by the vehicle.wait_if_early parameter:

  • true: The courier waits for the order time window to start (default value).
  • false: The courier handles the order as soon as they arrive.
Attention.

If there is a hard time window for an order location.hard_window = true, the vehicle.wait_if_early parameter value is true.

In the planned_route field, you can specify depots for reloading, which a courier needs to visit when traveling along the route.

Example 1

Both couriers had pre-planned orders in planned_route. As a result, these orders were given to these two couriers.

API request (JSON) API response View on map

Example 2

This example involves 1 vehicle that has orders linked to it via planned_route. The total weight of the orders exceeds the vehicle capacity, but the route is still being planned (because orders specified in this option can't be unallocated). But the ask status is UNFEASIBLE.

API request (JSON) API response View on map

Example 3

Theoretically, 2 couriers could deliver all 20 orders without overload and without being late. But a fixed sequence is specified for courier 1 using the vehicle.fixed_planned_route = true parameter, so they'll only deliver orders from this sequence. Courier 2 isn't limited by a strict plan, so they'll take as many orders as they can carry. Several orders will remain in the depot, despite the fact that courier 1 has the space and time.

API request (JSON) API response View on map

Example 4.1

2 couriers need to deliver 15 orders in 2 shifts. Using the planned_route option, orders 1-8 are assigned to courier 1, and orders 9-15 to courier 2. At the same time, it's indicated that orders 1-4 and 9-12 must be delivered during the first shift, and orders 5-8 and 13-15 during the second shift. Since fix_planned_shifts = false and couriers manage to deliver all orders within one shift, the distribution of orders by shifts is not taken into account.

API request (JSON) API response View on map

Example 4.2

The conditions are the same as in example 4.1, but the option fix_planned_shifts = true. This means the shifts during which orders have to be delivered are taken into account.

API request (JSON) API response View on map

The order is already in the vehicle

If the order is already in the vehicle, the courier can immediately start delivery. To run this scenario, specify the parameters in the planned_route field:

Parameter Description Value
location.loaded_orders* List of order ids with the delivery type, which are uploaded to locations. If the parameter isn't specified, you can pick up any orders at the location.

You can bring any orders with the pickup type to the location regardless of the loaded_orders value.

id
location.delivery_in_current_run* All orders loaded at the locations must be serviced during the same run before the vehicle returns to the depot. true / false
planned_runs_first

The vehicle will visit all depots in planned_route before making unplanned runs.

Use if:

  • Scheduled orders at depots have already been prepared for loading since last night, and it's more convenient to pick them up earlier.
  • You apply the delivery_in_current_run parameter to first deliver orders from planned_route.
true / false
Parameter Description Value
location.loaded_orders* List of order ids with the delivery type, which are uploaded to locations. If the parameter isn't specified, you can pick up any orders at the location.

You can bring any orders with the pickup type to the location regardless of the loaded_orders value.

id
location.delivery_in_current_run* All orders loaded at the locations must be serviced during the same run before the vehicle returns to the depot. true / false
planned_runs_first

The vehicle will visit all depots in planned_route before making unplanned runs.

Use if:

  • Scheduled orders at depots have already been prepared for loading since last night, and it's more convenient to pick them up earlier.
  • You apply the delivery_in_current_run parameter to first deliver orders from planned_route.
true / false

* Specified for depots and orders of the garage type.

Example

Several orders were loaded in the courier's vehicle last night. The courier doesn't have to pick them up at the depot. Therefore, the point of the garage type is specified in the place where the courier will go.

The loaded_orders parameter shows that orders 1 and 2 have been loaded. The courier can immediately deliver them to the destination.

The following parameters are also set in the conditions:

  • planned_runs_first = true.

  • delivery_in_current_run = true for depot and garage.

The courier starts from the garage and immediately delivers orders 1 and 2. They then go to the depot to pick up orders 3 and 4, which they must deliver immediately after loading. After these two deliveries, the courier returns to the depot to pick up orders 5 and 6 and follows the route further.

API request (JSON) API response View on map

Fixed part of the route

The visited_locations feature is useful if:

  • The beginning of route must follow a particular path.

  • You need to change the start point when doing additional planning.

The route must be fixed for each courier individually.

To do this, specify the visited_locations array in vehicles and describe the points of the fixed route using the following parameters.

Parameter Description
id* Order ID from locations or depot ID from depots. Please note that the order and depot IDs must be different.
shift_id ID of the courier shift from vehicle.shifts. Determines the shift in which to serve this point.
time
The time of departure from the point. If the first point of a fixed part of the route:
  • Has a specified time, that's the starting point.
  • Has no specified time, the route starts from the depot, and the start of work is calculated according to the depot or shift window.

You can specify this parameter for several orders, so that the visit time is calculated according to the time specified in time.

wait_if_early
The need to wait for the start of the time window in case of early arrival.
  • Its default value istrue, meaning that the courier will wait for the start of the time window.
  • If you specify false, the courier will start service immediately after arrival.
Parameter Description
id* Order ID from locations or depot ID from depots. Please note that the order and depot IDs must be different.
shift_id ID of the courier shift from vehicle.shifts. Determines the shift in which to serve this point.
time
The time of departure from the point. If the first point of a fixed part of the route:
  • Has a specified time, that's the starting point.
  • Has no specified time, the route starts from the depot, and the start of work is calculated according to the depot or shift window.

You can specify this parameter for several orders, so that the visit time is calculated according to the time specified in time.

wait_if_early
The need to wait for the start of the time window in case of early arrival.
  • Its default value istrue, meaning that the courier will wait for the start of the time window.
  • If you specify false, the courier will start service immediately after arrival.

* Required parameter

Example 1

There are 5 orders in this example. The sequence of orders 1, 2, 3 is fixed in visited_locations. Orders 4 and 5 can be delivered in any sequence.

API request (JSON) API response View on map

Example 2

In visited_locations, it's specified that the route must start with order 2 at 10:00.

API request (JSON) API response View on map

Example 3

The order sequence 1, 2, 3 is set as in example 1. It's also specified that departure from order 1 must be at 08:20 and from order 3 at 11:00.

API request (JSON) API response View on map

Example 4

There are 8 orders in this example. The specified sequence is orders 1, 2, 3, then the depot, then order 4. The courier may deliver the remaining orders in any sequence.

API request (JSON) API response View on map

Adjusting the vehicle's moving time

To calculate the speed of the vehicle when building a route, RouteQ uses Yandex Maps data about traffic and the speed specified in the request. Although the trucks usually move slower in traffic jams, some drivers drive more aggressively and arrive earlier than the calculated timeframes.

To compensate for such deviations, RouteQ has the travel_time_multiplier option where you can specify a fractional value. If the value is 1, the calculation is made for the vehicle with the expected average speed. At smaller values (for example, 0.8), the calculation accounts for faster vehicles. At higher values (for example, 1.2), the calculation accounts for slower vehicles.

Note.

The travel_time_multiplier parameter only affects the vehicle speed. The handover time at the delivery point remains the same.

Example 1

In the example below, the routing request is sent without adjusting the transit time. As a result, the vehicle delivers the order in 4 hours and 20 minutes, with 3 hours and 40 minutes spent moving between the points.

API request (JSON) API response View on map

Example 2

The same as in example 1, but with the travel_time_multiplier parameter set to 0.5. In the resulting route, the courier delivers the order in 2 hours and 25 minutes, spending 1 hour and 45 minutes moving between the points. However, time spent on parking and handover remains unchanged.

API request (JSON) API response View on map

Example 3

The same as in example 1, but with the travel_time_multiplier parameter set to 2. In the resulting route, the courier delivers the order in 7 hours and 58 minutes, spending 7 hours and 18 minutes moving between the points. Traveling the route takes more than twice as long as in example 1, because part of the route occurs at peak hours, and the vehicle can't drive at the maximum speed. Time spent on parking and handover remains unchanged.

API request (JSON) API response View on map

Adjusting handling time

To the courier needs some time to hand over the order on arrival. This time includes parking, riding the elevator, handing over the delivery, and paperwork. RouteQ ensures that by using the order's service_duration and shared_service_duration fields. However, some couriers deliver goods faster than others. For example:

  • In the case of parallel planning for vehicles and couriers using public transport, couriers who travel by public transport don't have to spend time parking. As a result, they need lower handling time.

  • Some couriers are faster than others. Experienced couriers usually spend less time handing over orders.

To compensate for the difference in courier time, RouteQ has the service_duration_multiplier and shared_service_duration_multiplier options that affect the handling time for a specific courier. If the value is 1, the handling time is the same as in service_duration or shared_service_duration. If the value is less than 1, the handling time is lower. If the value is greater than 1, the handling time is higher.

Note.

The service_duration_multiplier and shared_service_duration_multiplier parameters only affect the handling time. The transit time between the points remains the same.

Example 1

In the example below, the routing request is sent without adjusting the handling time.

API request (JSON) API response View on map

Example 2

In the example below, the same request is sent to RouteQ as in example 1, but with the service_duration_multiplier parameter set to 0.5. The calculated service order is half the time specified in example 1.

API request (JSON) API response View on map

Example 3

In the example below, the same request is sent to RouteQ as in example 1, but with the service_duration_multiplier parameter set to 2. Handling time is twice as long as in example 1.

API request (JSON) API response View on map

Prompt delivery

To build an optimal route, the algorithm minimizes the wait time between route points. But there are cases when it's useful to shift delivery to an earlier time. For example:

  • You have to minimize the risk of late arrival.
  • It's more comfortable for the courier to travel in the daytime.

To deliver goods as early as possible, use the penalty.arrival_after_start penalty, which consists of two parameters:

  • average_h: Sets the penalty amount for the average arrival time after the start of the time window. When using the option, we always recommend specifying this value.
  • as_soon_as_possible: Determines whether to start the route as early as possible. The parameter takes the value true or false (by default). It is specified in addition to average_h.
Note.

The algorithm can shift the start and arrival time of a vehicle only if the flexible start time is enabled for the depot.

If you don't use the penalty.arrival_after_start penalty, the route will be built with the minimal wait time between points and the latest possible start time from the depot.

When using the penalty, the algorithm will build routes to start them earlier, provided it doesn't reduce quality.

If the route must start as early as possible (even if it causes additional waiting), specify penalty.arrival_after_start.as_soon_as_possible = true.

Example 1

The route includes 4 orders with different time windows. The earliest start of the time window for order 5 is 08:00. The courier starts from the depot at 11:02 and arrives at the first delivery point at 11:40. Order 5 is delivered at 12:59.

API request (JSON) API response View on map

Example 2

The same data is used as in example 1, but the penalty is set for the average arrival time after the start of the time window using the penalty.arrival_after_start.average_h parameter. The courier starts from the depot at 06:59, waits for 8 minutes, and then delivers the earliest order (order 5) at 08:00.

API request (JSON) API response View on map

Example 3

The same data is used as in example 2, but the penalty.arrival_after_start.as_soon_as_possible = true parameter is additionally set. The courier starts from the depot at 06:00, waits for 1 hour and 7 minutes, and delivers the earliest order (order 5) at 08:00.

API request (JSON) API response View on map

Trailers

A trailer is a truck (tractor) with a trailer attached. You can place orders in the tractor and in the trailer, while one order can be loaded partially into the tractor and into the trailer.

To describe the trailer, use the trailer object.

Field Description
trailer.сapacity
The trailer carrying capacity is described by the fields:
  • weight_kg: Capacity in kilograms.
  • units: Capacity in units.

It's added to the tractor capacity.

trailer.capacity.custom

Amount of custom units a trailer can carry.

Carrying capacity in custom units is set in "name": size format, where:
  • name: The custom unit name (set instead of the additionalProperties field).
  • size: The vehicle carrying capacity in appropriate units, expressed as a non-negative real number.

If the unit name is present in deliveries or other vehicles, but not in this one, the capacity is assumed to be unlimited.

trailer.capacity.limits
The trailer loading limit is described by the fields:
  • units_perc: In custom units, expressed as a percentage of the trailer capacity.
  • volume_perc: As a percentage of the trailer volume.
  • weight_perc: As a percentage of the maximum permissible total weight the trailer can carry.
trailer.capacity.volume
The trailer dimensions are described by the fields:
  • depth_m*: Depth.
  • height_m*: Height.
  • width_m*: Width.

The values are expressed in meters.

* Required parameter

trailer.max_capacity_difference
The maximum difference in the load of a trailer and a tractor is described by the fields:
  • units: How many more units of goods can there be in a trailer than in a tractor.
  • volume_cbm: How many more cubic meters can the load of a trailer be than the load of a tractor.
  • weight_kg: How many more kilograms can the load of a trailer be than the load of a tractor.

If one of the fields is omitted, there are no restrictions on it.

There are physical restrictions on the difference in the load of a trailer and a tractor. If the tractor is empty, and the trailer is heavy, the vehicle becomes uncontrollable and the trailer can't go.

trailer.max_capacity_difference.custom

The maximum permissible difference in the loaded number of custom units for a trailer and a tractor.

The permissible difference in custom units is set in "name": size format where:
  • name: The custom unit name (set instead of the additionalProperties field).
  • size: The vehicle capacity in appropriate units, expressed as a non-negative real number.

If the unit name is present in deliveries or other vehicles, but not in this one, there is no restriction.

trailer.cost
The trailer cost is described by the fields:
  • fixed: The fixed cost-of-use for the trailer.
  • hour: The cost-of-use for the trailer per hour.
  • km: The cost per kilometer (added only for the route sections where a tractor is traveling with a trailer).
  • location: The cost-of-use for the trailer per destination.
  • run: The cost per run from the depot to the destination.
  • tonne_km: The cost of transporting one ton per kilometer.

It's added to the tractor cost if the trailer is used.

trailer.decoupling_time_s

Time to decouple the trailer in seconds.

Only for orders with the anchor and parking types (see Using a trailer).

trailer.coupling_time_s

Time to couple the trailer in seconds.

Only for orders with the anchor and parking types (see Using a trailer).

trailer.rolling_cost

Penalty for each rolling* of cargoes from a trailer to a tractor.

* Rolling means moving orders from a trailer to a tractor (to deliver them to non-accessible locations. See Using a trailer).

trailer.rolling_time
The time to roll cargo from a trailer to a tractor is set in seconds. It can be described by the following fields:
  • fixed_time_s: Fixed time.
  • s_per_kg: Unloading time per kilogram of cargo.
  • s_per_m3: Unloading time per cubic meter of cargo.
  • s_per_unit: Unloading time per unit of cargo.

If multiple time types are specified, use the one that spends the most time. If no type is specified, use only the fixed time.

coupling_time_s and decoupling_time_s are added to the rolling time, because you need to first couple the trailer and then decouple it for rolling.

Field Description
trailer.сapacity
The trailer carrying capacity is described by the fields:
  • weight_kg: Capacity in kilograms.
  • units: Capacity in units.

It's added to the tractor capacity.

trailer.capacity.custom

Amount of custom units a trailer can carry.

Carrying capacity in custom units is set in "name": size format, where:
  • name: The custom unit name (set instead of the additionalProperties field).
  • size: The vehicle carrying capacity in appropriate units, expressed as a non-negative real number.

If the unit name is present in deliveries or other vehicles, but not in this one, the capacity is assumed to be unlimited.

trailer.capacity.limits
The trailer loading limit is described by the fields:
  • units_perc: In custom units, expressed as a percentage of the trailer capacity.
  • volume_perc: As a percentage of the trailer volume.
  • weight_perc: As a percentage of the maximum permissible total weight the trailer can carry.
trailer.capacity.volume
The trailer dimensions are described by the fields:
  • depth_m*: Depth.
  • height_m*: Height.
  • width_m*: Width.

The values are expressed in meters.

* Required parameter

trailer.max_capacity_difference
The maximum difference in the load of a trailer and a tractor is described by the fields:
  • units: How many more units of goods can there be in a trailer than in a tractor.
  • volume_cbm: How many more cubic meters can the load of a trailer be than the load of a tractor.
  • weight_kg: How many more kilograms can the load of a trailer be than the load of a tractor.

If one of the fields is omitted, there are no restrictions on it.

There are physical restrictions on the difference in the load of a trailer and a tractor. If the tractor is empty, and the trailer is heavy, the vehicle becomes uncontrollable and the trailer can't go.

trailer.max_capacity_difference.custom

The maximum permissible difference in the loaded number of custom units for a trailer and a tractor.

The permissible difference in custom units is set in "name": size format where:
  • name: The custom unit name (set instead of the additionalProperties field).
  • size: The vehicle capacity in appropriate units, expressed as a non-negative real number.

If the unit name is present in deliveries or other vehicles, but not in this one, there is no restriction.

trailer.cost
The trailer cost is described by the fields:
  • fixed: The fixed cost-of-use for the trailer.
  • hour: The cost-of-use for the trailer per hour.
  • km: The cost per kilometer (added only for the route sections where a tractor is traveling with a trailer).
  • location: The cost-of-use for the trailer per destination.
  • run: The cost per run from the depot to the destination.
  • tonne_km: The cost of transporting one ton per kilometer.

It's added to the tractor cost if the trailer is used.

trailer.decoupling_time_s

Time to decouple the trailer in seconds.

Only for orders with the anchor and parking types (see Using a trailer).

trailer.coupling_time_s

Time to couple the trailer in seconds.

Only for orders with the anchor and parking types (see Using a trailer).

trailer.rolling_cost

Penalty for each rolling* of cargoes from a trailer to a tractor.

* Rolling means moving orders from a trailer to a tractor (to deliver them to non-accessible locations. See Using a trailer).

trailer.rolling_time
The time to roll cargo from a trailer to a tractor is set in seconds. It can be described by the following fields:
  • fixed_time_s: Fixed time.
  • s_per_kg: Unloading time per kilogram of cargo.
  • s_per_m3: Unloading time per cubic meter of cargo.
  • s_per_unit: Unloading time per unit of cargo.

If multiple time types are specified, use the one that spends the most time. If no type is specified, use only the fixed time.

coupling_time_s and decoupling_time_s are added to the rolling time, because you need to first couple the trailer and then decouple it for rolling.

Sample trailer description in a request:

{
    "trailer": {
        "capacity": {
            "weight_kg": 10000,
            "units": 200
        },
        "max_capacity_difference": {
            "units": 10,
            "weight_kg": 0
        },
        "cost": {
            "fixed": 1000,
            "km": 10
        },
        "decoupling_time_s": 300,
        "coupling_time_s": 300,
        "rolling_time": {
            "fixed_time_s": 3000
        }
    }
}
Copied to clipboard

For more information about using a tractor with a trailer, see Using a trailer.

Minimum order weight for a vehicle

To prevent a heavy truck from carrying a single small order across town, use the min_stop_weight parameter. Using this parameter, you can specify the minimum total weight that a vehicle will deliver to a single location. This is relevant when planning freight transportation by vehicles of different capacity.

The restriction is soft: the algorithm may violate it. Penalties are set in the fields:

  • penalty.min_stop_weight.fixed: A penalty for violating the minimum total weight for all orders in a single location (1000 by default).

  • penalty.min_stop_weight.kg: A penalty for each kilogram that the total order weight delivered to a single location (50 by default) is short.

For more information about using vehicles with different capacity, see Transport with different load capacities.

Example 1

Two vehicles with capacities of 1500 and 10,000 kg are delivering orders weighing 100, 500, 900, and 9000 kg. The large truck gets both light and heavy orders.

API request (JSON) API response View on map

Example 2

For a vehicle with a capacity of 10,000 kg, the specified value of min_stop_weight is 1000. As a result, the larger vehicle only gets the order weighing 9000 kg.

API request (JSON) API response View on map

Contact support