> ## Documentation Index
> Fetch the complete documentation index at: https://docs.telemax.com.au/llms.txt
> Use this file to discover all available pages before exploring further.

# Real-Time Fleet Tracking

> Poll fleet positions and render live vehicle locations on a map using GetAllLastPositionData and GetLastPositionData.

## Overview

The Telemax API uses a **polling model** for real-time fleet visibility. There is no persistent WebSocket connection — your integration requests the current position snapshot at a regular interval.

| Approach                 | When to use                                     |
| ------------------------ | ----------------------------------------------- |
| `GetAllLastPositionData` | Show all vehicles for a company on a single map |
| `GetLastPositionData`    | Track one specific vehicle                      |

Recommended polling interval: **30–60 seconds**. Devices typically report every 30 seconds, so polling faster returns the same data and adds unnecessary load.

***

## Step 1 — Authenticate

See [Authentication](/v1/authentication) for token details. Use the cached token pattern — request once, reuse for \~24 hours.

```bash cURL theme={null}
curl -s -X POST "https://api.telemax.com.au/api/Authentication/token/api-key" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "apiKey=YOUR_API_KEY"
```

***

## Step 2 — Get your company ID

You need a `companyId` to call fleet endpoints. Retrieve it from `GetCompanies`:

```bash theme={null}
curl -s -X POST "https://api.telemax.com.au/api/GetCompanies" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

The first `Id` in the response is your primary company ID.

***

## Step 3 — Fetch all fleet positions

Call `POST /api/GetAllLastPositionData/{companyId}` with `checkVehicleHandlerState=true` to get the latest known position for every vehicle in the company.

```bash cURL theme={null}
curl -s -X POST "https://api.telemax.com.au/api/GetAllLastPositionData/85?checkVehicleHandlerState=true" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

**Key response fields per vehicle:**

| Field               | Type    | Description                                             |
| ------------------- | ------- | ------------------------------------------------------- |
| `DeviceId`          | integer | Vehicle ID (use for follow-up calls)                    |
| `DeviceName`        | string  | Vehicle display name                                    |
| `Lat` / `Lng`       | double  | WGS84 decimal degrees                                   |
| `Speed`             | double  | Unit: km/h                                              |
| `Ignition`          | boolean | Whether ignition is on                                  |
| `UtcTime`           | string  | When this GPS fix was recorded (UTC, no `Z` suffix)     |
| `ConnectionStrengh` | string  | Device connectivity — `"Excellent"`, `"Good"`, `"Poor"` |

<Note>
  `UtcTime` is when the **GPS fix was recorded on the device**, not when it was fetched. A vehicle parked for an hour will show a one-hour-old timestamp. Use `ConnectionStrengh` (intentional spelling — see [Known Issues](/v1/quirks)) to distinguish a parked vehicle from an offline one.
</Note>

***

## Step 4 — Poll on an interval

<CodeGroup>
  ```python Python theme={null}
  import os, time, requests

  API_BASE = "https://api.telemax.com.au"
  API_KEY  = os.environ["TELEMAX_API_KEY"]
  COMPANY_ID = 85
  POLL_INTERVAL = 30  # seconds

  _token = None
  _token_expires_at = 0

  def get_token():
      global _token, _token_expires_at
      if _token and time.time() < _token_expires_at - 300:
          return _token
      r = requests.post(
          f"{API_BASE}/api/Authentication/token/api-key",
          data={"apiKey": API_KEY},
      )
      r.raise_for_status()
      d = r.json()
      _token = d["access_token"]
      _token_expires_at = time.time() + d["expires_in"]
      return _token

  def fetch_fleet():
      headers = {"Authorization": f"Bearer {get_token()}"}
      r = requests.post(
          f"{API_BASE}/api/GetAllLastPositionData/{COMPANY_ID}",
          params={"checkVehicleHandlerState": "true"},
          headers=headers,
      )
      r.raise_for_status()
      return r.json()

  while True:
      try:
          vehicles = fetch_fleet()
          print(f"\n{'Name':<25} {'Lat':>10} {'Lng':>11} {'km/h':>6} {'Ign'}")
          for v in vehicles:
              print(f"{v['DeviceName']:<25} {v['Lat']:>10.5f} {v['Lng']:>11.5f} "
                    f"{v['Speed']:>6.1f} {'ON' if v['Ignition'] else 'off'}")
      except Exception as e:
          print(f"Error: {e}")
      time.sleep(POLL_INTERVAL)
  ```

  ```javascript JavaScript (Leaflet map) theme={null}
  const API_BASE = "https://api.telemax.com.au";
  let token = null;
  let tokenExpiresAt = 0;
  const markers = {};

  async function getToken() {
    if (token && Date.now() < tokenExpiresAt - 300_000) return token;
    const res = await fetch(`${API_BASE}/api/Authentication/token/api-key`, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({ apiKey: "YOUR_API_KEY" }),
    });
    const { access_token, expires_in } = await res.json();
    token = access_token;
    tokenExpiresAt = Date.now() + expires_in * 1000;
    return token;
  }

  // Assumes Leaflet map already initialised as `map`
  async function updateFleet() {
    const res = await fetch(
      `${API_BASE}/api/GetAllLastPositionData/85?checkVehicleHandlerState=true`,
      { method: "POST", headers: { Authorization: `Bearer ${await getToken()}` } },
    );
    const vehicles = await res.json();

    for (const v of vehicles) {
      const latlng = [v.Lat, v.Lng];
      const label  = `${v.DeviceName} — ${v.Speed} km/h`;
      if (markers[v.DeviceId]) {
        markers[v.DeviceId].setLatLng(latlng).setTooltipContent(label);
      } else {
        markers[v.DeviceId] = L.marker(latlng)
          .bindTooltip(label)
          .addTo(map);
      }
    }
  }

  // Initial load then poll every 30 s
  updateFleet();
  setInterval(updateFleet, 30_000);
  ```
</CodeGroup>

***

## Data freshness

* `UtcTime` — timestamp of the last GPS fix recorded by the device. A vehicle parked for hours will have a stale timestamp.
* `ConnectionStrengh` — reflects the device's last-known signal quality. A poor signal may mean the vehicle is in a low-coverage area, not necessarily stationary.
* If `UtcTime` is more than a few minutes old and `Ignition` is `true`, the device may be temporarily offline.

***

## Polling guidance

* **30–60 seconds** is the recommended interval. Most Telemax devices report every 30 seconds.
* Polling faster than the device reporting rate returns identical data and wastes quota.
* If a vehicle's position hasn't changed between polls, suppress the map update to avoid unnecessary re-renders.

***

## Migrating to webhooks

Telemax supports webhook push for position events (see `webhooks.yaml`). When webhooks are fully deployed, your integration can receive position updates in real time instead of polling. Until then, polling `GetAllLastPositionData` is the supported approach.
