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:
| Field | Type | Description |
|---|
id | integer | Unique alert identifier — use for acknowledgement |
utcTime | string | When the alert occurred (UTC, no Z suffix) |
userTime | string | Alert time in the user’s configured timezone |
userTimeFormatted | string | Pre-formatted display string |
alertType | string | Alert type identifier (e.g. "18") |
description | string | Human-readable alert message |
vehicleId | integer | Vehicle that triggered the alert |
vehicleName | string | Vehicle display name |
address | string | Reverse-geocoded location |
lat / lng | double | Location coordinates |
isRead | boolean | Whether 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:
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
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:
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 -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"
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 -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
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.