GPS trackers
The trackers fitted to your cars, bikes and trucks (Concox, Jimi, Micodus, Teltonika, Sinotrack, Coban, Queclink, Meitrack,
Ruptela, Suntech, Galileosky, iStartek, JT/T 808 and more, and phones running Traccar Client or OsmAnd). Add one by its IMEI
(14 digits are fine: the check digit is worked out), and put it on a vehicle now or later (POST /trackers/assign; a vehicle
can have several, its position from the best current fix, the primary first); send it the setup SMS steps (setup), and its
positions appear as that vehicle's, with ignition, power and battery. First claim wins: a tracker another organisation
holds is refused (TRACKER_CLAIMED_ELSEWHERE: move it with /tracker-transfers). Devices report to trk.nways.ng on their
protocol's port (GT06 5023, Teltonika 5027, H02 5013, the catalogue lists each; 5000 works any of them out); ones that report
under a shorter id (TK103, watches, JT/T 808 by terminal or SIM number) are matched to their IMEI;
phones to https://nways.ng/v1/trackers/osmand?id=<tracker id>&lat=&lon=×tamp=&speed= (OsmAnd's protocol).
Alarms (SOS, power cut, overspeed, low battery) are alerts of kind tracker_alarm and the webhook asset.tracker_alarm.
Try it without hardware: POST /trackers/{trackerId}/virtual drives a virtual tracker speaking the device's own protocol,
or run go run ./cmd/trackersim (the backend repository) against your own gateway.
On this page
- List your trackers, with counts by state
- Add a tracker by its IMEI (first claim wins)
- The device catalogue, your country's SIM networks and their APNs, and where devices report
- Add many trackers from a CSV (check it first with dryRun)
- The installers' sheet, every tracker's setup SMS in order (CSV)
- Forwarding from your tracking platform, its addresses, and the units it sends
- Turn forwarding on, or give it a new token (the old one stops at once)
- Turn forwarding off (the units stay listed)
- Add a forwarded unit as one of your trackers (a new vehicle named after it, unless you give one)
- Forget a forwarded unit (it comes back if your platform sends it again)
- Your requests to move trackers here, and trackers that moved away
- Ask for a tracker another organisation holds (owners and admins)
- You're making the device log in afresh now (its restart SMS); a fresh login within 3 minutes moves it
- Withdraw a request
- Get a tracker, its setup steps and what's wrong
- Edit a tracker (its vehicle, model, SIM)
- Remove a tracker (it can then be added by anyone)
- The device log (connections, raw frames, decoded fields, answers sent, errors), oldest first
- The device log and state as they change (server-sent events)
- Drive a virtual tracker for this one (its own protocol, through N-Ways' gateway)
- Stop its virtual tracker
- Commands sent to a tracker (the last 30), and which it takes
- Send a command (owners and admins); its answer comes in the device log
Send your key as key=YOUR_API_KEY on the address, or in the X-NWays-Api-Key header. API keys
Base address: https://nways.ng/maps/v1/fleet
List your trackers, with counts by state
GET https://nways.ng/maps/v1/fleet/trackers
Parameters
| Name | In | Type | Description |
|---|---|---|---|
state | query | string | One of: awaiting_first_fix, live, silent. |
model | query | string | A catalogue model id. |
q | query | string | Finds a name, IMEI, vehicle or SIM number. |
curl "https://nways.ng/maps/v1/fleet/trackers" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Trackers
| Field | Type | Description |
|---|---|---|
trackers | Tracker[] | Required. |
trackers[].id | string | |
trackers[].imei | string | |
trackers[].name | string | |
trackers[].vehicleId | string | null | |
trackers[].vehicleName | string | |
trackers[].protocol | string | A protocol N-Ways' gateway reads (gt06, teltonika, h02, gps103, tk103, gl200, meitrack, ruptela, jt808, suntech, galileo, startek, topin, xexun, gosafe, tzone, wialon, watch, osmand), forward for a unit forwarded from your tracking platform, or "" until its model or first connection says. |
trackers[].model | string | |
trackers[].simNumber | string | |
trackers[].network | string | |
trackers[].apn | string | |
trackers[].state | string | One of: awaiting_first_fix, live, silent. |
trackers[].connected | boolean | |
trackers[].heard | boolean | N-Ways' gateway has heard this device (even before it was added). |
trackers[].lastSeenAt | string (date-time) | null | |
trackers[].lastFixAt | string (date-time) | null | Its last GPS fix. |
trackers[].onMapAt | string (date-time) | null | Its last fix that moved its vehicle on the map. |
trackers[].position | object | null | |
trackers[].batteryPct | number | null | |
trackers[].batteryV | number | null | |
trackers[].extVoltageV | number | null | |
trackers[].ignition | boolean | null | |
trackers[].sats | integer | null | |
trackers[].odometerM | number | null | |
trackers[].claimedAt | string (date-time) | |
trackers[].setup | object | The single tracker's: the SMS steps in order (key, sms, reply, optional), or a phone app's settings (value). |
trackers[].setup.protocol | string | |
trackers[].setup.host | string | |
trackers[].setup.port | integer | |
trackers[].setup.url | string | |
trackers[].setup.smsTo | string | |
trackers[].setup.assumed | boolean | |
trackers[].setup.steps | object[] | |
trackers[].setup.steps[].n | integer | |
trackers[].setup.steps[].key | string | |
trackers[].setup.steps[].sms | string | |
trackers[].setup.steps[].value | string | |
trackers[].setup.steps[].reply | string | |
trackers[].setup.steps[].optional | boolean | |
trackers[].diagnosis | string[] | What the gateway saw that needs fixing, most useful first. |
trackers[].virtual | VirtualTracker | |
trackers[].virtual.running | boolean | |
trackers[].virtual.protocol | string | |
trackers[].virtual.startedAt | string (date-time) | |
trackers[].virtual.until | string (date-time) | |
trackers[].virtual.sent | integer | |
trackers[].virtual.answered | integer | |
trackers[].virtual.problems | string[] | |
trackers[].virtual.error | string | |
counts | object | Required. |
models | object |
{
"trackers": [
{
"id": "trk_4fQ9xLm2Za",
"imei": "356307042441013",
"name": "string",
"vehicleId": "string",
"vehicleName": "string",
"protocol": "gt06",
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string",
"state": "awaiting_first_fix",
"connected": true,
"heard": true,
"lastSeenAt": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"onMapAt": "2026-10-15T09:00:00+01:00",
"position": {
"lat": 0,
"lng": 0,
"at": "2026-10-15T09:00:00+01:00"
},
"batteryPct": 0,
"batteryV": 0,
"extVoltageV": 0,
"ignition": true,
"sats": 0,
"odometerM": 0,
"claimedAt": "2026-10-15T09:00:00+01:00",
"setup": {
"protocol": "string",
"host": "string",
"port": 0,
"url": "string",
"smsTo": "string",
"assumed": true,
"steps": [
{}
]
},
"diagnosis": [
"no_vehicle"
],
"virtual": {
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}
}
],
"counts": {},
"models": {}
}Errors
defaultError
Add a tracker by its IMEI (first claim wins)
POST https://nways.ng/maps/v1/fleet/trackers
Errors: INVALID_IMEI (not 15 digits, or the Luhn check digit is wrong), INVALID_DEVICE_ID (a phone's id), TRACKER_EXISTS (already yours), TRACKER_CLAIMED_ELSEWHERE (another organisation holds it), VEHICLE_NOT_FOUND.
Request body
| Field | Type | Description |
|---|---|---|
imei | string | 15 digits (spaces and dashes are dropped); a phone's device id for model osmand-phone, a platform's unit id for model forwarded. |
name | string | |
vehicleId | string | One of your vehicles ("" to unlink). |
vehicle | object | A new vehicle for it, instead. |
vehicle.name | string | |
vehicle.mode | string | |
vehicle.plate | string | |
model | string | A catalogue model id, or not-sure (learned from its first connection). |
simNumber | string | |
network | string | A catalogue network id, or other. |
apn | string | Default: the network's. |
curl -X POST "https://nways.ng/maps/v1/fleet/trackers" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"imei":"356307042441013","vehicleId":"truck-12","model":"concox-gt06n","network":"mtn","simNumber":"+2348030000000"}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"imei": "356307042441013",
"vehicleId": "truck-12",
"model": "concox-gt06n",
"network": "mtn",
"simNumber": "+2348030000000"
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"imei": "356307042441013", "vehicleId": "truck-12", "model": "concox-gt06n", "network": "mtn", "simNumber": "+2348030000000"},
timeout=10,
)
data = res.json()Response
Added
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
name | string | |
vehicleId | string | null | |
vehicleName | string | |
protocol | string | A protocol N-Ways' gateway reads (gt06, teltonika, h02, gps103, tk103, gl200, meitrack, ruptela, jt808, suntech, galileo, startek, topin, xexun, gosafe, tzone, wialon, watch, osmand), forward for a unit forwarded from your tracking platform, or "" until its model or first connection says. |
model | string | |
simNumber | string | |
network | string | |
apn | string | |
state | string | One of: awaiting_first_fix, live, silent. |
connected | boolean | |
heard | boolean | N-Ways' gateway has heard this device (even before it was added). |
lastSeenAt | string (date-time) | null | |
lastFixAt | string (date-time) | null | Its last GPS fix. |
onMapAt | string (date-time) | null | Its last fix that moved its vehicle on the map. |
position | object | null | |
batteryPct | number | null | |
batteryV | number | null | |
extVoltageV | number | null | |
ignition | boolean | null | |
sats | integer | null | |
odometerM | number | null | |
claimedAt | string (date-time) | |
setup | object | The single tracker's: the SMS steps in order (key, sms, reply, optional), or a phone app's settings (value). |
setup.protocol | string | |
setup.host | string | |
setup.port | integer | |
setup.url | string | |
setup.smsTo | string | |
setup.assumed | boolean | |
setup.steps | object[] | |
setup.steps[].n | integer | |
setup.steps[].key | string | |
setup.steps[].sms | string | |
setup.steps[].value | string | |
setup.steps[].reply | string | |
setup.steps[].optional | boolean | |
diagnosis | string[] | What the gateway saw that needs fixing, most useful first. |
virtual | VirtualTracker | |
virtual.running | boolean | |
virtual.protocol | string | |
virtual.startedAt | string (date-time) | |
virtual.until | string (date-time) | |
virtual.sent | integer | |
virtual.answered | integer | |
virtual.problems | string[] | |
virtual.error | string |
{
"id": "trk_4fQ9xLm2Za",
"imei": "356307042441013",
"name": "string",
"vehicleId": "string",
"vehicleName": "string",
"protocol": "gt06",
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string",
"state": "awaiting_first_fix",
"connected": true,
"heard": true,
"lastSeenAt": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"onMapAt": "2026-10-15T09:00:00+01:00",
"position": {
"lat": 0,
"lng": 0,
"at": "2026-10-15T09:00:00+01:00"
},
"batteryPct": 0,
"batteryV": 0,
"extVoltageV": 0,
"ignition": true,
"sats": 0,
"odometerM": 0,
"claimedAt": "2026-10-15T09:00:00+01:00",
"setup": {
"protocol": "string",
"host": "string",
"port": 0,
"url": "string",
"smsTo": "string",
"assumed": true,
"steps": [
{
"n": 0,
"key": "string",
"sms": "string",
"value": "string",
"reply": "string",
"optional": true
}
]
},
"diagnosis": [
"no_vehicle"
],
"virtual": {
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}
}Errors
defaultError
The device catalogue, your country's SIM networks and their APNs, and where devices report
GET https://nways.ng/maps/v1/fleet/trackers/catalog
models: every model (with status supported | coming, its methods and family), then forwarded and not-sure. brands, families, protocols, counts: as GET https://nways.ng/v1/trackers/catalogue. networks: your country's; unverified: an APN from a public listing not yet checked on a real SIM.
curl "https://nways.ng/maps/v1/fleet/trackers/catalog" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/catalog', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/catalog",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Catalogue
| Field | Type | Description |
|---|---|---|
models | TrackerModel[] | |
models[].id | string | |
models[].brand | string | |
models[].brandId | string | |
models[].name | string | |
models[].protocol | string | |
models[].family | string | Its command set (setup SMS, configurator, commands). |
models[].kind | string | One of: vehicle, asset, personal, obd, phone. |
models[].password | string | The SMS password it ships with. |
models[].popular | boolean | |
models[].status | string | One of: supported, coming. |
models[].methods | string[] | |
brands | object[] | |
families | object | |
protocols | object[] | |
protocols[].id | string | |
protocols[].name | string | |
protocols[].status | string | One of: supported, coming. |
protocols[].port | integer | |
networks | object[] | |
networks[].id | string | |
networks[].name | string | |
networks[].apn | string | |
networks[].user | string | |
networks[].pass | string | |
networks[].unverified | boolean | |
country | string | |
host | string | |
ports | object | |
osmandUrl | string | |
platforms | string[] | |
commandKinds | string[] |
{
"models": [
{
"id": "concox-gt06n",
"brand": "Concox",
"brandId": "string",
"name": "GT06N",
"protocol": "gt06",
"family": "string",
"kind": "vehicle",
"password": "string",
"popular": true,
"status": "supported",
"methods": [
"sms"
]
}
],
"brands": [
{}
],
"families": {},
"protocols": [
{
"id": "string",
"name": "string",
"status": "supported",
"port": 0
}
],
"networks": [
{
"id": "string",
"name": "string",
"apn": "string",
"user": "string",
"pass": "string",
"unverified": true
}
],
"country": "string",
"host": "trk.nways.ng",
"ports": {},
"osmandUrl": "string",
"platforms": [
"string"
],
"commandKinds": [
"string"
]
}Errors
defaultError
Add many trackers from a CSV (check it first with dryRun)
POST https://nways.ng/maps/v1/fleet/trackers/import
Columns by header, any order, commas or semicolons: imei, vehicle (one of yours by id, name or plate, or a new one by that name), model (a catalogue id or "Brand Model"; empty: not sure), sim, network, and optionally apn, name, plate, type. At most 1,000 rows. Each row says what's wrong (issues: imei_missing, imei_invalid, imei_check_digit, imei_duplicate, imei_yours, imei_elsewhere, model_unknown, network_unknown, vehicle_missing, mode_unknown); with dryRun false the good rows are added and the rest left out.
Request body
| Field | Type | Description |
|---|---|---|
csv | string | Required. |
dryRun | boolean |
curl -X POST "https://nways.ng/maps/v1/fleet/trackers/import" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"csv":"imei,vehicle,model,sim,network\n356307042441013,Hiace 2,Concox GT06N,08030000000,MTN\n","dryRun":true}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/import', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"csv": "imei,vehicle,model,sim,network\n356307042441013,Hiace 2,Concox GT06N,08030000000,MTN\n",
"dryRun": true
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers/import",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"csv": "imei,vehicle,model,sim,network\n356307042441013,Hiace 2,Concox GT06N, 08030000000,MTN\n", "dryRun": True},
timeout=10,
)
data = res.json()Response
Each row
| Field | Type | Description |
|---|---|---|
rows | object[] | |
rows[].row | integer | |
rows[].imei | string | |
rows[].model | string | |
rows[].network | string | |
rows[].simNumber | string | |
rows[].vehicle | string | |
rows[].vehicleId | string | |
rows[].newVehicle | boolean | |
rows[].ok | boolean | |
rows[].trackerId | string | |
rows[].issues | object[] | |
rows[].issues[].field | string | |
rows[].issues[].code | string | |
rows[].issues[].message | string | |
total | integer | |
ok | integer | |
bad | integer | |
added | integer | |
dryRun | boolean |
{
"rows": [
{
"row": 0,
"imei": "string",
"model": "string",
"network": "string",
"simNumber": "string",
"vehicle": "string",
"vehicleId": "string",
"newVehicle": true,
"ok": true,
"trackerId": "string",
"issues": [
{
"field": "string",
"code": "string",
"message": "string"
}
]
}
],
"total": 0,
"ok": 0,
"bad": 0,
"added": 0,
"dryRun": true
}Errors
defaultError
The installers' sheet, every tracker's setup SMS in order (CSV)
GET https://nways.ng/maps/v1/fleet/trackers/setup.csv
Parameters
| Name | In | Type | Description |
|---|---|---|---|
ids | query | string | Tracker ids, comma-separated. Default: the trackers not on the map yet. |
lang | query | string | One of: en, fr, pt. Default: en. |
curl "https://nways.ng/maps/v1/fleet/trackers/setup.csv" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/setup.csv', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/setup.csv",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
One line per SMS: IMEI, tracker, vehicle, model, SIM number, step, what to do, SMS, answer.
Errors
defaultError
Forwarding from your tracking platform, its addresses, and the units it sends
GET https://nways.ng/maps/v1/fleet/trackers/forwarding
curl "https://nways.ng/maps/v1/fleet/trackers/forwarding" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/forwarding', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/forwarding",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Forwarding
| Field | Type | Description |
|---|---|---|
enabled | boolean | |
token | string | null | The key in your addresses: keep it secret. |
urls | object | null | |
urls.traccar | string | |
urls.osmand | string | |
urls.flespi | string | |
urls.webhook | string | |
urls.bearer | string | |
wialon | object | |
wialon.host | string | |
wialon.port | integer | |
wialon.password | string | |
wialon.status | string | One of: supported, coming. |
units | object[] | |
units[].unitId | string | |
units[].source | string | One of: traccar, osmand, flespi, webhook, wialon. |
units[].name | string | |
units[].firstSeen | string (date-time) | |
units[].lastSeen | string (date-time) | |
units[].lastFixAt | string (date-time) | null | |
units[].position | object | null | |
units[].received | integer | |
units[].trackerId | string | Set once it's one of your trackers. |
units[].trackerName | string | |
units[].elsewhere | boolean | Another organisation holds this IMEI. |
units[].lastPayload | object | What the platform sent last (units not added yet). |
lastAt | string (date-time) | null | |
lastBySource | object | |
unknown | integer | Units not added yet. |
units24h | integer |
{
"enabled": true,
"token": "fwd_8KwP2nVd5T…",
"urls": {
"traccar": "string",
"osmand": "string",
"flespi": "string",
"webhook": "string",
"bearer": "string"
},
"wialon": {
"host": "string",
"port": 0,
"password": "string",
"status": "supported"
},
"units": [
{
"unitId": "string",
"source": "traccar",
"name": "string",
"firstSeen": "2026-10-15T09:00:00+01:00",
"lastSeen": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"position": {},
"received": 0,
"trackerId": "string",
"trackerName": "string",
"elsewhere": true,
"lastPayload": {}
}
],
"lastAt": "2026-10-15T09:00:00+01:00",
"lastBySource": {},
"unknown": 0,
"units24h": 0
}Errors
defaultError
Turn forwarding on, or give it a new token (the old one stops at once)
POST https://nways.ng/maps/v1/fleet/trackers/forwarding
curl -X POST "https://nways.ng/maps/v1/fleet/trackers/forwarding" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/forwarding', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers/forwarding",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Forwarding
| Field | Type | Description |
|---|---|---|
enabled | boolean | |
token | string | null | The key in your addresses: keep it secret. |
urls | object | null | |
urls.traccar | string | |
urls.osmand | string | |
urls.flespi | string | |
urls.webhook | string | |
urls.bearer | string | |
wialon | object | |
wialon.host | string | |
wialon.port | integer | |
wialon.password | string | |
wialon.status | string | One of: supported, coming. |
units | object[] | |
units[].unitId | string | |
units[].source | string | One of: traccar, osmand, flespi, webhook, wialon. |
units[].name | string | |
units[].firstSeen | string (date-time) | |
units[].lastSeen | string (date-time) | |
units[].lastFixAt | string (date-time) | null | |
units[].position | object | null | |
units[].received | integer | |
units[].trackerId | string | Set once it's one of your trackers. |
units[].trackerName | string | |
units[].elsewhere | boolean | Another organisation holds this IMEI. |
units[].lastPayload | object | What the platform sent last (units not added yet). |
lastAt | string (date-time) | null | |
lastBySource | object | |
unknown | integer | Units not added yet. |
units24h | integer |
{
"enabled": true,
"token": "fwd_8KwP2nVd5T…",
"urls": {
"traccar": "string",
"osmand": "string",
"flespi": "string",
"webhook": "string",
"bearer": "string"
},
"wialon": {
"host": "string",
"port": 0,
"password": "string",
"status": "supported"
},
"units": [
{
"unitId": "string",
"source": "traccar",
"name": "string",
"firstSeen": "2026-10-15T09:00:00+01:00",
"lastSeen": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"position": {},
"received": 0,
"trackerId": "string",
"trackerName": "string",
"elsewhere": true,
"lastPayload": {}
}
],
"lastAt": "2026-10-15T09:00:00+01:00",
"lastBySource": {},
"unknown": 0,
"units24h": 0
}Errors
defaultError
Turn forwarding off (the units stay listed)
DELETE https://nways.ng/maps/v1/fleet/trackers/forwarding
curl -X DELETE "https://nways.ng/maps/v1/fleet/trackers/forwarding" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/forwarding', {
method: 'DELETE',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.delete(
"https://nways.ng/maps/v1/fleet/trackers/forwarding",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Forwarding
| Field | Type | Description |
|---|---|---|
enabled | boolean | |
token | string | null | The key in your addresses: keep it secret. |
urls | object | null | |
urls.traccar | string | |
urls.osmand | string | |
urls.flespi | string | |
urls.webhook | string | |
urls.bearer | string | |
wialon | object | |
wialon.host | string | |
wialon.port | integer | |
wialon.password | string | |
wialon.status | string | One of: supported, coming. |
units | object[] | |
units[].unitId | string | |
units[].source | string | One of: traccar, osmand, flespi, webhook, wialon. |
units[].name | string | |
units[].firstSeen | string (date-time) | |
units[].lastSeen | string (date-time) | |
units[].lastFixAt | string (date-time) | null | |
units[].position | object | null | |
units[].received | integer | |
units[].trackerId | string | Set once it's one of your trackers. |
units[].trackerName | string | |
units[].elsewhere | boolean | Another organisation holds this IMEI. |
units[].lastPayload | object | What the platform sent last (units not added yet). |
lastAt | string (date-time) | null | |
lastBySource | object | |
unknown | integer | Units not added yet. |
units24h | integer |
{
"enabled": true,
"token": "fwd_8KwP2nVd5T…",
"urls": {
"traccar": "string",
"osmand": "string",
"flespi": "string",
"webhook": "string",
"bearer": "string"
},
"wialon": {
"host": "string",
"port": 0,
"password": "string",
"status": "supported"
},
"units": [
{
"unitId": "string",
"source": "traccar",
"name": "string",
"firstSeen": "2026-10-15T09:00:00+01:00",
"lastSeen": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"position": {},
"received": 0,
"trackerId": "string",
"trackerName": "string",
"elsewhere": true,
"lastPayload": {}
}
],
"lastAt": "2026-10-15T09:00:00+01:00",
"lastBySource": {},
"unknown": 0,
"units24h": 0
}Errors
defaultError
Add a forwarded unit as one of your trackers (a new vehicle named after it, unless you give one)
POST https://nways.ng/maps/v1/fleet/trackers/forwarding/units/{unitId}/add
Parameters
| Name | In | Type | Description |
|---|---|---|---|
unitId | path | string | Required. |
Request body
| Field | Type | Description |
|---|---|---|
imei | string | 15 digits (spaces and dashes are dropped); a phone's device id for model osmand-phone, a platform's unit id for model forwarded. |
name | string | |
vehicleId | string | One of your vehicles ("" to unlink). |
vehicle | object | A new vehicle for it, instead. |
vehicle.name | string | |
vehicle.mode | string | |
vehicle.plate | string | |
model | string | A catalogue model id, or not-sure (learned from its first connection). |
simNumber | string | |
network | string | A catalogue network id, or other. |
apn | string | Default: the network's. |
curl -X POST "https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string/add" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"imei":"string","name":"string","vehicleId":"string","vehicle":{"name":"string","mode":"string","plate":"string"},"model":"string","simNumber":"string","network":"string","apn":"string"}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string/add', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"imei": "string",
"name": "string",
"vehicleId": "string",
"vehicle": {
"name": "string",
"mode": "string",
"plate": "string"
},
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string"
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string/add",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"imei": "string", "name": "string", "vehicleId": "string", "vehicle": {"name": "string", "mode": "string", "plate": "string"}, "model": "string", "simNumber": "string", "network": "string", "apn": "string"},
timeout=10,
)
data = res.json()Response
Added
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
name | string | |
vehicleId | string | null | |
vehicleName | string | |
protocol | string | A protocol N-Ways' gateway reads (gt06, teltonika, h02, gps103, tk103, gl200, meitrack, ruptela, jt808, suntech, galileo, startek, topin, xexun, gosafe, tzone, wialon, watch, osmand), forward for a unit forwarded from your tracking platform, or "" until its model or first connection says. |
model | string | |
simNumber | string | |
network | string | |
apn | string | |
state | string | One of: awaiting_first_fix, live, silent. |
connected | boolean | |
heard | boolean | N-Ways' gateway has heard this device (even before it was added). |
lastSeenAt | string (date-time) | null | |
lastFixAt | string (date-time) | null | Its last GPS fix. |
onMapAt | string (date-time) | null | Its last fix that moved its vehicle on the map. |
position | object | null | |
batteryPct | number | null | |
batteryV | number | null | |
extVoltageV | number | null | |
ignition | boolean | null | |
sats | integer | null | |
odometerM | number | null | |
claimedAt | string (date-time) | |
setup | object | The single tracker's: the SMS steps in order (key, sms, reply, optional), or a phone app's settings (value). |
setup.protocol | string | |
setup.host | string | |
setup.port | integer | |
setup.url | string | |
setup.smsTo | string | |
setup.assumed | boolean | |
setup.steps | object[] | |
setup.steps[].n | integer | |
setup.steps[].key | string | |
setup.steps[].sms | string | |
setup.steps[].value | string | |
setup.steps[].reply | string | |
setup.steps[].optional | boolean | |
diagnosis | string[] | What the gateway saw that needs fixing, most useful first. |
virtual | VirtualTracker | |
virtual.running | boolean | |
virtual.protocol | string | |
virtual.startedAt | string (date-time) | |
virtual.until | string (date-time) | |
virtual.sent | integer | |
virtual.answered | integer | |
virtual.problems | string[] | |
virtual.error | string |
{
"id": "trk_4fQ9xLm2Za",
"imei": "356307042441013",
"name": "string",
"vehicleId": "string",
"vehicleName": "string",
"protocol": "gt06",
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string",
"state": "awaiting_first_fix",
"connected": true,
"heard": true,
"lastSeenAt": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"onMapAt": "2026-10-15T09:00:00+01:00",
"position": {
"lat": 0,
"lng": 0,
"at": "2026-10-15T09:00:00+01:00"
},
"batteryPct": 0,
"batteryV": 0,
"extVoltageV": 0,
"ignition": true,
"sats": 0,
"odometerM": 0,
"claimedAt": "2026-10-15T09:00:00+01:00",
"setup": {
"protocol": "string",
"host": "string",
"port": 0,
"url": "string",
"smsTo": "string",
"assumed": true,
"steps": [
{
"n": 0,
"key": "string",
"sms": "string",
"value": "string",
"reply": "string",
"optional": true
}
]
},
"diagnosis": [
"no_vehicle"
],
"virtual": {
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}
}Errors
defaultError
Forget a forwarded unit (it comes back if your platform sends it again)
DELETE https://nways.ng/maps/v1/fleet/trackers/forwarding/units/{unitId}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
unitId | path | string | Required. |
curl -X DELETE "https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string', {
method: 'DELETE',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.delete(
"https://nways.ng/maps/v1/fleet/trackers/forwarding/units/string",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Forgotten
Errors
defaultError
Your requests to move trackers here, and trackers that moved away
GET https://nways.ng/maps/v1/fleet/tracker-transfers
curl "https://nways.ng/maps/v1/fleet/tracker-transfers" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/tracker-transfers', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/tracker-transfers",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Transfers
| Field | Type | Description |
|---|---|---|
transfers | TrackerTransfer[] | |
transfers[].id | string | |
transfers[].imei | string | |
transfers[].direction | string | One of: in, out. |
transfers[].state | string | One of: pending, waiting, moved, expired, cancelled. |
transfers[].vehicleId | string | null | |
transfers[].restartSms | string | What to send the device so it logs in afresh. |
transfers[].createdAt | string (date-time) | |
transfers[].startedAt | string (date-time) | null | |
transfers[].expiresAt | string (date-time) | null | |
transfers[].movedAt | string (date-time) | null | |
transfers[].trackerId | string | |
windowS | integer |
{
"transfers": [
{
"id": "trf_4fQ9xLm2Za",
"imei": "string",
"direction": "in",
"state": "pending",
"vehicleId": "string",
"restartSms": "string",
"createdAt": "2026-10-15T09:00:00+01:00",
"startedAt": "2026-10-15T09:00:00+01:00",
"expiresAt": "2026-10-15T09:00:00+01:00",
"movedAt": "2026-10-15T09:00:00+01:00",
"trackerId": "string"
}
],
"windowS": 180
}Errors
defaultError
Ask for a tracker another organisation holds (owners and admins)
POST https://nways.ng/maps/v1/fleet/tracker-transfers
Errors: TRACKER_NOT_CLAIMED (nobody holds it: add it), TRACKER_EXISTS (yours already), TRANSFER_NOT_PROVABLE (a phone or forwarded unit: its organisation removes it).
Request body
| Field | Type | Description |
|---|---|---|
imei | string | Required. |
vehicleId | string |
curl -X POST "https://nways.ng/maps/v1/fleet/tracker-transfers" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"imei":"string","vehicleId":"string"}'const res = await fetch('https://nways.ng/maps/v1/fleet/tracker-transfers', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"imei": "string",
"vehicleId": "string"
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/tracker-transfers",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"imei": "string", "vehicleId": "string"},
timeout=10,
)
data = res.json()Response
Asked
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
direction | string | One of: in, out. |
state | string | One of: pending, waiting, moved, expired, cancelled. |
vehicleId | string | null | |
restartSms | string | What to send the device so it logs in afresh. |
createdAt | string (date-time) | |
startedAt | string (date-time) | null | |
expiresAt | string (date-time) | null | |
movedAt | string (date-time) | null | |
trackerId | string |
{
"id": "trf_4fQ9xLm2Za",
"imei": "string",
"direction": "in",
"state": "pending",
"vehicleId": "string",
"restartSms": "string",
"createdAt": "2026-10-15T09:00:00+01:00",
"startedAt": "2026-10-15T09:00:00+01:00",
"expiresAt": "2026-10-15T09:00:00+01:00",
"movedAt": "2026-10-15T09:00:00+01:00",
"trackerId": "string"
}Errors
defaultError
You're making the device log in afresh now (its restart SMS); a fresh login within 3 minutes moves it
POST https://nways.ng/maps/v1/fleet/tracker-transfers/{transferId}/start
Parameters
| Name | In | Type | Description |
|---|---|---|---|
transferId | path | string | Required. |
curl -X POST "https://nways.ng/maps/v1/fleet/tracker-transfers/trf_4fQ9xLm2Za/start" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/tracker-transfers/trf_4fQ9xLm2Za/start', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/tracker-transfers/trf_4fQ9xLm2Za/start",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Waiting
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
direction | string | One of: in, out. |
state | string | One of: pending, waiting, moved, expired, cancelled. |
vehicleId | string | null | |
restartSms | string | What to send the device so it logs in afresh. |
createdAt | string (date-time) | |
startedAt | string (date-time) | null | |
expiresAt | string (date-time) | null | |
movedAt | string (date-time) | null | |
trackerId | string |
{
"id": "trf_4fQ9xLm2Za",
"imei": "string",
"direction": "in",
"state": "pending",
"vehicleId": "string",
"restartSms": "string",
"createdAt": "2026-10-15T09:00:00+01:00",
"startedAt": "2026-10-15T09:00:00+01:00",
"expiresAt": "2026-10-15T09:00:00+01:00",
"movedAt": "2026-10-15T09:00:00+01:00",
"trackerId": "string"
}Errors
defaultError
Withdraw a request
DELETE https://nways.ng/maps/v1/fleet/tracker-transfers/{transferId}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
transferId | path | string | Required. |
curl -X DELETE "https://nways.ng/maps/v1/fleet/tracker-transfers/string" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/tracker-transfers/string', {
method: 'DELETE',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.delete(
"https://nways.ng/maps/v1/fleet/tracker-transfers/string",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Withdrawn
Errors
defaultError
Get a tracker, its setup steps and what's wrong
GET https://nways.ng/maps/v1/fleet/trackers/{trackerId}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. Its id, or its IMEI. |
curl "https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Tracker
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
name | string | |
vehicleId | string | null | |
vehicleName | string | |
protocol | string | A protocol N-Ways' gateway reads (gt06, teltonika, h02, gps103, tk103, gl200, meitrack, ruptela, jt808, suntech, galileo, startek, topin, xexun, gosafe, tzone, wialon, watch, osmand), forward for a unit forwarded from your tracking platform, or "" until its model or first connection says. |
model | string | |
simNumber | string | |
network | string | |
apn | string | |
state | string | One of: awaiting_first_fix, live, silent. |
connected | boolean | |
heard | boolean | N-Ways' gateway has heard this device (even before it was added). |
lastSeenAt | string (date-time) | null | |
lastFixAt | string (date-time) | null | Its last GPS fix. |
onMapAt | string (date-time) | null | Its last fix that moved its vehicle on the map. |
position | object | null | |
batteryPct | number | null | |
batteryV | number | null | |
extVoltageV | number | null | |
ignition | boolean | null | |
sats | integer | null | |
odometerM | number | null | |
claimedAt | string (date-time) | |
setup | object | The single tracker's: the SMS steps in order (key, sms, reply, optional), or a phone app's settings (value). |
setup.protocol | string | |
setup.host | string | |
setup.port | integer | |
setup.url | string | |
setup.smsTo | string | |
setup.assumed | boolean | |
setup.steps | object[] | |
setup.steps[].n | integer | |
setup.steps[].key | string | |
setup.steps[].sms | string | |
setup.steps[].value | string | |
setup.steps[].reply | string | |
setup.steps[].optional | boolean | |
diagnosis | string[] | What the gateway saw that needs fixing, most useful first. |
virtual | VirtualTracker | |
virtual.running | boolean | |
virtual.protocol | string | |
virtual.startedAt | string (date-time) | |
virtual.until | string (date-time) | |
virtual.sent | integer | |
virtual.answered | integer | |
virtual.problems | string[] | |
virtual.error | string |
{
"id": "trk_4fQ9xLm2Za",
"imei": "356307042441013",
"name": "string",
"vehicleId": "string",
"vehicleName": "string",
"protocol": "gt06",
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string",
"state": "awaiting_first_fix",
"connected": true,
"heard": true,
"lastSeenAt": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"onMapAt": "2026-10-15T09:00:00+01:00",
"position": {
"lat": 0,
"lng": 0,
"at": "2026-10-15T09:00:00+01:00"
},
"batteryPct": 0,
"batteryV": 0,
"extVoltageV": 0,
"ignition": true,
"sats": 0,
"odometerM": 0,
"claimedAt": "2026-10-15T09:00:00+01:00",
"setup": {
"protocol": "string",
"host": "string",
"port": 0,
"url": "string",
"smsTo": "string",
"assumed": true,
"steps": [
{
"n": 0,
"key": "string",
"sms": "string",
"value": "string",
"reply": "string",
"optional": true
}
]
},
"diagnosis": [
"no_vehicle"
],
"virtual": {
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}
}Errors
defaultError
Edit a tracker (its vehicle, model, SIM)
PATCH https://nways.ng/maps/v1/fleet/trackers/{trackerId}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. Its id, or its IMEI. |
Request body
| Field | Type | Description |
|---|---|---|
imei | string | 15 digits (spaces and dashes are dropped); a phone's device id for model osmand-phone, a platform's unit id for model forwarded. |
name | string | |
vehicleId | string | One of your vehicles ("" to unlink). |
vehicle | object | A new vehicle for it, instead. |
vehicle.name | string | |
vehicle.mode | string | |
vehicle.plate | string | |
model | string | A catalogue model id, or not-sure (learned from its first connection). |
simNumber | string | |
network | string | A catalogue network id, or other. |
apn | string | Default: the network's. |
curl -X PATCH "https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"imei":"string","name":"string","vehicleId":"string","vehicle":{"name":"string","mode":"string","plate":"string"},"model":"string","simNumber":"string","network":"string","apn":"string"}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za', {
method: 'PATCH',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"imei": "string",
"name": "string",
"vehicleId": "string",
"vehicle": {
"name": "string",
"mode": "string",
"plate": "string"
},
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string"
}),
})
const data = await res.json()import os
import requests
res = requests.patch(
"https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"imei": "string", "name": "string", "vehicleId": "string", "vehicle": {"name": "string", "mode": "string", "plate": "string"}, "model": "string", "simNumber": "string", "network": "string", "apn": "string"},
timeout=10,
)
data = res.json()Response
Tracker
| Field | Type | Description |
|---|---|---|
id | string | |
imei | string | |
name | string | |
vehicleId | string | null | |
vehicleName | string | |
protocol | string | A protocol N-Ways' gateway reads (gt06, teltonika, h02, gps103, tk103, gl200, meitrack, ruptela, jt808, suntech, galileo, startek, topin, xexun, gosafe, tzone, wialon, watch, osmand), forward for a unit forwarded from your tracking platform, or "" until its model or first connection says. |
model | string | |
simNumber | string | |
network | string | |
apn | string | |
state | string | One of: awaiting_first_fix, live, silent. |
connected | boolean | |
heard | boolean | N-Ways' gateway has heard this device (even before it was added). |
lastSeenAt | string (date-time) | null | |
lastFixAt | string (date-time) | null | Its last GPS fix. |
onMapAt | string (date-time) | null | Its last fix that moved its vehicle on the map. |
position | object | null | |
batteryPct | number | null | |
batteryV | number | null | |
extVoltageV | number | null | |
ignition | boolean | null | |
sats | integer | null | |
odometerM | number | null | |
claimedAt | string (date-time) | |
setup | object | The single tracker's: the SMS steps in order (key, sms, reply, optional), or a phone app's settings (value). |
setup.protocol | string | |
setup.host | string | |
setup.port | integer | |
setup.url | string | |
setup.smsTo | string | |
setup.assumed | boolean | |
setup.steps | object[] | |
setup.steps[].n | integer | |
setup.steps[].key | string | |
setup.steps[].sms | string | |
setup.steps[].value | string | |
setup.steps[].reply | string | |
setup.steps[].optional | boolean | |
diagnosis | string[] | What the gateway saw that needs fixing, most useful first. |
virtual | VirtualTracker | |
virtual.running | boolean | |
virtual.protocol | string | |
virtual.startedAt | string (date-time) | |
virtual.until | string (date-time) | |
virtual.sent | integer | |
virtual.answered | integer | |
virtual.problems | string[] | |
virtual.error | string |
{
"id": "trk_4fQ9xLm2Za",
"imei": "356307042441013",
"name": "string",
"vehicleId": "string",
"vehicleName": "string",
"protocol": "gt06",
"model": "string",
"simNumber": "string",
"network": "string",
"apn": "string",
"state": "awaiting_first_fix",
"connected": true,
"heard": true,
"lastSeenAt": "2026-10-15T09:00:00+01:00",
"lastFixAt": "2026-10-15T09:00:00+01:00",
"onMapAt": "2026-10-15T09:00:00+01:00",
"position": {
"lat": 0,
"lng": 0,
"at": "2026-10-15T09:00:00+01:00"
},
"batteryPct": 0,
"batteryV": 0,
"extVoltageV": 0,
"ignition": true,
"sats": 0,
"odometerM": 0,
"claimedAt": "2026-10-15T09:00:00+01:00",
"setup": {
"protocol": "string",
"host": "string",
"port": 0,
"url": "string",
"smsTo": "string",
"assumed": true,
"steps": [
{
"n": 0,
"key": "string",
"sms": "string",
"value": "string",
"reply": "string",
"optional": true
}
]
},
"diagnosis": [
"no_vehicle"
],
"virtual": {
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}
}Errors
defaultError
Remove a tracker (it can then be added by anyone)
DELETE https://nways.ng/maps/v1/fleet/trackers/{trackerId}
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. Its id, or its IMEI. |
curl -X DELETE "https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za', {
method: 'DELETE',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.delete(
"https://nways.ng/maps/v1/fleet/trackers/trk_4fQ9xLm2Za",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Removed
Errors
defaultError
The device log (connections, raw frames, decoded fields, answers sent, errors), oldest first
GET https://nways.ng/maps/v1/fleet/trackers/{trackerId}/log
The last 500 entries and 7 days are kept. Without after, the last limit entries.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
after | query | string | An entry id: only later entries. |
limit | query | integer | Default: 200. ≤ 500. |
curl "https://nways.ng/maps/v1/fleet/trackers/string/log" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/log', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/string/log",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Entries
| Field | Type | Description |
|---|---|---|
entries | TrackerLogEntry[] | |
entries[].id | string | A cursor: later entries have larger ones. |
entries[].at | string (date-time) | |
entries[].dir | string | One of: in, out, note. |
entries[].kind | string | login, position, heartbeat, alarm, status, handshake, unknown, ack, connect, disconnect, noise, refused |
entries[].hex | string | |
entries[].ascii | string | |
entries[].decoded | object | |
entries[].error | string | |
entries[].remote | string |
{
"entries": [
{
"id": "string",
"at": "2026-10-15T09:00:00+01:00",
"dir": "in",
"kind": "string",
"hex": "string",
"ascii": "string",
"decoded": {},
"error": "string",
"remote": "string"
}
]
}Errors
defaultError
The device log and state as they change (server-sent events)
GET https://nways.ng/maps/v1/fleet/trackers/{trackerId}/stream
event: state (the Tracker) and event: log (a TrackerLogEntry), starting with the state and the last 50 entries (or those after ?after=). A comment every 15 s keeps it open.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
curl "https://nways.ng/maps/v1/fleet/trackers/string/stream" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/stream', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/string/stream",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
An event stream
Errors
defaultError
Drive a virtual tracker for this one (its own protocol, through N-Ways' gateway)
POST https://nways.ng/maps/v1/fleet/trackers/{trackerId}/virtual
A short road in your country, a position every 3 s, answers checked byte for byte. Faults to try: noAckWait, badCrc, invalidFix, clockSkewH (8: a tracker on China time), backlog. Errors: VIRTUAL_RUNNING, TRACKER_NO_VEHICLE, TRACKER_CONNECTED (the real one is connected), VIRTUAL_TRACKER_UNAVAILABLE.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
Request body
| Field | Type | Description |
|---|---|---|
minutes | integer | Default: 3. ≥ 1, ≤ 10. |
sos | boolean | |
powerCut | boolean | |
noAckWait | boolean | |
badCrc | boolean | |
invalidFix | boolean | |
clockSkewH | number | |
backlog | integer | ≤ 50. |
lang | string |
curl -X POST "https://nways.ng/maps/v1/fleet/trackers/string/virtual" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"minutes":3,"sos":true,"powerCut":true,"noAckWait":true,"badCrc":true,"invalidFix":true,"clockSkewH":0,"backlog":0,"lang":"string"}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/virtual', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"minutes": 3,
"sos": true,
"powerCut": true,
"noAckWait": true,
"badCrc": true,
"invalidFix": true,
"clockSkewH": 0,
"backlog": 0,
"lang": "string"
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers/string/virtual",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"minutes": 3, "sos": True, "powerCut": True, "noAckWait": True, "badCrc": True, "invalidFix": True, "clockSkewH": 0, "backlog": 0, "lang": "string"},
timeout=10,
)
data = res.json()Response
Started
| Field | Type | Description |
|---|---|---|
running | boolean | |
protocol | string | |
startedAt | string (date-time) | |
until | string (date-time) | |
sent | integer | |
answered | integer | |
problems | string[] | |
error | string |
{
"running": true,
"protocol": "string",
"startedAt": "2026-10-15T09:00:00+01:00",
"until": "2026-10-15T09:00:00+01:00",
"sent": 0,
"answered": 0,
"problems": [
"string"
],
"error": "string"
}Errors
defaultError
Stop its virtual tracker
DELETE https://nways.ng/maps/v1/fleet/trackers/{trackerId}/virtual
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
curl -X DELETE "https://nways.ng/maps/v1/fleet/trackers/string/virtual" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/virtual', {
method: 'DELETE',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.delete(
"https://nways.ng/maps/v1/fleet/trackers/string/virtual",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Stopped
Errors
defaultError
Commands sent to a tracker (the last 30), and which it takes
GET https://nways.ng/maps/v1/fleet/trackers/{trackerId}/commands
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
curl "https://nways.ng/maps/v1/fleet/trackers/string/commands" \
-H "X-NWays-Api-Key: YOUR_API_KEY"const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/commands', {
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY },
})
const data = await res.json()import os
import requests
res = requests.get(
"https://nways.ng/maps/v1/fleet/trackers/string/commands",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
timeout=10,
)
data = res.json()Response
Commands
| Field | Type | Description |
|---|---|---|
commands | TrackerCommand[] | |
commands[].id | string | |
commands[].kind | string | One of: locate, restart, interval, heartbeat. |
commands[].seconds | integer | |
commands[].state | string | offline and sms: send the SMS instead. One of: sent, answered, offline, failed, sms. |
commands[].text | string | The command over the connection. |
commands[].sms | string | The same as an SMS. |
commands[].smsTo | string | |
commands[].reply | string | What the device answered. |
commands[].error | string | |
commands[].createdBy | string | |
commands[].createdAt | string (date-time) | |
commands[].sentAt | string (date-time) | null | |
commands[].answeredAt | string (date-time) | null | |
kinds | object | Each command it takes: over its connection (gprs) or by SMS only. |
connected | boolean |
{
"commands": [
{
"id": "cmd_4fQ9xLm2Za",
"kind": "locate",
"seconds": 0,
"state": "sent",
"text": "string",
"sms": "string",
"smsTo": "string",
"reply": "string",
"error": "string",
"createdBy": "string",
"createdAt": "2026-10-15T09:00:00+01:00",
"sentAt": "2026-10-15T09:00:00+01:00",
"answeredAt": "2026-10-15T09:00:00+01:00"
}
],
"kinds": {},
"connected": true
}Errors
defaultError
Send a command (owners and admins); its answer comes in the device log
POST https://nways.ng/maps/v1/fleet/trackers/{trackerId}/commands
Connected and its protocol takes it over the connection: sent, then answered. Otherwise: offline or sms, with the SMS to send it (sms, smsTo). Errors: COMMAND_NOT_SUPPORTED, COMMANDS_NOT_SUPPORTED (a phone or forwarded unit).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
trackerId | path | string | Required. |
Request body
| Field | Type | Description |
|---|---|---|
kind | string | Required. One of: locate, restart, interval, heartbeat. |
seconds | integer | interval: 5–3600; heartbeat: 60–3600 (whole minutes). |
curl -X POST "https://nways.ng/maps/v1/fleet/trackers/string/commands" \
-H "X-NWays-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind":"interval","seconds":30}'const res = await fetch('https://nways.ng/maps/v1/fleet/trackers/string/commands', {
method: 'POST',
headers: { 'X-NWays-Api-Key': process.env.NWAYS_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
"kind": "interval",
"seconds": 30
}),
})
const data = await res.json()import os
import requests
res = requests.post(
"https://nways.ng/maps/v1/fleet/trackers/string/commands",
headers={"X-NWays-Api-Key": os.environ["NWAYS_API_KEY"]},
json={"kind": "interval", "seconds": 30},
timeout=10,
)
data = res.json()Response
Sent (or the SMS to send)
| Field | Type | Description |
|---|---|---|
id | string | |
kind | string | One of: locate, restart, interval, heartbeat. |
seconds | integer | |
state | string | offline and sms: send the SMS instead. One of: sent, answered, offline, failed, sms. |
text | string | The command over the connection. |
sms | string | The same as an SMS. |
smsTo | string | |
reply | string | What the device answered. |
error | string | |
createdBy | string | |
createdAt | string (date-time) | |
sentAt | string (date-time) | null | |
answeredAt | string (date-time) | null |
{
"id": "cmd_4fQ9xLm2Za",
"kind": "locate",
"seconds": 0,
"state": "sent",
"text": "string",
"sms": "string",
"smsTo": "string",
"reply": "string",
"error": "string",
"createdBy": "string",
"createdAt": "2026-10-15T09:00:00+01:00",
"sentAt": "2026-10-15T09:00:00+01:00",
"answeredAt": "2026-10-15T09:00:00+01:00"
}Errors
defaultError