Skip to main content

Overview

V2 uses standard pagination for alert retrieval — no sliding window or num cap required. Alerts are returned as AlertDto records from GET /api/v2/companies/{id}/alert-records. Key fields per alert:
FieldTypeDescription
idintegerUnique alert identifier — use for acknowledgement
utcTimestringWhen the alert occurred (UTC, no Z suffix)
userTimestringAlert time in the user’s configured timezone
userTimeFormattedstringPre-formatted display string
alertTypestringAlert type identifier (e.g. "18")
descriptionstringHuman-readable alert message
vehicleIdintegerVehicle that triggered the alert
vehicleNamestringVehicle display name
addressstringReverse-geocoded location
lat / lngdoubleLocation coordinates
isReadbooleanWhether the alert has been acknowledged
V2 adds GET /api/v2/companies/{id}/alerts which returns your alert configurations — including the human-readable AlertType string (e.g. "Speeding", "Geofence"). Use this to build your type mapping instead of discovering it empirically.

Step 1 — Look up alert type names

Before polling, fetch your alert configurations to build a type-ID-to-name map:
Python
import requests

def get_alert_config_map(company_id: int, token: str) -> dict:
    configs = {}
    page = 1
    while True:
        r = requests.get(
            f"https://api.telemax.com.au/api/v2/companies/{company_id}/alerts",
            params={"page": page, "pageSize": 50},
            headers={"Authorization": f"Bearer {token}"},
        )
        r.raise_for_status()
        data = r.json()
        for cfg in data.get("items", []):
            configs[cfg["alertId"]] = cfg["alertType"]   # e.g. {3631: "18"}
        if page >= data.get("numberOfPages", 1):
            break
        page += 1
    return configs

Step 2 — Poll with pagination

GET /api/v2/companies/{id}/alert-records supports standard page/pageSize pagination. Filter by IsRead to process only unread alerts.
import os, time, requests

API_BASE   = "https://api.telemax.com.au"
API_KEY    = os.environ["TELEMAX_API_KEY"]
COMPANY_ID = 85
POLL_SEC   = 60

_token, _expires_at = None, 0

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

def fetch_unread_alerts() -> list:
    alerts = []
    page = 1
    while True:
        r = requests.get(
            f"{API_BASE}/api/v2/companies/{COMPANY_ID}/alert-records",
            params={"page": page, "pageSize": 50},
            headers={"Authorization": f"Bearer {get_token()}"},
        )
        r.raise_for_status()
        data = r.json()
        unread = [a for a in data.get("items", []) if not a["isRead"]]
        alerts.extend(unread)
        if page >= data.get("numberOfPages", 1):
            break
        page += 1
    return alerts

alert_types = get_alert_config_map(COMPANY_ID, get_token())

while True:
    try:
        alerts = fetch_unread_alerts()
        for alert in alerts:
            process_alert(alert, alert_types)   # your handler — see Step 3
    except Exception as e:
        print(f"Poll error: {e}")
    time.sleep(POLL_SEC)

Step 3 — Filter by alert type

Use the config map from Step 1 to route alerts to the appropriate handler:
Python
ALERT_HANDLERS = {
    "Speeding":       "overspeed",
    "Geofence":       "geofence",
    "DoorUnlocked":   "door_unlocked",
    "LowBattery":     "battery",
    # extend from your GET /api/v2/companies/{id}/alerts response
}

def process_alert(alert: dict, alert_types: dict):
    type_name  = alert_types.get(alert["alertType"], f"type_{alert['alertType']}")
    handler    = ALERT_HANDLERS.get(type_name, "unknown")
    print(f"[{handler}] {alert['vehicleName']}{alert['description']} @ {alert['address']}")
    dispatch_notification(handler, alert)

Step 4 — Acknowledge alerts

Mark one alert as read

PUT /api/v2/alerts/{id}/{date}/update-read-status accepts a JSON body. In V2, isRead is honoured — you can mark an alert as unread by passing false.
cURL
curl -s -X PUT \
  "https://api.telemax.com.au/api/v2/alerts/101/2025-05-01T10:30:00/update-read-status?isRead=true" \
  -H "Authorization: Bearer YOUR_TOKEN"
Python
def mark_read(alert: dict, is_read: bool = True):
    requests.put(
        f"{API_BASE}/api/v2/alerts/{alert['id']}/{alert['utcTime']}/update-read-status",
        params={"isRead": str(is_read).lower()},
        headers={"Authorization": f"Bearer {get_token()}"},
    ).raise_for_status()

Bulk clear all alerts

When you want to reset the unread state for the entire company:
cURL
curl -s -X PUT \
  "https://api.telemax.com.au/api/v2/companies/85/set-all-alerts-read" \
  -H "Authorization: Bearer YOUR_TOKEN"
PUT /api/v2/companies/{id}/set-all-alerts-read marks all alerts for the company as read. In multi-tenant or multi-integration setups, only call this when every consumer is caught up.

Building notification rules

Python
SEVERITY = {
    "overspeed":   "high",
    "geofence":    "medium",
    "door_unlocked": "medium",
    "battery":     "low",
}

CHANNELS = {
    "high":   lambda a: send_sms(a),
    "medium": lambda a: send_email(a),
    "low":    lambda a: log_to_dashboard(a),
}

def dispatch_notification(handler: str, alert: dict):
    severity = SEVERITY.get(handler, "low")
    CHANNELS[severity](alert)

Gotchas

  • No sliding window needed. V2 uses standard pagination — fetch all pages, filter by IsRead: false.
  • isRead is now honoured. Unlike V1, V2’s update-read-status correctly sets the read state to the value you pass.
  • AlertType names are available. Use GET /api/v2/companies/{id}/alerts to get the string name for each AlertType integer — no need to build the mapping empirically.
  • UtcTime has no Z suffix but is always UTC — treat it as UTC when parsing.