Concepts & Guides
Understand the fundamentals of vehicle routing optimization and how to get the most out of the API.
Vehicle Routing Problem (VRP)
The Vehicle Routing Problem is the challenge of finding the optimal set of routes for a fleet of vehicles to service a collection of tasks or customers. It sits at the heart of logistics, field service, and delivery operations. Finding the best routes saves fuel, reduces labour costs, and improves customer satisfaction.
VRP is classified as NP-hard, meaning there is no known algorithm that can solve it in polynomial time. With just 20 stops, there are over 2.4 quintillion possible routes. Our API uses Google OR-Tools with metaheuristic search strategies to find near-optimal solutions in seconds rather than centuries.
Common problem variants include CVRP (capacitated), VRPTW (with time windows), PDPTW (pickup and delivery with time windows), and TSP (single vehicle, no constraints). The API handles all of these transparently based on the data you provide.
Route Topology
Problem Profiles (Phase 2.1)
Problem profiles apply domain-specific defaults before solving. They reduce setup time and improve baseline behavior for common operations while preserving explicit request settings.
| Profile | Default Focus | Typical Adaptations |
|---|---|---|
| last_mile_delivery | On-time + route efficiency | Balanced policy defaults, duration/distance weights, optional default max route duration. |
| field_service | SLA and technician fit | SLA-first policy and optional strict multi-skill matching (required_skills_mode=all). |
| sales_routes | Coverage and fairness | Balanced workload defaults and daily variance target for territory distribution. |
{
"problem_type": "vrptw",
"problem_profile": "field_service",
"profile_options": {
"field_service": {
"require_all_skills_for_multi_skill_tasks": true,
"default_min_technician_rating": 4.0
}
}
}Time Windows
Time windows constrain when a vehicle can arrive at a task location. They are essential for modelling real-world deliveries where customers are only available during certain hours, or where regulatory limits apply (e.g. no deliveries before 7 AM in residential areas).
Hard time windows must be strictly respected — a vehicle arriving outside the window causes the task to be marked unassigned. Soft time windows allow violations but apply a penalty cost that the optimizer minimises, giving you flexibility when strict adherence is impractical.
Delivery Windows (24h timeline)
{
"tasks": [
{
"id": "delivery-001",
"location": { "lat": 51.5074, "lng": -0.1278 },
"time_window": {
"start": "2024-01-15T09:00:00Z",
"end": "2024-01-15T12:00:00Z"
},
"service_duration": 600
}
]
}Vehicle Capacities
Capacity constraints ensure that vehicles are never overloaded. The API supports multi-dimensional capacity modelling so you can track weight, volume, and pallet count simultaneously. Each task specifies its demand across the same dimensions.
For example, a truck might have a maximum weight of 10,000 kg and a volume of 40 m³. A delivery requiring 500 kg and 2 m³ is only assigned to that truck if sufficient capacity remains after all previously assigned tasks.
| Dimension | Unit | Example Vehicle | Example Task |
|---|---|---|---|
| Weight | kg | 10,000 | 500 |
| Volume | m³ | 40 | 2 |
| Pallets | count | 18 | 1 |
{
"vehicles": [
{
"id": "truck-01",
"capacity": [10000, 40, 18]
}
],
"tasks": [
{
"id": "delivery-001",
"demand": [500, 2, 1]
}
]
}Skills & Requirements
Skills matching ensures that tasks are only assigned to vehicles (and drivers) that have the necessary capabilities. A task may require refrigeration, hazmat certification, a tail-lift, or a specific language spoken by the driver.
The vehicle must possess all skills listed on the task for it to be eligible. If no vehicle can satisfy a task's requirements, the task will appear in the unassigned list in the response, along with the reason.
Matching Example
Vehicle: truck-01
Task: delivery-005
Match — vehicle has all required skills
{
"vehicles": [
{
"id": "truck-01",
"skills": ["refrigeration", "tail-lift", "hazmat"]
}
],
"tasks": [
{
"id": "delivery-005",
"skills": ["refrigeration", "tail-lift"]
}
]
}Objectives & Trade-offs
Route optimization rarely has a single goal. You might want to minimise total distance driven, but also minimise the number of vehicles used. These objectives often compete — fewer vehicles means longer individual routes.
The API supports multi-objective optimization through configurable weights. Each objective is assigned a weight between 0 and 1 that controls its relative importance. The solver blends these into a single cost function and finds the best compromise.
Objective Weight Sliders
{
"objectives": {
"minimize_distance": 0.8,
"minimize_time": 0.6,
"minimize_vehicles": 0.4,
"minimize_cost": 0.7
}
}Depots & Multi-Depot
A depot is where vehicles start and (optionally) end their routes. In a single-depot scenario all vehicles originate from one location. Multi-depot routing assigns each vehicle a home depot, and the optimizer considers travel distance from each depot to each task when building routes.
You can also configure open routes where vehicles do not return to the depot after their last task. This is useful for field-service teams that go home at the end of the day rather than returning to a warehouse.
Depot Configurations
Single Depot
All vehicles start and return to one location
Multi-Depot
Vehicles assigned to different home locations
Open Routes
Vehicles end at last task, no return trip
{
"depots": [
{
"id": "warehouse-north",
"location": { "lat": 51.55, "lng": -0.10 }
},
{
"id": "warehouse-south",
"location": { "lat": 51.45, "lng": -0.12 }
}
],
"vehicles": [
{
"id": "van-01",
"depot_id": "warehouse-north",
"return_to_depot": false
}
]
}Distance Matrices
A distance matrix is a table of travel times and distances between every pair of locations in your problem. The optimizer uses this matrix millions of times during search, so having an accurate and fast matrix is critical for solution quality.
You can either let the API compute the matrix automatically using OSRM (self-hosted, no rate limits) or provide a precomputed matrix. For production workloads, you can also integrate Google Maps for traffic-aware travel times.
Pass locations only — the API calculates the full matrix using OSRM. Best for most use cases with up to 2,000 locations.
POST /api/v1/matrix
{
"locations": [
{ "lat": 51.5074, "lng": -0.1278 },
{ "lat": 51.5155, "lng": -0.1419 },
{ "lat": 51.5033, "lng": -0.1195 }
],
"engine": "osrm"
}Re-optimization
Real-world operations rarely go as planned. New orders arrive, customers cancel, and vehicles break down. Re-optimization takes your current plan and adjusts it to accommodate changes without rebuilding from scratch.
The API accepts a previous solution along with a set of changes (added tasks, removed tasks, or updated constraints). It preserves already-started routes and only rearranges what is necessary. The response includes a changes object that details every modification for auditing purposes.
Re-optimization Flow
POST /api/v1/reoptimize
{
"previous_job_id": "job_abc123",
"add_tasks": [
{
"id": "urgent-delivery-099",
"location": { "lat": 51.51, "lng": -0.13 },
"time_window": {
"start": "2024-01-15T14:00:00Z",
"end": "2024-01-15T16:00:00Z"
}
}
],
"remove_task_ids": ["delivery-003"]
}ML-Enhanced Routing
Traditional routing engines use static road-network speeds. Our ML layer learns from your historical delivery data to predict actual travel times more accurately, accounting for time-of-day patterns, weather effects, and driver behaviour.
When ML predictions are active, each route segment includes a confidence score indicating prediction reliability. Models are versioned and can be retrained as new data accumulates. This is a key differentiator over generic routing APIs.
ML Pipeline
Historical Data
GPS traces, ETAs
Train Model
Feature engineering
Predict Times
Per segment
Optimize
Better solutions
// Enable ML predictions in optimization
POST /api/v1/optimize
{
"options": {
"use_ml_predictions": true,
"ml_model_version": "latest"
},
...
}
// Check ML model status
GET /api/v1/ml/status
// Response includes: model_version, accuracy, last_trainedAsync vs Sync Execution
For small problems (fewer than 50 tasks), synchronous execution returns results directly in the HTTP response within seconds. For larger problems, asynchronous execution queues the job and returns a job ID immediately so your application is not blocked.
With async mode, you can either poll the job status endpoint or register a webhook to be notified when the job completes. Polling is simpler to implement while webhooks are more efficient for high-throughput systems.
// Sync: result returned directly
POST /api/v1/optimize
{ "mode": "sync", "tasks": [...], "vehicles": [...] }
// Response: 200 OK with full solutionSync Mode
- Best for < 50 tasks
- Result in HTTP response
- Simpler integration
Async Mode
- Best for 50+ tasks
- Non-blocking execution
- Webhook notifications
Webhooks & Events
Webhooks let you receive real-time notifications when events occur in the optimization service. Instead of polling for job status, you register a URL and the API sends an HTTP POST with the event payload as soon as the event fires.
Failed deliveries are retried with exponential backoff up to 5 times over 24 hours. Each delivery includes a signature header so you can verify authenticity. Events are delivered at least once; your endpoint should be idempotent.
Supported Event Types
job.completedOptimization job finishedjob.failedJob encountered an errorjob.progressIntermediate progress updatemodel.trainedML model training completedreport.readyScheduled report generatedusage.thresholdUsage limit approachingPOST /api/v1/webhooks
{
"url": "https://your-app.com/webhooks/optiroute",
"events": ["job.completed", "job.failed"],
"secret": "whsec_your_signing_secret"
}
// Webhook payload example
{
"event": "job.completed",
"job_id": "job_abc123",
"timestamp": "2024-01-15T14:32:00Z",
"data": {
"total_distance": 142500,
"total_duration": 28800,
"vehicles_used": 3
}
}Rate Limits & Best Practices
The API enforces rate limits to ensure fair usage across all tenants. The default tier allows 60 requests per minute. Rate limit headers are included in every response so you can track your remaining quota in real time.
When you receive a 429 response, implement exponential backoff: wait 1 second, then 2, then 4, up to a maximum of 32 seconds. For bulk operations, batch your tasks into a single optimization request rather than sending one request per task.
Rate Limit Tiers
| Tier | Requests/min | Max Tasks/req | Concurrent Jobs |
|---|---|---|---|
| Free | 20 | 50 | 1 |
| Starter | 60 | 500 | 3 |
| Professional | 200 | 2,000 | 10 |
| Enterprise | Custom | 10,000+ | Unlimited |
Tips for Production
- Cache distance matrices when locations are reused across requests
- Use async mode for anything above 50 tasks to avoid HTTP timeouts
- Set realistic time windows — overly tight windows increase unassigned tasks
- Monitor the
X-RateLimit-Remainingheader - Enable ML predictions after collecting at least 2 weeks of historical data
// Exponential backoff example (JavaScript)
async function callWithRetry(fn, maxRetries = 5) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (err) {
if (err.status !== 429 || i === maxRetries - 1) throw err;
const delay = Math.min(1000 * Math.pow(2, i), 32000);
await new Promise(r => setTimeout(r, delay));
}
}
}