“How do I get a unit’s last update time?” was the most-viewed developer question on the Wialon forum, and it ran to ninety replies before it settled. The reason it was hard is not that the API hides the answer. It is that Wialon distinguishes between the last known position and the last known message, most integrations want one while asking for the other, and the two only agree when every message a device sends happens to carry a GPS fix. This page covers the unit data-flag table, how to fetch units and their state in one call, and how to watch for changes instead of polling for them.
Select what comes back with data flags
Requests that return units accept a flags value, and the response contains only the blocks those flags select. The complete table, from Data format: Units:
| HEX | DEC | Returns |
|---|---|---|
0x00000001 | 1 | Base — name, id, class, measure units, access level |
0x00000002 | 2 | Custom properties |
0x00000004 | 4 | Billing properties |
0x00000008 | 8 | Custom fields |
0x00000010 | 16 | Image |
0x00000020 | 32 | Messages |
0x00000040 | 64 | GUID |
0x00000080 | 128 | Administrative fields |
0x00000100 | 256 | Advanced properties |
0x00000200 | 512 | Commands available at the current moment |
0x00000400 | 1024 | Last message and position |
0x00001000 | 4096 | Sensors |
0x00002000 | 8192 | Counters |
0x00008000 | 32768 | Maintenance |
0x00020000 | 131072 | Trip detector and fuel consumption config |
0x00080000 | 524288 | All possible commands for the unit |
0x00100000 | 1048576 | Message parameters |
0x00200000 | 2097152 | Connection status |
0x00400000 | 4194304 | Position |
0x00800000 | 8388608 | Profile fields |
0x3FFFFFFFFFFFFFFF | 4611686018427387903 | Everything |
The reference states one thing explicitly that costs more time than anything else in the table: all flags are only used in DEC format. The documentation writes them in hexadecimal and the request takes decimal, so 0x400 goes in as 1024 and a request built by copying the hex string silently selects the wrong blocks rather than failing.
The all-flags value exists and is a trap on any real account, because it returns every block of every unit — sensors, counters, maintenance, command lists, custom fields — for every item in the result set. Requesting 1025 rather than everything is the difference between a response you can parse and one you wait for.
Decide whether you need the last position or the last message
Flag 1024 returns two things, and understanding why they differ is the whole point of this page:
{
"pos": {
"t": 1754870400,
"y": 52.2297,
"x": 21.0122,
"z": 113,
"s": 0,
"c": 180,
"sc": 9
},
"lmsg": { }
}The pos object is the last known position: t is time in UTC, y latitude, x longitude, z altitude, s speed, c course, and sc satellite count. The lmsg object is the last known message, and its shape depends on the message type. These two diverge whenever a device reports something without a GPS fix, which happens constantly in normal operation — an ignition event, a sensor reading, a driver code or a keepalive updates lmsg and leaves pos exactly where it was.
That divergence decides which field answers your question. If you are asking when the platform last heard from a unit, which is the liveness question most monitoring integrations actually care about, read lmsg. If you are asking where a unit is and when it was there, read pos.t. Using pos.t as a heartbeat marks a parked vehicle as offline while it is still reporting normally, and using lmsg as a position timestamp puts a vehicle on the map at a location it left hours ago. Both mistakes produce a system that looks correct in testing and disagrees with reality in the field.
Two related flags are worth knowing before you build a status view. Flag 2097152 returns a connection state as a boolean, which answers whether a device is connected right now without inferring it from timestamps at all. Flag 4194304 returns pos alone without lmsg, and is cheaper when coordinates are all you need.
Fetch every unit in one call rather than one call per unit
The core/search_items command returns a set of items with the flags you ask for, which is how you retrieve every unit and its last position in a single request:
svc=core/search_items¶ms={
"spec":{
"itemsType":"avl_unit",
"propName":"sys_name",
"propValueMask":"*",
"sortType":"sys_name"
},
"force":1,
"flags":1025,
"from":0,
"to":0
}The value 1025 is 1 combined with 1024 — base properties plus last message and position, in decimal. The parameters, from the search reference:
| Parameter | Description |
|---|---|
spec.itemsType | avl_unit, avl_unit_group, avl_resource, avl_retranslator, avl_route, avl_hw, user |
spec.propName | Property to search on — sys_name, sys_id, sys_unique_id (IMEI), sys_phone_number, rel_hw_type_name, and others |
spec.propValueMask | Value mask; *, |, >, <, =, ! are supported |
spec.sortType | Property used for sorting |
spec.propType | Property type; optional, defaults to property |
spec.or_logic | OR logic across propName; optional, defaults to 0 |
force | 0 returns a cached result if the same search was done before, 1 runs a new search |
flags | Data flags for the response |
from | Index of the first returned item; 0 for a new search |
to | Index of the last returned item; 0 returns everything from from |
Two details from the reference shape how this behaves in practice. The propName, propType and propValueMask fields are evaluated in threes, so a multi-criteria search must supply the same number of entries in each or the criteria misalign. And force set to 0 is a genuine cache rather than a hint, which is convenient while developing and actively misleading when you are polling to detect changes. Where the choice exists, search by sys_unique_id rather than by sys_name, because the IMEI is stable while the name is whatever the customer last typed into the interface.
Subscribe to state changes instead of polling for them
Polling core/search_items on a timer is the obvious approach and the wrong one at any scale, because it re-reads every unit on the account to discover the few that changed, against a session that permits ten simultaneous API requests in total. Wialon’s own mechanism is to subscribe: core/update_data_flags adds items to the session with a set of flags, and subsequent changes arrive through avl_evts.
svc=core/update_data_flags¶ms={
"spec":[{
"type":"type",
"data":"avl_unit",
"flags":1025,
"mode":0,
"max_items":1000
}]
}| Parameter | Description |
|---|---|
type | id (single id in data), col (array of ids), type (item type), access (subscribe to access-rights events, data 1 or 0) |
data | Depends on type |
flags | Which parts of the item to watch — the same flag table as above |
mode | 0 redefine flags, 1 add to the flags already in the session, 2 remove them |
max_items | Only when type is type — caps how many items are subscribed |
Mode 2 carries a consequence worth remembering, documented in the item events reference: removing the base flag removes the item from the session entirely rather than merely trimming what is reported for it. The polling ceiling on the receiving side is published as no more than 10 avl_evts requests during 10 seconds, so an event loop running once per second is already at the limit before anything else on the session competes with it.
The question that prompted this page, “How to get Unit Last update date and time”, drew 66,629 views across 90 replies on the Wialon forum before the board was taken offline. Every thread URL now redirects to the help.wialon.com root, and captured pages survive for roughly 61% of threads in the Wayback Machine.
Subscribing keeps you current. It does not keep you covered: Wialon Hosting removes unit history past 400 days by default, so a question asked next year about last year has nothing to read. Mirroring the data somewhere you control is a separate decision from how you read it live, and FleetSQL is our managed answer to it.
- Read lmsg for liveness and pos.t for location, and never substitute one for the other.
- Write flag values in decimal, because the documentation prints hex and the API rejects it.
- Subscribe through core/update_data_flags rather than polling search, and keep the event loop inside 10 requests per 10 seconds.