API Documentation
vitaRoute API integration guide
Quick Start
The vitaRoute API is REST-based and works with JSON. All requests must be sent over HTTPS.
- Create a free account
- Generate an API key from the Dashboard
- Send your first optimization request
Authentication
All API requests require authentication via the X-Api-Key header.
⚠️ Security Note
Do not include your API keys in source code. Use environment variables.
Endpoints
/api/optimization/optimizeAdvanced route optimization. The most efficient routes are calculated by evaluating 20+ parameters with the RL-powered proprietary vitaRoute algorithm.
/api/route/calculateBasic route calculation. Simple cluster-based route plan.
/api/route/cluster-stopsClusters existing stops according to vehicle capacity.
Request Schema
| Field | Type | Description |
|---|---|---|
facilityLat | float | Facility/depot latitude coordinate |
facilityLng | float | Facility/depot longitude coordinate |
totalCapacity | int | Maximum capacity per vehicle (default: 14) |
vehicleCount | int | Always 0 — vehicle count is auto-determined |
maxWalking | int? | Maximum walking distance (meters, default: 500) |
maxDuration | int? | Maximum route duration (minutes, default: 90) |
maxClusterDiameterKm | float | Maximum geographic diameter of stops in the same cluster (km, default: 25) |
minSavingsKm | float | Minimum distance saving required to merge a stop (km, default: 0.3) |
maxDetourFactor | float | Maximum detour ratio when adding a stop to an existing route (default: 0.6) |
minDistrictPassengers | int | Minimum passengers required to create a district-specific route (default: 8) |
tripDirection | string | Trip direction: 'to_facility' (inbound to depot) or 'from_facility' (outbound from depot) |
arrivalTimeAtDepot | string? | Vehicle arrival time at depot (ISO 8601 UTC). When provided, speed is calculated based on traffic profile; otherwise a fixed 28 km/h is used. |
useDistanceMatrix | boolean | Whether to use Google Maps Distance Matrix API for accurate road distances (default: false) |
nodes | NodeInput[] | List of personnel/locations to optimize |
NodeInput
| Field | Type | Description |
|---|---|---|
id | string | Unique personnel/location identifier |
name | string | Personnel name |
latitude | float | Latitude coordinate |
longitude | float | Longitude coordinate |
district | string? | District name (optional, for district rules) |
Response Schema
{
"routes": [
{
"routeId": "uuid",
"routeName": "GEBZE 1",
"totalDuration": 45,
"totalDistance": 28500,
"nodeCount": 14,
"totalLoad": 14,
"stops": [
{
"stopIndex": 0,
"latitude": 40.8962,
"longitude": 29.1882,
"nodes": [
{ "id": "1", "name": "Ali Yilmaz" }
]
}
],
"routeCenter": {
"latitude": 40.9,
"longitude": 29.2
}
}
]
}Rate Limits
| Plan | Monthly Requests | Max Nodes | Concurrent |
|---|---|---|---|
| Free | 50 | 1 | 1 |
| Starter | 1,000 | 100 | 5 |
| Growth | 5,000 | 500 | 20 |
| Enterprise | Unlimited | Unlimited | Custom |
When the rate limit is exceeded, a 429 Too Many Requests response is returned. The Retry-After header specifies the wait time.
Error Codes
Bad Request
Invalid JSON or missing required field
Unauthorized
API key missing or invalid
Forbidden
Your plan limit has been exceeded
Too Many Requests
Rate limit exceeded
Internal Server Error
Server error, please contact support
Code Examples
curl
curl -X POST https://api.vitaroute.ai/api/optimization/optimize \
-H "Content-Type: application/json" \
-H "X-Api-Key: vtr_live_your_key_here" \
-d '{
"facilityLat": 40.9139,
"facilityLng": 29.1167,
"totalCapacity": 16,
"vehicleCount": 0,
"maxWalking": 500,
"maxDuration": 90,
"maxClusterDiameterKm": 25,
"minSavingsKm": 0.3,
"maxDetourFactor": 0.6,
"minDistrictPassengers": 8,
"tripDirection": "to_facility",
"arrivalTimeAtDepot": "2025-01-15T05:00:00Z",
"useDistanceMatrix": false,
"nodes": [
{ "id": "1", "name": "Ali Yilmaz", "latitude": 40.8962, "longitude": 29.1882, "district": "Kadikoy" },
{ "id": "2", "name": "Ayse Demir", "latitude": 40.9278, "longitude": 29.3125, "district": "Gebze" }
]
}'python
import requests
response = requests.post(
"https://api.vitaroute.ai/api/optimization/optimize",
headers={
"Content-Type": "application/json",
"X-Api-Key": "vtr_live_your_key_here"
},
json={
"facilityLat": 40.9139,
"facilityLng": 29.1167,
"totalCapacity": 16,
"vehicleCount": 0,
"maxWalking": 500,
"maxDuration": 90,
"maxClusterDiameterKm": 25,
"minSavingsKm": 0.3,
"maxDetourFactor": 0.6,
"minDistrictPassengers": 8,
"tripDirection": "to_facility",
"arrivalTimeAtDepot": "2025-01-15T05:00:00Z",
"useDistanceMatrix": False,
"nodes": [
{"id": "1", "name": "Ali Yilmaz", "latitude": 40.8962, "longitude": 29.1882}
]
}
)
data = response.json()
for route in data["routes"]:
print(f"{route['routeName']}: {route['nodeCount']} stops, {route['totalDuration']} min")javascript
const response = await fetch(
"https://api.vitaroute.ai/api/optimization/optimize",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "vtr_live_your_key_here",
},
body: JSON.stringify({
facilityLat: 40.9139,
facilityLng: 29.1167,
totalCapacity: 16,
vehicleCount: 0,
maxWalking: 500,
maxDuration: 90,
maxClusterDiameterKm: 25,
minSavingsKm: 0.3,
maxDetourFactor: 0.6,
minDistrictPassengers: 8,
tripDirection: "to_facility",
arrivalTimeAtDepot: "2025-01-15T05:00:00Z",
useDistanceMatrix: false,
nodes: [
{ id: "1", name: "Ali Yilmaz", latitude: 40.8962, longitude: 29.1882 },
],
}),
}
);
const { routes } = await response.json();
routes.forEach(route => {
console.log(`${route.routeName}: ${route.nodeCount} stops`);
});C#
using System.Net.Http.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", "vtr_live_your_key_here");
var payload = new {
facilityLat = 40.9139,
facilityLng = 29.1167,
totalCapacity = 16,
vehicleCount = 0,
maxWalking = 500,
maxDuration = 90,
maxClusterDiameterKm = 25,
minSavingsKm = 0.3,
maxDetourFactor = 0.6,
minDistrictPassengers = 8,
tripDirection = "to_facility",
arrivalTimeAtDepot = "2025-01-15T05:00:00Z",
useDistanceMatrix = false,
nodes = new[] {
new { id = "1", name = "Ali Yilmaz", latitude = 40.8962, longitude = 29.1882 }
}
};
var response = await client.PostAsJsonAsync(
"https://api.vitaroute.ai/api/optimization/optimize",
payload
);
var result = await response.Content.ReadFromJsonAsync<RouteResponse>();Integration API (ERP Integration)
An API designed for managing vitaRoute end-to-end from your own interface (e.g. an ERP system). Create and update project, shift, and passenger records, read finalized route plans, and write back edits you make — all without ever touching the extranet UI.
Uses the same authentication (X-Api-Key); all endpoints live under https://api.vitaroute.ai/api/integration.
All PUT (update) requests are PARTIAL — only fields you send in the body change; omitted fields keep their current value.
When updating a plan, do NOT send route geometry (savedPolyline) or distance/duration (savedStats) — vitaRoute computes these itself from your stop order via Google Directions, so the map always shows a valid, real road path.
Projects
Create, list, update, and delete projects. An ERP should store the id of the vitaRoute project matching its own customer record here.
/api/integration/projectsLists all projects owned by the API key.
/api/integration/projectsCreates a new project (facility location, optimization model, trip info).
/api/integration/projects/{projectId}Partially updates a project — only the fields provided change.
/api/integration/projects/{projectId}Permanently deletes a project and all its data (passengers, shifts, runs, plans). Irreversible.
| Field | Type | Description |
|---|---|---|
name | string | Project name |
facilityLat | float | Facility latitude |
facilityLng | float | Facility longitude |
description | string? | Description (optional) |
countryCode | string? | Country code, e.g. "TR" (optional) |
icon | string? | Facility icon key (optional) |
optimizationModel | string | "personnel" (staff transport) | "school" (school transport) |
passengerMode | string | "fixed" (fixed trips) | "shift" (shift-based) — only meaningful in personnel model |
trips | Trip[] | List of trips (time+direction). At least one is required in fixed mode; ignored in shift mode. |
Shifts
Full CRUD for shift records that define facility entry/exit times in shift-based projects.
/api/integration/shifts?projectId=Lists all shifts for a project.
/api/integration/shiftsAdds a new shift (at least one of entry/exit time is required).
/api/integration/shifts/{shiftId}Partially updates a shift.
/api/integration/shifts/{shiftId}Deletes a shift.
| Field | Type | Description |
|---|---|---|
projectId | string | Id of the project to add the shift to |
name | string | Shift name, e.g. "Morning" |
entryTime | string? | Facility entry time, "HH:mm" (optional) |
exitTime | string? | Facility exit time, "HH:mm" (optional) |
nextDayExit | boolean | true = exit is next day (only meaningful when exitTime is given) |
Passengers
Full CRUD for passenger/student/employee records. The employee_no field is an optional natural key so your ERP can match records by its own registry/student number.
/api/integration/passengers?projectId=Lists all passengers for a project.
/api/integration/passengersAdds a new passenger (name and location are required).
/api/integration/passengers/{nodeId}Partially updates a passenger.
/api/integration/passengers/{nodeId}Deletes a passenger.
| Field | Type | Description |
|---|---|---|
projectId | string | Id of the project to add the passenger to |
name | string | Passenger name |
latitude | float | Latitude |
longitude | float | Longitude |
employeeNo | string? | Registry/student number — natural key for matching your own records (optional) |
department | string? | Department (optional) |
gender | string? | "male" | "female" (optional) |
specialNeeds | boolean | Special needs flag (default: false) |
address | string? | Address text (optional) |
city | string? | City (optional) |
district | string? | District (optional) |
Plan Transfer
Read finalized route plans filtered by project/date/shift/direction; write back the stop order and passenger assignment you edited.
/api/integration/plan?projectId=&dateFrom=&dateTo=&shiftName=&direction=Returns finalized route plan(s) matching project/date range/shift/direction filters — including routes, stops, passengers, distance and duration — in full.
/api/integration/plan/{runId}Overwrites a run's route/stop/passenger data with the edits made on the ERP side. Route geometry is recomputed by vitaRoute.
result[] — Route
| Field | Type | Description |
|---|---|---|
routeName | string? | Route name, e.g. "Route 1" |
color | string? | Display color on the map, hex (optional) |
stops | Stop[] | Stops, IN ROUTE ORDER |
stops[] — Stop
| Field | Type | Description |
|---|---|---|
lat | float | Stop latitude |
lng | float | Stop longitude |
stopName | string? | Stop name (optional) |
passengers | Passenger[] | Passengers assigned to this stop |
passengers[] — Passenger
| Field | Type | Description |
|---|---|---|
id | string | Existing passenger id (must match the one from the GET response exactly) — REQUIRED |
name | string? | Passenger name (display only) |
Integration API Examples
GET /projects
curl https://api.vitaroute.ai/api/integration/projects \ -H "X-Api-Key: vtr_live_your_key_here"
POST /passengers
curl -X POST https://api.vitaroute.ai/api/integration/passengers \
-H "Content-Type: application/json" \
-H "X-Api-Key: vtr_live_your_key_here" \
-d '{
"projectId": "b3f1c2a4-...",
"name": "Ali Yilmaz",
"latitude": 40.8962,
"longitude": 29.1882,
"employeeNo": "EMP-00123"
}'GET /plan
curl "https://api.vitaroute.ai/api/integration/plan?projectId=b3f1c2a4-...&shiftName=Sabah&direction=to_facility" \ -H "X-Api-Key: vtr_live_your_key_here"
PUT /plan/{runId}
curl -X PUT https://api.vitaroute.ai/api/integration/plan/9e7d0f21-... \
-H "Content-Type: application/json" \
-H "X-Api-Key: vtr_live_your_key_here" \
-d '{
"result": [
{
"routeName": "Hat 1",
"color": "#1E40AF",
"stops": [
{
"lat": 40.8962, "lng": 29.1882, "stopName": "Kadikoy Iskele",
"passengers": [{ "id": "3f9a...", "name": "Ali Yilmaz" }]
}
]
}
]
}'
# Not: savedPolyline / savedStats göndermezsiniz — vitaRoute rota
# geometrisini durak sırasından kendisi hesaplar.