---
title: "Wialon API: Get a Unit's Last Position and Message"
url: https://theassettrack.com/wialon-api/units/
description: "Data flags, core/search_items, and the difference between last position and last message — the distinction behind the most-asked question on the SDK board."
---

# Wialon API: Get a Unit's Last Position and Message

Reference · last checked August 10, 2026

Data flags, core/search_items, and the difference between last position and last message — the distinction behind the most-asked question on the SDK board.

“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](https://sdk.wialon.com/wiki/en/kit/remoteapi/apiref/format/unit):

| 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&params={ "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](https://sdk.wialon.com/wiki/en/kit/remoteapi/apiref/core/search_items):

| 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&params={ "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](https://sdk.wialon.com/wiki/en/kit/remoteapi/apiref/core/update_data_flags): 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](https://help.wialon.com/) root, and captured pages survive for roughly 61% of threads in the [Wayback Machine](https://web.archive.org/web/*/https://forum.wialon.com/*).

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](https://theassettrack.com/products/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.

## Also in this reference

- ### Wialon API Token and Login: Sessions That Survive
 Wialon authorization end to end: the login form, token/login, token/update, the access-flag table, and the 100-day inaction rule that deletes idle tokens.
 [Wialon API Token and Login: Sessions That Survive](https://theassettrack.com/wialon-api/token/)
- ### Wialon API Errors: Codes 1, 4, 6, 7 and 1004
 The full Wialon Remote API error table, the 1003 reason variants, the quotas that produce each code, and how to classify them for retry logic.
 [Wialon API Errors: Codes 1, 4, 6, 7 and 1004](https://theassettrack.com/wialon-api/errors/)
- ### Wialon API in Postman: Authenticate in 10 Minutes
 The Wialon request format, the two headers and encodings that break every first call, and a Postman setup for an authenticated session.
 [Wialon API in Postman: Authenticate in 10 Minutes](https://theassettrack.com/wialon-api/postman/)
- ### Wialon Drivers API: Bind Drivers to Units
 Create drivers, bind them to units, read binding history over the Wialon Remote API — including the avl_driver auto-binding sensor.
 [Wialon Drivers API: Bind Drivers to Units](https://theassettrack.com/wialon-api/drivers/)
- ### Wialon API Reports: exec_report Without the Errors
 One report per session, the cleanup_result rule, the calls that cannot run alongside it, and the time limit that returns no rows instead of an error.
 [Wialon API Reports: exec_report Without the Errors](https://theassettrack.com/wialon-api/reports/)
- ### Wialon API Notifications: Create, Edit, Enable
 resource/update_notification end to end — call modes, the trigger and action pair, schedules, and the response fields that make notifications diffable.
 [Wialon API Notifications: Create, Edit, Enable](https://theassettrack.com/wialon-api/notifications/)
- ### Wialon Retranslator: Protocols and Configuration
 The nine retranslation protocols Wialon can forward to, the update_config parameters each one uses, and where retranslation fits against an API pull.
 [Wialon Retranslator: Protocols and Configuration](https://theassettrack.com/wialon-api/retranslator/)
