Live Vehicle GPS
Put a phone or a GPS device in a vehicle, then read its live position, speed, and history from your own backend or website. One contract for every device type, over REST and WebSocket.
https://api.niyantha.inwss://api.niyantha.in/ws1–10 sSetup (once per vehicle)
- Create a Niyantha account and sign in to the dashboard.
- Add the vehicle under Vehicles (or
POST /api/v1/session/vehicles, see Create Vehicle). Note itsid. - Install Optimus Mini on the phone that rides in the vehicle, sign in with the same account (SMS OTP or password), choose the vehicle, press Start streaming. Each phone becomes its own sensor, so one account can run a whole fleet. A Standard GPS device is attached from the dashboard and lands in the same APIs.
- Crew with their own accounts: open the vehicle in the dashboard → Crew Access and add the driver, conductor or cleaner by phone number (
POST /api/v1/session/vehicles/:id/access{ "contact": "+91...", "role": "driver" }). They sign in to Optimus Mini with their account, find the vehicle tagged with their role and attach their phone. Revoking detaches the phone at once.GET /api/v1/session/vehicles?scope=alllists owned and granted vehicles withaccess_role. - Optional: create a public tracking link so a website can show the vehicle without credentials.
Fixes captured offline are queued on the phone and flushed in order when connectivity returns, so history has no gaps.
Authentication
| Method | Use it for | How |
|---|---|---|
| Session bearer token | Scripts acting as the account | POST /api/v1/accounts/login → token; send Authorization: Bearer |
| S2S API key | Your server (Flask, Node, …) | Create once: POST /api/v1/session/keys with ttl_seconds. REST headers X-API-Key / X-API-Secret; WS auth.login with authType: "s2s". See S2S guide. |
| Public tracking token | A public page showing one vehicle | No credentials; the token in the link is the secret. Deactivate the link to rotate it. |
The live payload
Every live surface (REST snapshot, account event, public event) uses the same location object.
{
"vehicle_id": 45,
"vehicle": { "id": 45, "display_name": "College Bus 1", "vehicle_type": "van", "registration_number": "KA19AB1234" },
"sensor": {
"id": 128, "device_id": "mob_8fhs82aa", "sensor_code": "mob_8fhs82aa",
"name": "Optimus Mini · Samsung SM-A155F", "sensor_type": "mobile", "status": "active",
"battery_pct": 72, "last_seen": 1779201065
},
"location": {
"lat": 13.34012, "lng": 74.74211,
"speed_kmh": 38.2, "heading": 186, "accuracy": 4.5, "altitude": 21.3,
"sensor_id": 128, "timestamp": 1779201065, "server_time": 1779201067, "age_s": 2, "moving": true
},
"server_time": 1779201067
}lat, lngWGS-84 decimal degreesspeed_kmhSpeed in km/h as reported by the deviceheadingDegrees clockwise from north (0-359)accuracyHorizontal accuracy in metresaltitudeMetres above sea leveltimestampGPS fix time, unix seconds (device clock)server_timeWhen Niyantha produced the payload, unix secondsage_sserver_time - timestamp, clamped at 0; how stale the fix ismovingtrue when speed_kmh >= 3 (filters parking jitter)device_idPublic sensor code of the device that produced the fixbattery_pctPhone battery 0-100 (mobile sensors only)location is null until the first fix arrives; sensor is null when nothing is attached.
REST
Session (Bearer) or S2S (API key)
/api/v1/session/vehicles/:id/locationLatest fix with derived fields. S2S: /api/v1/s2s/accounts/vehicles/:id/location
/api/v1/session/vehiclesList vehicles (page, count, status, vehicle_type)
/api/v1/session/vehicles/:id/telemetry/history?from=&to=Points plus stats: total_distance_km, moving_time_s, idle_time_s, max/avg speed_kmh, overspeed instances, coverage gaps
/api/v1/session/vehicles/:id/telemetry/settings{ "overspeed_enabled": true, "overspeed_limit_kmh": 60 }
/api/v1/session/vehicles/:id/telemetry/overspeed-alertsWorker-created overspeed alerts
/api/v1/session/vehicles/:id/tracking-links{ "no_expiry": true } for a permanent public link; default expiry 24 h
/api/v1/session/sensorsPhones and GPS devices registered on the account
Public (no auth)
/api/v1/public/vehicle-tracking/:tokenVehicle summary + the live location object; the dashboard renders it at /track/vehicle/:token
WebSocket
Frames are JSON { type, requestId, as, payload }. Authenticate once; live events are pushed without subscribing. Send { "type": "ping" } every 15–30 s.
Account / server socket
{ "type": "auth.login", "requestId": "a1", "payload": { "authType": "s2s", "token": "<key>", "metadata": { "secret": "<secret>", "app": "college-bus" } } }vehicle.location.updatedEvery accepted fix for any vehicle of the account: { vehicle_id, sensor_id, device_id, location { …live payload…, battery_pct } }
vehicle.telemetry.overspeed_alert.updatedOverspeed alert created or extended
account.vehicle.location.get{ "vehicle_id": 45 } → .ok with the REST live-location payload
account.vehicle.telemetry.historySame as the REST history call
Public tracking socket (no credentials)
{ "type": "auth.login", "requestId": "t1", "payload": { "authType": "vehicle_tracking", "token": "<tracking-link-token>" } }public.vehicle.location.updated{ vehicle_id, location { lat, lng, speed_kmh, heading, accuracy, altitude, timestamp, server_time, age_s, moving } } for that vehicle only
Minimal consumers
import json, os, threading, websocket
latest = {}
def on_message(ws, raw):
msg = json.loads(raw)
if msg.get("type") == "vehicle.location.updated":
latest[msg["payload"]["vehicle_id"]] = msg["payload"]["location"]
def on_open(ws):
ws.send(json.dumps({"type": "auth.login", "requestId": "a1", "payload": {
"authType": "s2s", "token": os.environ["NIYANTHA_KEY"],
"metadata": {"secret": os.environ["NIYANTHA_SECRET"], "app": "college-bus"}}}))
ws = websocket.WebSocketApp("wss://api.niyantha.in/ws", on_open=on_open, on_message=on_message)
threading.Thread(target=ws.run_forever, kwargs={"ping_interval": 20}, daemon=True).start()
# serve `latest` from your own Flask route, e.g. GET /bus/<vehicle_id>const ws = new WebSocket("wss://api.niyantha.in/ws");
ws.onopen = () => ws.send(JSON.stringify({ type: "auth.login", requestId: "t1", payload: { authType: "vehicle_tracking", token } }));
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "public.vehicle.location.updated") setPosition(msg.payload.location);
};
// initial paint: fetch(`https://api.niyantha.in/api/v1/public/vehicle-tracking/${token}`)