Tracking API
Capture GPS telemetry from field devices, see where your workforce is right now, and replay where they have been.
Where it's used
Use cases, value and how it works
Overview & Solution
Field teams are the part of the business you can least see. Attendance is self-reported, visits are claimed after the fact, and disputes come down to one person's word.
The Tracking API closes that gap. Devices push location continuously; you read it back as a live position or as a full day's track. Every point carries speed, accuracy, battery and device metadata, so you can tell a real journey from a device left on a desk.
Key Value Propositions
- Live and historical in one API - the same telemetry stream answers "where is this person now" and "where did they go last Tuesday".
- Accepts backdated points - the API takes timestamped points regardless of when they arrive, so an app can buffer locally while offline and push the batch once connectivity returns. Whether a given app actually supports offline collection is a front-end/SDK decision, not something this API does on its own.
Industry Use Cases
1. Banking, NBFC & Collections
- Verified field presence - prove a collections officer reached the customer's premises, with time and coordinates, instead of relying on a call report.
- Attendance without hardware - replace biometric machines at branches the workforce never visits.
2. Distribution & Field Sales
- Beat adherence - compare the route actually travelled against the planned journey and see where the day diverged.
- Productive hours - separate travel time from time at customer locations.
3. Service & Maintenance Networks
- Nearest-technician dispatch - route the next job to whoever is genuinely closest, not whoever answers first.
- SLA evidence - reconstruct arrival times when a customer disputes a response window.
How it works
- Collect - the device records position continuously, in foreground and background.
- Buffer - without connectivity, points are retained locally rather than dropped.
- Push - buffered points are sent as soon as the network returns.
- Read - query the latest known position, or a full track over a time range.
Works well with
| Pair it with | To get |
|---|---|
| PJP API | Planned route vs actual route |
| Events API | Duty status and check-ins alongside the track |
| Reverse Geocode API | Readable addresses instead of raw coordinates |
Background collection continues after the app is closed on Android. On iOS this is not possible - a platform restriction, not an SDK limitation.
API reference
Field Force Mobility Execution APIs · Requires Intelomatic tenant
Quick try
curl -X POST 'https://api-gw.sovereignsolutions.com/gateway/$TENANT/tracking/push?api-key=$API_KEY' \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '[{"driver": "your_username", "trackerId": "mydevice@your_username", "heading": 0, "lat": 18.4585507, "lng": 75.4128607, "motionActivity": 0, "session": 1790131313, "speed": 0, "timestamp": 1790131380, "jobStatus": 2, "meta": "{\"sourceType\":\"api\",\"accuracy\":1217.35,\"battery\":\"86%\",\"networkType\":\"Mobile\"}"}]'
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /tracking/push | Push GPS points from a device |
POST | /tracking/live | Get current positions |
POST | /tracking/history | Get historical track |
Push GPS points from a device
Request parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
[] | body | object | - | One GPS point. Send several objects to push a batch. |
[].driver | body | string | - | Username of the employee the device belongs to. |
[].trackerId | body | string | - | Device identifier. The live and history calls read the track back by this value. |
[].heading | body | integer | - | |
[].lat | body | number | - | Latitude, decimal degrees. |
[].lng | body | number | - | Longitude, decimal degrees. |
[].motionActivity | body | integer | - | |
[].session | body | integer | - | |
[].speed | body | integer | - | |
[].timestamp | body | integer | - | Time of the fix, Unix epoch seconds. |
[].jobStatus | body | integer | - | |
[].meta | body | string | - | Extra device metadata as a JSON-encoded string, not an object. |
[
{
"driver": "your_username",
"trackerId": "mydevice@your_username",
"heading": 0,
"lat": 18.4585507,
"lng": 75.4128607,
"motionActivity": 0,
"session": 1790131313,
"speed": 0,
"timestamp": 1790131380,
"jobStatus": 2,
"meta": "{\"sourceType\":\"api\",\"accuracy\":1217.35,\"battery\":\"86%\",\"networkType\":\"Mobile\"}"
}
]
Response
{
"status": {
"success": true,
"time": "2026-09-23T02:29:38.888Z"
}
}
| Field | Type | Description |
|---|---|---|
status | object | |
status.success | boolean | true when the points were accepted. |
status.time | string | Server time the batch was accepted, UTC. |
The body is a JSON array, one object per GPS point - send a single-element array for one point.
Errors: non-2xx responses use the standard status codes listed on Errors.
Get current positions
Request parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
layer | body | string | - | Layer the trackers belong to, EMPLOYEE. |
page | body | integer | - | Page number, starting at 1. |
pageSize | body | integer | - | Trackers per page. |
searchKey | body | string | - | Free-text filter. Empty string returns all. |
sort | body | array | - | Fields to sort by. |
sort[] | body | string | - |
{
"layer": "EMPLOYEE",
"page": 1,
"pageSize": 20,
"searchKey": "",
"sort": [
"ts"
]
}
Response
{
"result": 0,
"status": {
"success": true,
"message": ""
},
"data": {
"trackers": [
{
"driver": "apidemo_newuser_9",
"trackingInfo": [
{
"trackerId": "mydevice@apidemo_newuser_9",
"lat": 18.4585507,
"lng": 75.4128607,
"ts": 1790131380,
"speed": 0,
"heading": 0,
"device_status": 2,
"session": "1790131313",
"employee_username": "apidemo_newuser_9",
"employee_organization_id": 1,
"employee_team_id": 2,
"employee_type_id": 0,
"received": 1790132970,
"employee_full_name": "Demo User 9",
"meta_event": "",
"meta": "{\"sourceType\":\"api\",\"accuracy\":1217.35,\"battery\":\"86%\",\"networkType\":\"Mobile\"}",
"address": "",
"action_code": "off_duty",
"typeCode": "DUTY",
"event_ts": 0,
"motionActivity": 0,
"employee_status": 3,
"employee_meta": "{\"employee_code\": null, \"employee_dob\": \"1995-04-17T00:00:00\", \"employee_email\": \"[email protected]\", \"employee_guid\": \"6ab33224bba47a219f950da5\", \"employee_phone\": \"919800000009\", \"employee_reporting_manager\": \"apidemo_sovereignsolutions\", \"employee_role\": \"Worker\", \"employee_vehicle_id\": null, \"hierarchyPath\": \"/demo/sovereignsolutions\"}",
"meta_tracking": "{\"sourceType\":\"api\",\"accuracy\":1217.35,\"battery\":\"86%\",\"networkType\":\"Mobile\"}",
"employee_image": ""
}
],
"latest_events": {
"DUTY": {
"action_code": "off_duty",
"typeCode": "DUTY",
"event_ts": 0,
"meta_event": "",
"address": ""
}
},
"latest_duty_event": {
"action_code": "off_duty",
"typeCode": "DUTY",
"event_ts": 0,
"meta_event": "",
"address": ""
},
"employee_image": ""
}
],
"total": 1,
"counters": {
"employee_username": {
"apidemo_newuser_9": 1
},
"device_status": {
"2": 1
},
"action_code": {
"off_duty": 1
}
}
}
}
Response fields (57)
| Field | Type | Description |
|---|---|---|
result | integer | Status of the call. 0 means it succeeded. |
status | object | |
status.success | boolean | true when the call succeeded. |
status.message | string | |
data | object | |
data.trackers | array | One entry per employee with a known position. |
data.trackers[] | object | |
data.trackers[].driver | string | Username of the employee. |
data.trackers[].trackingInfo | array | |
data.trackers[].trackingInfo[] | object | |
data.trackers[].trackingInfo[].trackerId | string | Device the position came from. |
data.trackers[].trackingInfo[].lat | number | Latitude of the latest fix. |
data.trackers[].trackingInfo[].lng | number | Longitude of the latest fix. |
data.trackers[].trackingInfo[].ts | integer | Time of the latest fix, Unix epoch seconds. |
data.trackers[].trackingInfo[].speed | integer | |
data.trackers[].trackingInfo[].heading | integer | |
data.trackers[].trackingInfo[].device_status | integer | |
data.trackers[].trackingInfo[].session | string | |
data.trackers[].trackingInfo[].employee_username | string | |
data.trackers[].trackingInfo[].employee_organization_id | integer | |
data.trackers[].trackingInfo[].employee_team_id | integer | |
data.trackers[].trackingInfo[].employee_type_id | integer | |
data.trackers[].trackingInfo[].received | integer | When the platform received the fix, Unix epoch seconds. |
data.trackers[].trackingInfo[].employee_full_name | string | |
data.trackers[].trackingInfo[].meta_event | string | |
data.trackers[].trackingInfo[].meta | string | Device metadata sent with the point, as a JSON-encoded string. |
data.trackers[].trackingInfo[].address | string | |
data.trackers[].trackingInfo[].action_code | string | |
data.trackers[].trackingInfo[].typeCode | string | |
data.trackers[].trackingInfo[].event_ts | integer | |
data.trackers[].trackingInfo[].motionActivity | integer | |
data.trackers[].trackingInfo[].employee_status | integer | Employee lifecycle state as a numeric code: 1 New, 2 Inactive, 3 Active, 4 Disable. |
data.trackers[].trackingInfo[].employee_meta | string | Employee profile fields as a JSON-encoded string. |
data.trackers[].trackingInfo[].meta_tracking | string | Device metadata sent with the point, as a JSON-encoded string. |
data.trackers[].trackingInfo[].employee_image | string | |
data.trackers[].latest_events | object | Most recent event per event type, keyed by type code. |
data.trackers[].latest_events.DUTY | object | |
data.trackers[].latest_events.DUTY.action_code | string | |
data.trackers[].latest_events.DUTY.typeCode | string | |
data.trackers[].latest_events.DUTY.event_ts | integer | |
data.trackers[].latest_events.DUTY.meta_event | string | |
data.trackers[].latest_events.DUTY.address | string | |
data.trackers[].latest_duty_event | object | Most recent duty event (on_duty / off_duty). |
data.trackers[].latest_duty_event.action_code | string | |
data.trackers[].latest_duty_event.typeCode | string | |
data.trackers[].latest_duty_event.event_ts | integer | |
data.trackers[].latest_duty_event.meta_event | string | |
data.trackers[].latest_duty_event.address | string | |
data.trackers[].employee_image | string | |
data.total | integer | Total number of trackers matching the request. |
data.counters | object | Counts of the returned trackers, grouped by username, device status and duty action. |
data.counters.employee_username | object | |
data.counters.employee_username.apidemo_newuser_9 | integer | |
data.counters.device_status | object | |
data.counters.device_status.2 | integer | |
data.counters.action_code | object | |
data.counters.action_code.off_duty | integer |
Errors: non-2xx responses use the standard status codes listed on Errors.
Get historical track
Request parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
trackerId | body | string | - | Device to read the track for. |
from | body | string | - | Start of the range, Unix epoch seconds, sent as a string. |
to | body | string | - | End of the range, Unix epoch seconds, sent as a string. |
{
"trackerId": "mydevice@your_username",
"from": "1788022800",
"to": "1791651599"
}
Response
{
"result": 0,
"status": {
"success": true,
"message": ""
},
"data": [
{
"deviceStatus": {
"value": 1,
"iconColor": "#7CB342",
"session": "1790131313"
},
"data": [
[
75.4128607,
18.4585507
]
],
"times": [
1790131380
],
"metaData": [
{
"speed": 0,
"heading": 0
}
]
}
]
}
Response fields (19)
| Field | Type | Description |
|---|---|---|
result | integer | Status of the call. 0 means it succeeded. |
status | object | |
status.success | boolean | true when the call succeeded. |
status.message | string | |
data | array | One entry per tracking session in the range. |
data[] | object | |
data[].deviceStatus | object | |
data[].deviceStatus.value | integer | |
data[].deviceStatus.iconColor | string | |
data[].deviceStatus.session | string | Session the points belong to. |
data[].data | array | Track points as [longitude, latitude] pairs, in time order. |
data[].data[] | array | |
data[].data[][] | number | |
data[].times | array | Unix epoch seconds for each point, same order as data. |
data[].times[] | integer | |
data[].metaData | array | Speed and heading for each point, same order as data. |
data[].metaData[] | object | |
data[].metaData[].speed | integer | |
data[].metaData[].heading | integer |
Coordinates in data are GeoJSON order - longitude first.
Errors: non-2xx responses use the standard status codes listed on Errors.