Tracking API
Capture GPS telemetry from field devices, see where your workforce is right now, and replay where they have been.
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
graph LR
A[Device collects GPS] --> B{Network available?}
B -->|Yes| C[Push to backend]
B -->|No| D[Store on device]
D --> C
C --> E[Live position / History]
- 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.
Background collection continues after the app is closed on Android. On iOS this is not possible - a platform restriction, not an SDK limitation.
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 |
API reference
Field Force Mobility Execution APIs · Requires Intelomatic tenant
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 |
All requests require a bearer token and the api-key query parameter:
Authorization: Bearer <access_token>
?api-key=<apiKey>
Push GPS points from a device
POST /tracking/push
Request Parameters
| Parameter | In | Type | Required | Description | Example |
|---|---|---|---|---|---|
[] | body | object | No | One GPS point. Send several objects to push a batch. | |
[].driver | body | string | No | Username of the employee the device belongs to. | |
[].trackerId | body | string | No | Device identifier. The live and history calls read the track back by this value. | |
[].heading | body | integer | No | ||
[].lat | body | number | No | Latitude, decimal degrees. | |
[].lng | body | number | No | Longitude, decimal degrees. | |
[].motionActivity | body | integer | No | ||
[].session | body | integer | No | ||
[].speed | body | integer | No | ||
[].timestamp | body | integer | No | Time of the fix, Unix epoch seconds. | |
[].jobStatus | body | integer | No | ||
[].meta | body | string | No | Extra device metadata as a JSON-encoded string, not an object. |
Request body
[
{
"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 Schema
200 OK
{
"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.
Get current positions
POST /tracking/live
Request Parameters
| Parameter | In | Type | Required | Description | Example |
|---|---|---|---|---|---|
layer | body | string | No | Layer the trackers belong to, EMPLOYEE. | |
page | body | integer | No | Page number, starting at 1. | |
pageSize | body | integer | No | Trackers per page. | |
searchKey | body | string | No | Free-text filter. Empty string returns all. | |
sort | body | array | No | Fields to sort by. | |
sort[] | body | string | No |
Request body
{
"layer": "EMPLOYEE",
"page": 1,
"pageSize": 20,
"searchKey": "",
"sort": [
"ts"
]
}
Response Schema
200 OK
{
"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
}
}
}
}
| 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 |
Get historical track
POST /tracking/history
Request Parameters
| Parameter | In | Type | Required | Description | Example |
|---|---|---|---|---|---|
trackerId | body | string | No | Device to read the track for. | |
from | body | string | No | Start of the range, Unix epoch seconds, sent as a string. | |
to | body | string | No | End of the range, Unix epoch seconds, sent as a string. |
Request body
{
"trackerId": "mydevice@your_username",
"from": "1788022800",
"to": "1791651599"
}
Response Schema
200 OK
{
"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
}
]
}
]
}
| 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.
Example
curl -X POST '$BASE_URL/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\"}"}]'