1
📡
Fetch trackingMulti-courier API — J&T, PosLaju, DHL, GDEX
2
🧩
Normalize statusMap courier-specific codes to standard status
3
⏱️
Flag delaysCompare ETA vs current time, flag SLA breaches
4
📬
Notify exceptionsPush alert to WhatsApp & update dashboard
import requests, json, datetime
COURIER_APIS = {
"J&T": "https://api.jtexpress.my/v2/tracking",
"PosLaju": "https://api.pos.com.my/v1/parcels",
"DHL": "https://api.dhl.com.my/v1/shipments",
"GDEX": "https://api.gdexpress.com/v2/track"
}
STATUS_MAP = {
"PU": "Picked Up", "IT": "In Transit",
"OD": "Out for Delivery", "DL": "Delivered",
"EX": "Exception", "DE": "Delayed"
}
def track_parcel(tracking_id, courier):
api = COURIER_APIS.get(courier)
resp = requests.get(f"{api}/{tracking_id}")
data = resp.json()
raw_status = data.get("status", "UNKNOWN")
normalized = STATUS_MAP.get(raw_status, "Unknown")
eta = data.get("estimated_delivery")
is_delayed = eta and datetime.date.fromisoformat(eta) < datetime.date.today()
return {
"id": tracking_id,
"status": normalized,
"location": data.get("location", "N/A"),
"est": eta,
"delayed": is_delayed,
"courier": courier
}
parcels = ["SHIP-1001", "SHIP-1002", "SHIP-1003", "SHIP-1004"]
results = [track_parcel(p, c) for p, c in zip(parcels, ["J&T","PosLaju","DHL","GDEX"])]
print(json.dumps(results, indent=2))