Skip to main content

Booking Penalty

A Booking Penalty (also known as an "order penalty") is an artificial cost, set as an integer, that you assign to a specific order. This penalty is applied only if the optimization engine chooses not to fulfill that order, leading to a "no offer" status.

This feature enables the optimizer to intelligently weigh the benefits of fulfilling an order against its associated costs.

Purpose

In a typical Vehicle Routing Problem (VRP), the aim is to fulfill every order. However, in real-world logistics, it's often impossible or too costly to service every single order. For example, an order might be too distant, all vehicles might be full, or delivery time windows could be too narrow.

Rather than treating "service all orders" as a strict, unyielding rule (which might cause the optimization process to fail), the booking penalty turns it into a flexible constraint. You are essentially communicating to the optimizer:

"Do your best to include this order. If the routing cost to include it exceeds its penalty value, you are allowed to leave it unassigned and 'pay' the penalty instead."

How It Works: The Cost Trade-Off

The main objective of the optimization engine is to discover the solution with the absolute lowest total cost. This total cost combines routing expenses (like fuel, time, and vehicle usage) with any penalties that are applied.

When assessing an order that has an assigned penalty, the optimizer conducts a straightforward comparison:

  • Cost to Service: What is the extra routing cost required to include this order? (e.g., 500 units for additional time and fuel)
  • Cost to Skip: What is the value of the booking penalty? (e.g., 1000 units)

The optimizer then selects the less expensive option:

  • Scenario 1: Order is Serviced If the Cost to Service (500 units) is lower than the Cost to Skip (1000 units), the optimizer will fulfill the order. The 500 units of routing cost are then added to the solution's total cost.
  • Scenario 2: Order is Not Serviced ("No Offer") If the Cost to Service is exceptionally high (e.g., 1500 units, perhaps due to needing an entirely new vehicle) and this cost exceeds the Cost to Skip (1000 units), the optimizer will not fulfill the order. The 1000-unit penalty is then added to the solution's total cost.

This outcome is beneficial for the optimizer, as paying a 1000-unit penalty is more economical than incurring a 1500-unit routing cost.

tip

Use this setting to control the tradeoff between the cost of delivery and cost of NOT delivering. The exact value depends on the problem being solved.

Key Principle

A higher penalty value makes it more probable that an order will be serviced.

  • A low penalty indicates to the optimizer, "You may skip this order if it causes even minor inconvenience."
  • An extremely high penalty signals to the optimizer, "You must fulfill this order regardless of the cost, even if it requires adding a new vehicle or creating a highly inefficient route."

Implementation in API

The booking_penalty parameter is configurable for each node for Stateless API or in the simulation settings for Integration API that will apply the default value to all orders unless explicitly set at the order level.

Example Configuration

Here is a JSON snippet for a node_scheduler request. In this example, three dropoff nodes are defined with varying penalties:

  • A high penalty (1,000,000) for a VIP delivery that must be completed.
  • A low penalty (100) for a distant, low-priority order that can be skipped if it's inefficient.
  • A medium penalty (5,000) for a standard delivery.

The optimizer will likely drop the low-penalty order if servicing it significantly increases the total travel time and cost.

{
"current_time": "2024-07-10T08:00:00+00:00",
"engine_settings": {
"calculation_parameters": {
"calculations_mode": "sync",
"scheduling_mode": "prebook_cvrptw"
},
"model_parameters": {
"optimize_quantity": "total_time"
},
"routing_engine": {
"routing_engine_name": "osrme",
"url": "http://mapbox-osrm-proxy",
"road_network": "van"
}
},
"nodes": [
{
"uid": "dropoff_high_penalty",
"booking_uid": "booking_1",
"node_type": "dropoff",
"lat": 1.280097,
"lon": 103.889129,
"open_time_ts": "2026-01-01T09:00:00+00:00",
"close_time_ts": "2026-01-01T12:00:00+00:00",
"service_time": 300,
"demand": { "units": 10 },
"penalty": 1000000,
"location_name": "VIP Dropoff - Marina Bay"
},
{
"uid": "dropoff_low_penalty",
"booking_uid": "booking_2",
"node_type": "dropoff",
"lat": 1.4495,
"lon": 103.8015,
"open_time_ts": "2026-01-01T09:00:00+00:00",
"close_time_ts": "2026-01-01T12:00:00+00:00",
"service_time": 300,
"demand": { "units": 10 },
"penalty": 100,
"location_name": "Low Priority Dropoff - Woodlands"
},
{
"uid": "dropoff_medium_penalty",
"booking_uid": "booking_3",
"node_type": "dropoff",
"lat": 1.3069,
"lon": 103.8434,
"open_time_ts": "2026-01-01T09:00:00+00:00",
"close_time_ts": "2026-01-01T12:00:00+00:00",
"service_time": 300,
"demand": { "units": 10 },
"penalty": 5000,
"location_name": "Standard Dropoff - Orchard"
},
{
"uid": "depot_start_node",
"node_type": "point",
"lat": 1.3521,
"lon": 103.8198,
"open_time_ts": "2026-01-01T08:00:00+00:00",
"close_time_ts": "2026-01-01T18:00:00+00:00",
"service_time": 0,
"demand": {}
}
],
"vehicles": [
{
"agent_id": "vehicle_1",
"lat": 1.3521,
"lon": 103.8198,
"start_time": "2026-01-01T08:00:00+00:00",
"end_time": "2026-01-01T18:00:00+00:00",
"capacity": { "units": 50 },
"partial_route": ["depot_start_node"]
}
]
}

Playground

You can experiment with the Booking Penalty concept using the playground below. The example is set up with three drop-off nodes with different penalty values.

  • Observe how the optimizer chooses to reject the low-penalty booking because it is geographically inefficient to service.
  • Try increasing the penalty for the "Low Priority Dropoff" to a very high value (e.g., 1000000) and see how the optimizer is forced to include it in the route, despite the higher travel cost.
Loading...