API Documentation
Navora provides three REST APIs for route optimization and navigation. All endpoints accept JSON via POST,
require authentication, and return JSON responses.
Base URL
https://resolt-navora-api.azurewebsites.net
All endpoint paths below are relative to this base URL.
Authentication
Every request must include your accountId and apiKey in the JSON body.
These are validated against your account on every call. If invalid or suspended, the API returns 401 Unauthorized.
{
"accountId": "your-account-guid",
"apiKey": "your-api-key",
...
}
Error Handling
| Status | Meaning |
200 | Success |
400 | Bad request — invalid input, too many tasks/vehicles, or route could not be calculated |
401 | Unauthorized — invalid accountId or apiKey, or account suspended |
500 | Internal server error — includes detail message |
Error responses return JSON: { "error": "description" }
POST /api/navigate
Point-to-point navigation with turn-by-turn instructions. Ideal for in-app driver navigation.
For re-routing, simply call again with the driver's current position as the origin.
Request Body
| Field | Type | Required | Description |
accountId | string | Yes | Your account GUID |
apiKey | string | Yes | Your API key |
origin | GeoLocation | Yes | Start point |
destination | GeoLocation | Yes | End point |
profile | string | No | Car (default) or Bike |
preference | string | No | Fastest (default) or Shortest |
waypoints | GeoLocation[] | No | Optional intermediate points |
Example Request
POST https://resolt-navora-api.azurewebsites.net/api/navigate
Content-Type: application/json
{
"accountId": "6ffdea07-8957-49ba-9e0b-5dbce4b86d87",
"apiKey": "your-api-key",
"origin": { "latitude": -26.2041, "longitude": 28.0473 },
"destination": { "latitude": -26.1076, "longitude": 28.0567 },
"profile": "Car",
"preference": "Fastest",
"waypoints": [
{ "latitude": -26.1452, "longitude": 28.0364 }
]
}
Response
{
"distanceKm": 14.23,
"duration": "00:18:45",
"encodedPolyline": "~pq~FhtciC...",
"steps": [
{
"instruction": "Head south onto Main Rd",
"distanceKm": 0.5,
"duration": "00:01:00",
"maneuver": "depart-south",
"location": { "latitude": -26.2041, "longitude": 28.0473 }
},
{
"instruction": "Turn right onto N1",
"distanceKm": 5.2,
"duration": "00:06:30",
"maneuver": "turn-right",
"location": { "latitude": -26.1890, "longitude": 28.0410 }
},
...
]
}
POST /api/route
Multi-stop ordered routing. Supply a sequence of locations and receive a route that visits them in the exact order provided.
Returns the same response format as /api/navigate.
Request Body
| Field | Type | Required | Description |
accountId | string | Yes | Your account GUID |
apiKey | string | Yes | Your API key |
locations | GeoLocation[] | Yes | Ordered list of stops (minimum 2) |
profile | string | No | Car (default) or Bike |
preference | string | No | Fastest (default) or Shortest |
Example Request
POST https://resolt-navora-api.azurewebsites.net/api/route
Content-Type: application/json
{
"accountId": "6ffdea07-8957-49ba-9e0b-5dbce4b86d87",
"apiKey": "your-api-key",
"profile": "Car",
"preference": "Fastest",
"locations": [
{ "latitude": -26.2041, "longitude": 28.0473 },
{ "latitude": -26.1452, "longitude": 28.0364 },
{ "latitude": -26.1076, "longitude": 28.0567 },
{ "latitude": -25.9891, "longitude": 28.1275 }
]
}
Response
Same format as /api/navigate response — distanceKm, duration, encodedPolyline, and steps.
POST /api/optimize
Fleet Matrix Routing — assign tasks to vehicles optimally. Supports capacity constraints, time windows,
multi-depot, chained stops, priority levels, vehicle specialties, and four quality tiers.
Request Body
| Field | Type | Required | Description |
accountId | string | Yes | Your account GUID |
apiKey | string | Yes | Your API key |
tasks | RouteTask[] | Yes | Tasks to assign (max 200) |
vehicles | Vehicle[] | Yes | Available vehicles (max 20) |
mode | string | No | Balanced (default), Shortest, or Fastest |
quality | string | No | Quick (default), Standard, Refined, or Exhaustive |
chains | TaskChain[] | No | Task ordering constraints |
departureTime | DateTimeOffset | No | Departure time (defaults to UTC now) |
includeGeometry | bool | No | Include road polylines per route (default: false) |
clusterBeforeRoute | bool | No | Spatially cluster tasks before routing — one cluster per vehicle, seeded at each depot. Improves geographic cohesion for large, spread-out fleets. Default: false |
territoryFallback | string | No | Free (default) — tasks outside all territories are routed freely. NearestTerritory — out-of-polygon tasks are hard-assigned to the vehicle whose territory centroid is nearest. |
Example Request
POST https://resolt-navora-api.azurewebsites.net/api/optimize
Content-Type: application/json
{
"accountId": "6ffdea07-8957-49ba-9e0b-5dbce4b86d87",
"apiKey": "your-api-key",
"mode": "Balanced",
"quality": "Refined",
"includeGeometry": false,
"vehicles": [
{
"id": "v1",
"name": "Small Van",
"startDepot": {
"id": "depot-1",
"name": "JHB Central",
"location": { "latitude": -26.2041, "longitude": 28.0473 }
},
"endDepot": {
"id": "depot-1",
"name": "JHB Central",
"location": { "latitude": -26.2041, "longitude": 28.0473 }
},
"capacity": 50,
"required": true
}
],
"tasks": [
{
"id": "t1",
"name": "Deliver to Sandton",
"location": { "latitude": -26.1076, "longitude": 28.0567 },
"type": "Delivery",
"serviceDuration": "00:10:00",
"demand": 15
}
]
}
Response
{
"accountId": "6ffdea07-8957-49ba-9e0b-5dbce4b86d87",
"solution": {
"quality": "Refined",
"mode": "Balanced",
"totalDistanceKm": 42.5,
"totalDuration": "01:15:00",
"computedAt": "2025-01-15T10:30:00Z",
"routes": [
{
"vehicleId": "v1",
"vehicleName": "Small Van",
"stops": [ ... ],
"distanceKm": 42.5,
"duration": "01:15:00"
}
],
"unassignedTasks": []
}
}
Territory Planning
Territory planning lets you define a geographic boundary (polygon) per vehicle. Any task whose location falls
inside that polygon is automatically hard-assigned to that vehicle before the solver runs — no specialty tags or
manual assignedVehicleId required.
This is ideal for fleets where drivers own fixed service areas: sales regions, delivery zones, franchise territories,
or field service districts. The solver still optimises the sequence of stops within each territory — you define
who serves an area, Navora figures out how.
How it works
- Add a
territory polygon (ordered list of GeoLocation points, minimum 3) to any vehicle.
- Set
territoryFallback on the request to control what happens to tasks that fall outside all polygons.
- Submit a normal
/api/optimize request — territory assignment happens automatically before clustering and solving.
Overlapping territories
When polygons overlap, the first matching vehicle in the vehicles array wins. Tasks with an explicit assignedVehicleId are never overridden by territory assignment.
Example
POST https://resolt-navora-api.azurewebsites.net/api/optimize
Content-Type: application/json
{
"accountId": "6ffdea07-8957-49ba-9e0b-5dbce4b86d87",
"apiKey": "your-api-key",
"mode": "Balanced",
"quality": "Refined",
"territoryFallback": "NearestTerritory",
"vehicles": [
{
"id": "v-north",
"name": "North Region",
"startDepot": { "id": "d1", "name": "JHB", "location": { "latitude": -26.115, "longitude": 28.073 } },
"endDepot": { "id": "d1", "name": "JHB", "location": { "latitude": -26.115, "longitude": 28.073 } },
"territory": [
{ "latitude": -25.70, "longitude": 27.80 },
{ "latitude": -25.70, "longitude": 28.40 },
{ "latitude": -26.10, "longitude": 28.40 },
{ "latitude": -26.10, "longitude": 27.80 }
]
},
{
"id": "v-south",
"name": "South Region",
"startDepot": { "id": "d1", "name": "JHB", "location": { "latitude": -26.115, "longitude": 28.073 } },
"endDepot": { "id": "d1", "name": "JHB", "location": { "latitude": -26.115, "longitude": 28.073 } },
"territory": [
{ "latitude": -26.10, "longitude": 27.80 },
{ "latitude": -26.10, "longitude": 28.40 },
{ "latitude": -26.50, "longitude": 28.40 },
{ "latitude": -26.50, "longitude": 27.80 }
]
}
],
"tasks": [
{
"id": "t1", "name": "Pretoria delivery",
"location": { "latitude": -25.7461, "longitude": 28.1881 },
"type": "Delivery", "demand": 1
},
{
"id": "t2", "name": "Soweto delivery",
"location": { "latitude": -26.2677, "longitude": 27.8587 },
"type": "Delivery", "demand": 1
}
]
}
In this example, t1 (Pretoria) falls inside the north polygon → assigned to v-north. t2 (Soweto) falls inside the south polygon → assigned to v-south. With NearestTerritory, any task outside both polygons would be assigned to whichever territory centroid is closest.
Enums
All enums can be passed as string names or integer values.
NavigationProfile
Car | 0 | Standard driving profile |
Bike | 1 | Bicycle routing |
RoutePreference
Fastest | 0 | Minimise travel time |
Shortest | 1 | Minimise distance |
OptimizationMode
Balanced | 0 | Balance distance and time |
Shortest | 1 | Minimise total distance |
Fastest | 2 | Minimise total time |
SolutionQuality
Quick | 0 | ~5 seconds |
Standard | 1 | ~15 seconds |
Refined | 2 | ~30 seconds |
Exhaustive | 3 | ~120 seconds |
RouteTaskType
Delivery | 0 | Drop-off task |
Collection | 1 | Pick-up task |
Service | 2 | On-site service |
TerritoryFallback
Free | 0 | Out-of-polygon tasks routed freely by solver |
NearestTerritory | 1 | Assigned to vehicle with nearest territory centroid |
Models
GeoLocation
| Field | Type | Description |
latitude | double | Latitude in decimal degrees |
longitude | double | Longitude in decimal degrees |
Vehicle
| Field | Type | Required | Description |
id | string | Yes | Unique vehicle identifier |
name | string | Yes | Display name |
startDepot | Depot | Yes | Where the vehicle starts |
endDepot | Depot | Yes | Where the vehicle returns |
capacity | double? | No | Load capacity |
maxTasks | int? | No | Maximum tasks this vehicle can handle |
maxDistanceKm | double? | No | Maximum route distance |
maxDuration | TimeSpan? | No | Maximum route duration |
required | bool | No | If true, vehicle must be used |
specialties | string? | No | Comma-delimited specialties (e.g. "refrigerated,hazmat") |
territory | GeoLocation[]? | No | Optional territory polygon (minimum 3 points). Tasks inside this polygon are automatically hard-assigned to this vehicle. See Territory Planning. |
Depot
| Field | Type | Required | Description |
id | string | Yes | Unique depot identifier |
name | string | Yes | Display name |
location | GeoLocation | Yes | Depot coordinates |
RouteTask
| Field | Type | Required | Description |
id | string | Yes | Unique task identifier |
name | string | Yes | Display name |
location | GeoLocation | Yes | Task coordinates |
type | string | No | Delivery (default), Collection, or Service |
serviceDuration | TimeSpan? | No | Time spent at location |
timeWindow | TimeWindow? | No | Earliest/latest arrival constraint |
priority | int | No | 1 (default) = normal, higher = more important |
demand | double | No | Load demand (counted against vehicle capacity) |
chainId | string? | No | Chain group identifier |
chainOrder | int | No | Order within the chain |
specialties | string? | No | Comma-delimited specialties the assigned vehicle must have (e.g. "refrigerated") |
assignedVehicleId | string? | No | Hard assignment — the task must be served by this vehicle. The solver will not assign it to any other vehicle. |
preferredVehicleId | string? | No | Soft preference — the solver will prefer this vehicle but may reassign if constraints cannot be met. A penalty is applied for using a different vehicle. |
TaskChain
| Field | Type | Required | Description |
chainId | string | Yes | Matches the chainId on tasks |
taskIds | string[] | Yes | Ordered list of task IDs in this chain |
allowInterleavedStops | bool | No | If true, other stops may appear between chained tasks |
TimeWindow
| Field | Type | Description |
earliest | DateTimeOffset | Earliest allowed arrival |
latest | DateTimeOffset | Latest allowed arrival |