OptiRoad API Documentation

Introduction

The OptiRoad API lets you optimize delivery routes, geocode addresses, and manage contacts programmatically. Access requires a Business plan and an API key.

Base URL:

https://optiroad.io/api/v1

All requests must include the Authorization header. Responses are JSON. Dates are ISO 8601 strings. Distances are in kilometers, durations in minutes.

Authentication

Authenticate using your API key in the Authorization :

curl https://optiroad.io/api/v1/usage \
  -H "Authorization: Bearer or_live_YOUR_KEY"

API keys are created in Settings → API Keys. Each key is shown only once at creation. Maximum 5 keys per account.

JavaScript example

const BASE = "https://optiroad.io/api/v1";
const KEY  = process.env.OPTIROAD_API_KEY;

const res = await fetch(`${BASE}/usage`, {
  headers: { Authorization: `Bearer ${KEY}` },
});
const data = await res.json();

Python example

import os, requests

BASE = "https://optiroad.io/api/v1"
KEY  = os.environ["OPTIROAD_API_KEY"]

resp = requests.get(
    f"{BASE}/usage",
    headers={"Authorization": f"Bearer {KEY}"}
)
data = resp.json()

Optimize a route

POST/api/v1/optimizeCompute the optimal visiting order for a set of addresses.

Request body

{
  "addresses": [
    { "label": "Dépôt",    "lat": 48.8566, "lng": 2.3522 },
    { "label": "Client A", "lat": 48.8737, "lng": 2.2950 },
    { "label": "Client B", "lat": 48.8416, "lng": 2.3224 }
  ],
  "options": {
    "mode":         "driving",
    "startAddress": 0,
    "roundTrip":    true
  }
}

Parameters

FieldTypeDescription
addressesarrayRequired. List of stops (min 2, max 150). Each item: { label, lat, lng }.
options.modestringRouting profile: driving (default), walking, cycling.
options.startAddressnumberIndex of the start/depot address in the array (default: 0).
options.roundTripbooleanReturn to start after the last stop (default: true).

Response

{
  "optimizedOrder": [0, 2, 1],
  "totalDistanceKm": 12.4,
  "totalDurationMin": 22,
  "legs": [
    { "from": 0, "to": 2, "distanceKm": 5.1, "durationMin": 9 },
    { "from": 2, "to": 1, "distanceKm": 4.2, "durationMin": 8 },
    { "from": 1, "to": 0, "distanceKm": 3.1, "durationMin": 5 }
  ],
  "googleMapsUrl": "https://www.google.com/maps/dir/...",
  "usageRemaining": 487
}

Geocode an address

POST/api/v1/geocodeConvert a free-text address to lat/lng coordinates.
// Request
{ "address": "10 Downing Street, London" }

// Response
{
  "lat": 51.5034,
  "lng": -0.1276,
  "label": "10 Downing Street, Westminster, London, UK"
}

Contacts

Manage your saved address book. All operations are scoped to your account.

GET/api/v1/contactsList contacts (paginated).
GET /api/v1/contacts?page=1&limit=20&search=Paris
{
  "contacts": [
    {
      "id": "clx...",
      "name": "Entrepôt Paris",
      "address": "12 rue de Rivoli, 75001 Paris",
      "lat": 48.856,
      "lng": 2.352,
      "phone": "+33 1 23 45 67 89",
      "createdAt": "2026-03-01T10:00:00.000Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20
}
POST/api/v1/contactsCreate a contact.
// Request
{
  "name": "Entrepôt Paris",
  "address": "12 rue de Rivoli, 75001 Paris",
  "lat": 48.856,
  "lng": 2.352,
  "phone": "+33 1 23 45 67 89"
}

// Response — 201 Created
{ "id": "clx...", "name": "...", ... }
PUT/api/v1/contacts/:idUpdate a contact.
DELETE/api/v1/contacts/:idDelete a contact.
// Response — 204 No Content

Vehicles

GET/api/v1/vehiclesList vehicles.
GET /api/v1/vehicles?status=active&type=van
{
  "vehicles": [
    {
      "id": "clx...",
      "name": "Camion 1",
      "type": "truck",
      "status": "active",
      "depotAddress": "ZI Nord, 59000 Lille",
      "depotLat": 50.651,
      "depotLng": 3.074
    }
  ]
}

Optimization history

GET/api/v1/historyList past optimizations (paginated).
GET /api/v1/history?page=1&limit=20&from=2026-01-01&to=2026-04-01
{
  "items": [
    {
      "id": "clx...",
      "addressCount": 8,
      "totalDistanceKm": 34.2,
      "totalDurationMin": 61,
      "createdAt": "2026-03-15T08:30:00.000Z"
    }
  ],
  "total": 42
}

API usage

GET/api/v1/usageRequest counts for the current key.
{
  "keyPrefix": "or_live_ab12",
  "today":     { "optimize": 3,   "geocode": 12  },
  "thisMonth": { "optimize": 47,  "geocode": 203 },
  "allTime":   { "optimize": 312, "geocode": 1024 }
}

Rate limits

Limits apply per API key. Response headers always include the current window state.

Endpoint typePer minutePer hourPer day
Light (geocode, contacts, vehicles)1001 000
Heavy (optimize)10100500

When a limit is hit the API returns 429 Too Many Requests with a Retry-After header (seconds).

Rate-limit headers

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1744012800   # Unix timestamp (UTC)
Retry-After: 38                 # Only present on 429

Error codes

HTTPerrorMeaning
401UNAUTHORIZEDMissing or malformed Authorization header.
401INVALID_API_KEYKey not found or revoked.
402QUOTA_EXCEEDEDMonthly optimization quota reached. Upgrade your plan.
403PLAN_REQUIREDThis endpoint requires a Business plan.
422VALIDATION_ERRORRequest body failed validation (details in message).
422MAX_KEYS_REACHEDYou already have 5 API keys. Revoke one first.
429RATE_LIMIT_EXCEEDEDToo many requests. Check Retry-After.
500INTERNAL_ERRORUnexpected server error. Please retry.

Error response shape

{
  "error": "QUOTA_EXCEEDED",
  "message": "Monthly quota reached (5/5). Upgrade to Pro for unlimited optimizations.",
  "statusCode": 402
}

Questions? Contact support@optiroad.io

OptiRoad API v1 · 2026