Skip to main content

Maximum Trips Per Vehicle

In some logistics scenarios, it's necessary to limit the number of trips a vehicle can make from a depot. For example, a driver might have a maximum number of routes they can perform in a shift, or a vehicle might need to return to the depot for reloading or maintenance after a certain number of tours.

This constraint is particularly relevant for operations using a Pickup and Delivery (PDP) model, where a vehicle can perform multiple trips, returning to a depot between them.

How It Works

To enforce a maximum number of trips, two key parameters must be configured in a Stateless API request:

  1. number_of_trips: This parameter is set on the vehicle object and defines the maximum number of trips that the vehicle is allowed to perform.
  2. end_of_trip: true: This flag must be set on the node that represents the depot. It signals to the optimizer that visiting this node completes a trip, allowing the vehicle to start a new one if its limit has not been reached.

When a vehicle completes a delivery and returns to a node marked as end_of_trip: true, the optimizer counts this as one completed trip. It will only assign a new trip to the vehicle if the total number of completed trips is less than the number_of_trips limit.

Example

Here is a JSON snippet for a node_scheduler request that demonstrates this constraint.

  • The vehicle is limited to one trip. Its starting point is explicitly set to the depot using partial_route.
  • There are three bookings (A, B, and C). Bookings A and B are close to the depot and can be served in a single trip. Booking C is far away and has a later time window, making it impossible to serve in the same trip as A and B.
  • The depot node is marked with end_of_trip: true.

Because the vehicle is limited to one trip, the optimizer will serve bookings A and B and reject booking C.

{
"current_time": "2025-11-21T08:00:00Z",
"engine_settings": {
"calculation_parameters": {
"calculations_mode": "sync",
"scheduling_mode": "prebook"
},
"model_parameters": {
"optimize_quantity": "total_time",
"booking_penalty": 100000
},
"routing_engine": {
"routing_engine_name": "osrme",
"url": "http://mapbox-osrm-proxy",
"road_network": "van"
}
},
"nodes": [
{
"uid": "depot",
"node_type": "depot",
"lat": 1.3521,
"lon": 103.8198,
"open_time_ts": "2025-11-21T08:00:00Z",
"close_time_ts": "2025-11-21T18:00:00Z",
"close_time_ts_dynamic": "2025-11-21T18:00:00Z",
"service_time": 0,
"demand": {},
"end_of_trip": true
},
{
"uid": "pickup_A",
"booking_uid": "booking_A",
"node_type": "pickup",
"lat": 1.306,
"lon": 103.832,
"open_time_ts": "2025-11-21T09:00:00Z",
"close_time_ts": "2025-11-21T10:00:00Z",
"close_time_ts_dynamic": "2025-11-21T10:00:00Z",
"service_time": 300,
"demand": { "units": 10 }
},
{
"uid": "dropoff_A",
"booking_uid": "booking_A",
"node_type": "dropoff",
"lat": 1.283,
"lon": 103.858,
"open_time_ts": "2025-11-21T10:00:00Z",
"close_time_ts": "2025-11-21T11:00:00Z",
"close_time_ts_dynamic": "2025-11-21T11:00:00Z",
"service_time": 300,
"demand": { "units": -10 }
},
{
"uid": "pickup_B",
"booking_uid": "booking_B",
"node_type": "pickup",
"lat": 1.32,
"lon": 103.9,
"open_time_ts": "2025-11-21T09:00:00Z",
"close_time_ts": "2025-11-21T10:00:00Z",
"close_time_ts_dynamic": "2025-11-21T10:00:00Z",
"service_time": 300,
"demand": { "units": 10 }
},
{
"uid": "dropoff_B",
"booking_uid": "booking_B",
"node_type": "dropoff",
"lat": 1.34,
"lon": 103.92,
"open_time_ts": "2025-11-21T10:00:00Z",
"close_time_ts": "2025-11-21T11:00:00Z",
"close_time_ts_dynamic": "2025-11-21T11:00:00Z",
"service_time": 300,
"demand": { "units": -10 }
},
{
"uid": "pickup_C",
"booking_uid": "booking_C",
"node_type": "pickup",
"lat": 1.449,
"lon": 103.801,
"open_time_ts": "2025-11-21T14:00:00Z",
"close_time_ts": "2025-11-21T15:00:00Z",
"close_time_ts_dynamic": "2025-11-21T15:00:00Z",
"service_time": 300,
"demand": { "units": 5 }
},
{
"uid": "dropoff_C",
"booking_uid": "booking_C",
"node_type": "dropoff",
"lat": 1.43,
"lon": 103.79,
"open_time_ts": "2025-11-21T15:00:00Z",
"close_time_ts": "2025-11-21T16:00:00Z",
"close_time_ts_dynamic": "2025-11-21T16:00:00Z",
"service_time": 300,
"demand": { "units": -5 }
}
],
"vehicles": [
{
"agent_id": "vehicle_1",
"start_time": "2025-11-21T08:00:00Z",
"end_time": "2025-11-21T18:00:00Z",
"capacity": { "units": 50 },
"number_of_trips": 1,
"partial_route": ["depot"]
}
]
}

Playground

You can experiment with this constraint in the playground below.

  • Run the simulation with number_of_trips: 1 and observe that Booking C is rejected.
  • Change the number_of_trips to 2 and run it again. The optimizer will now be able to perform a second trip to service Booking C.
Loading...