Skip to content

Time Windows

Time windows let you specify when each stop must be visited. The optimizer arranges the stop order to satisfy as many windows as possible. Any stop that cannot be reached within its window is still visited - the response reports the violation so you can act on it.

Time windows require the Optimized Routing endpoint and departureTime.

Each stop can have a time window defined by an open and close time. The optimizer treats these as scheduling constraints when deciding the visit order.

08:00 09:00 10:00 11:00 12:00
├───────┼───────┼───────┼───────┤
A [═══════════════] 09:00–11:00
↑ 08:50 early: waits 10 min
B [═══════════] 10:30–12:00
↑ 10:45 matched
C [═══════] 09:00–10:00
↑ 11:20 late: 4800s past close

The vehicle arrives before the window opens. It waits at the stop until open, then begins service. The wait time is reported as violation_seconds. Subsequent stops are delayed by the same amount - this is the most common reason a tight window on one stop causes a cascade of late arrivals on others.

The vehicle arrives within the window. No wait, no violation.

The vehicle arrives after the window closes. The stop is still served immediately - the vehicle does not skip it. violation_seconds reports how far past close the vehicle arrived. Late violations cannot be recovered; the optimizer tried all orderings and this was the best result possible given the constraints.

POST https://api.roadgis.dev/directions/v1/optimized
Authorization: Bearer YOUR_API_KEY

Add timeWindow to any intermediate stop alongside stopDuration. First and last locations (depot) do not accept time windows.

{
"profile": "auto",
"departureTime": "08:00",
"locations": [
{
"address_structured": {
"postcode": "28216",
"city": "Utena",
"street": "Metalo g. 3"
}
},
{
"id": "LT000000001",
"stopDuration": 120,
"address_structured": {
"postcode": "28214",
"city": "Utena",
"street": "J. Basanavičiaus g. 108E"
}
},
{
"id": "LT000000002",
"stopDuration": 150,
"address_structured": {
"postcode": "28150",
"city": "Utena",
"street": "Aušros g. 78"
},
"timeWindow": {
"open": "08:30",
"close": "12:00"
}
},
{
"id": "LT000000003",
"stopDuration": 120,
"address_structured": {
"postcode": "28142",
"city": "Utena",
"street": "Basanavičiaus g. 52"
},
"timeWindow": {
"open": "08:00",
"close": "09:00"
}
},
{
"address_structured": {
"postcode": "28216",
"city": "Utena",
"street": "Metalo g. 3"
}
}
],
"routeModifiers": {
"excludeUnpaved": false,
"topSpeed": 80,
"shortest": false
},
"computeOptions": {
"steps": false
}
}
FieldTypeRequiredDescription
openstringyesEarliest allowed arrival in HH:MM
closestringyesLatest allowed arrival in HH:MM

departureTime is required whenever any location includes a timeWindow. The request returns 400 with code: InvalidInput if time windows are present but departureTime is omitted.

Waypoints with a timeWindow include a timeWindowStatus object.

{
"code": "Ok",
"waypoints": [
{
"id": null,
"originalIndex": 0,
"location": {
"lat": 55.49894,
"lng": 25.631195
},
"matchedAddress": "Metalo g. 3, LT-28216 Utena",
"relevance": 0.8727,
"arrivalTime": "08:00"
},
{
"id": "LT000000003",
"originalIndex": 3,
"location": {
"lat": 55.497962,
"lng": 25.596965
},
"matchedAddress": "J. Basanavi\u010diaus g. 52, LT-28142 Utena",
"relevance": 0.7965,
"arrivalTime": "08:05",
"timeWindowStatus": {
"matched": true
}
},
{
"id": "LT000000002",
"originalIndex": 2,
"location": {
"lat": 55.507264,
"lng": 25.595426
},
"matchedAddress": "Au\u0161ros g. 78, LT-28150 Utena",
"relevance": 0.8727,
"arrivalTime": "08:12",
"timeWindowStatus": {
"matched": false,
"violation": "early",
"violation_seconds": 1033
}
},
{
"id": "LT000000001",
"originalIndex": 1,
"location": {
"lat": 55.505768,
"lng": 25.623086
},
"matchedAddress": "J. Basanavi\u010diaus g. 108E, LT-28214 Utena",
"relevance": 0.8727,
"arrivalTime": "08:37"
},
{
"id": null,
"originalIndex": 4,
"location": {
"lat": 55.49894,
"lng": 25.631195
},
"matchedAddress": "Metalo g. 3, LT-28216 Utena",
"relevance": 0.8727,
"arrivalTime": "08:44"
}
],
"routes": [...]
}
FieldTypeDescription
matchedbooleantrue if the vehicle arrived within the window
violationstring"early" or "late". Present only when matched is false
violation_secondsintegerSeconds outside the window. Present only when matched is false

Stops without a timeWindow do not have timeWindowStatus in the response.

OutcomeMeaning
matchedArrival falls within open-close. No wait, no violation.
earlyVehicle arrives before open. It waits at the stop until the window opens before departing. violation_seconds is the wait time.
lateVehicle arrives after close. The delivery is late. violation_seconds is how far past the close time.