Most first hours with the Wialon Remote API are spent on the request format rather than on the API itself. It looks like a JSON REST API and behaves like nothing of the kind: the payload is form-encoded, the JSON travels inside a single field, and hexadecimal flag values are rejected outright. Getting those three right is most of the work, and everything after them is mechanical. This page covers the request format, obtaining a token with the access you actually need, exchanging it for a session, and the two quotas that make exploring against a customer’s production account a bad idea.
Get the request format right before anything else
The request format reference states that all actions are executed only through POST requests over https, that additional parameters are supplied as JSON, and that the response is returned as JSON. The template is a single endpoint carrying three parameters:
https://{host}/wialon/ajax.html?sid=<text>&svc=<svc>¶ms={<params>}| Parameter | Description |
|---|---|
sid | Session ID |
svc | Command |
params | Parameters for command execution, as JSON |
Four rules come off that page, and each one produces a confusing failure when broken. Requests are POST only and https only. The Content-Type header must be application/x-www-form-urlencoded, which the reference calls out explicitly — sending a raw JSON body returns an invalid-input error that says nothing about the encoding, and the natural response is to start rewriting the payload rather than the header. All text parameters use UTF-8 in both directions. And JSON does not support HEX values, so every flag printed in hexadecimal in the documentation goes into a request in decimal instead; this one is the most costly because it produces wrong behaviour rather than an error. The session identifier is mandatory on all requests except login and some of the requests documented under Other requests.
Ask for read-only access when the integration only reads
Send the account owner to the authorization form on their own host, and set the access explicitly rather than accepting what the form assumes:
https://hst-api.wialon.com/login.html?client_id=Your%20App&access_type=768&duration=2592000&response_type=tokenThe access_type parameter defaults to 0x100, which grants online tracking only, so omitting it produces a token that returns access-denied on every data read for as long as it exists. The value 768 is 0x100 combined with 0x200 — online tracking plus view access — written in decimal because the request format requires it. The token and login page covers the full flag table, along with why requesting unlimited access for a read-only feature is the thing that ends a security review.
Tokens can also be created without the form, through token/update with a call mode of create. Two constraints apply either way: the duration is capped at 8,640,000 seconds, which is 100 days, and a token is deleted automatically after 100 days of inaction even when its duration is set to infinite.
Exchange the token for a session and read the response rather than assuming it
curl -s -X POST 'https://hst-api.wialon.com/wialon/ajax.html' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'svc=token/login' \
--data-urlencode 'params={"token":"<72-symbol token>"}'A token is 72 symbols, and a shorter one comes back as an invalid-input error carrying a reason of WRONG_TOKEN_LENGTH — which is a good first check that the encoding and headers are right, because a malformed request fails differently. The call also accepts a response-flags parameter controlling how much the login response carries: 0x1 basic info, 0x2 user info, 0x4 token info, 0x8 items info, 0x10 billing services info, and 0x20 user custom properties, all in decimal like everything else.
The response returns the session identifier that every subsequent call passes as sid. Read it out of the response object rather than hardcoding a field name taken from a blog post, including this one — the response shape is documented, and a client built on an assumption about it breaks silently when the assumption is wrong.
Build the Postman environment around three variables
Three environment variables carry the whole setup: host, token and sid. Configure the request as POST to the ajax endpoint on the host variable, set the body type to x-www-form-urlencoded, and give it two keys — svc holding token/login, and params holding the token wrapped in JSON. Postman sets the correct Content-Type header automatically for that body type, which is most of the reason to use it here rather than hand-rolling raw bodies and getting the header wrong.
Every subsequent request adds sid as a third key and changes svc and params. A collection-level pre-request script that logs in when sid is empty removes the manual re-authentication step, and it should be written defensively: if login fails, stop rather than loop, because more than ten failed logins from one IP address in a minute produces a temporary IP-address block that affects every integration sharing that address, not only the one being debugged.
Explore against a small account before pointing a runner at a real one
Two quotas make casual experimentation expensive, and both are published on the current limitations page.
Message loading is a heavy request, and no more than three heavy requests run simultaneously in one session. Report execution counts as heavy too, so a Postman runner iterating over units in parallel starts colliding with itself well before it saturates anything on the server. The message quotas are the more serious constraint: 15,000,000 messages within 2 minutes, 200,000,000 within an hour, and 2 GB per request, all measured per user rather than per integration. After a bound is reached the account cannot load or import messages for the remainder of that period, and the documentation notes that this breaks report execution and track building as well — so exhausting a quota while exploring degrades the customer’s live interface, not just the notebook it was run from.
Reports carry a trap of their own for a runner. Continuous execution for one user from one IP address is capped at ten minutes, and crossing it locks reporting out for another ten — so a loop that fires report after report while you read the results can take the customer’s reporting offline for twenty minutes.
When a call does fail, the response carries an error code and sometimes a reason string. Three appear in the first hour: invalid input, usually the encoding or a malformed params field, where the reason names the specific problem; invalid session, meaning the session identifier is no longer valid and needs a fresh token/login rather than a retry; and access denied, most often a token whose access_type is too narrow, though item-level access rights produce it too. The error reference page carries the full table, the five reason variants hiding behind one of the codes, and a classification of which failures are worth retrying.
- Set Content-Type to application/x-www-form-urlencoded and let Postman manage it via the body type.
- Write every flag value in decimal, because the documentation prints hex and the API rejects it.
- Explore against a short interval and a small unit set — the message quota belongs to the customer, not to you.