Wiki

Technical reference for system integrators and engineers.

REST API

The server-side REST API for configuration, entity management and live position streaming. JSON over HTTP, authenticated with OAuth 2.0.

Where MQTT is the push path for device telemetry, the REST API is the request path: it manages the entities a deployment is built from — venues, floors, zones, trackables, devices, users — and exposes live RTLS output through long-polling endpoints.

Base URI<host>/api/
Media typeapplication/json
AuthenticationOAuth 2.0 (bearer token)
SpecificationRAML — a browsable API console is served from the deployment

Authentication

Every endpoint requires OAuth 2.0 except those under /public. A token is obtained from the token endpoint, then presented on every subsequent request.

Token endpointPOST <host>/api/public/token
Request bodyapplication/x-www-form-urlencoded
Grant typespassword, refresh_token, client_credentials
Request headerAuthorization: Bearer <access token>
The token endpoint sits under /public, which is what makes it reachable before a token exists. The request body is form-encoded, not JSON — the rest of the API is JSON, this endpoint is not.

Identifying the client

Every grant identifies the calling client. Two equivalent methods are accepted; use one, not both.

HTTP Basic header. The client ID and secret are joined by a colon and the whole string is Base64-encoded:

base64( client_id + ":" + client_secret )

acme:s3cr3t   →   YWNtZTpzM2NyM3Q=

Authorization: Basic YWNtZTpzM2NyM3Q=

Encode the joined string once — not each part separately — and without a trailing newline. Client IDs are restricted to a–z, 0–9, ., _ and -, so the first colon is always the separator and a colon inside the secret is safe.

Body parameters. Alternatively, send client_id and client_secret as ordinary form fields, unencoded.

Base64 is used in exactly one place — the Basic header above. The password, the client secret sent as a body field, the refresh token and the access token are all plain values. Base64 is not encryption; it protects nothing on its own, so the token endpoint must be reached over TLS.

Which grants a client may use

Grant availability is a property of the registered client, not a free choice:

Client typePermitted grants
User-facing clientpassword, refresh_token
Machine-to-machine clientclient_credentials

Password grant — acting as a user

POST /api/public/token
Content-Type: application/x-www-form-urlencoded

grant_type=password
&username=alice%40example.com
&password=hunter2
&client_id=acme
&client_secret=s3cr3t

The username is matched case-insensitively. The password is sent as a plain form value.

Client credentials grant — machine to machine

POST /api/public/token
Authorization: Basic YWNtZTpzM2NyM3Q=
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

Refreshing

POST /api/public/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=<refresh token>
&client_id=acme
&client_secret=s3cr3t

The response

{
  "token_type":    "bearer",
  "access_token":  "…",
  "expires_in":    6000,
  "refresh_token": "…"
}

The access token is an opaque string, not a JWT — it carries no readable payload and is matched verbatim by the server. Store and send it exactly as received; do not decode, trim or re-encode it.

Token lifetime

Obtained byAccess tokenRefresh token
password — a user6000 s (100 min)60000 s (≈ 16 h 40 min)
client_credentials — a clientno expiryno expiry
Machine-to-machine tokens do not expire on their own. A token issued once stays valid until the client's credentials are changed, so treat it with the same care as the secret that produced it.

Using the token

Authorization: Bearer <access token>

The Bearer prefix is required. The server reads the second whitespace-separated word of the header, so a bare token without the prefix is rejected as unauthenticated.

Selected GET endpoints — those intended to be opened directly in a browser or embedded as a URL — also accept the token as a token query parameter instead of the header.

Failure responses

StatusMeaningWhat to do
401Bad access token — expired, invalid, or missing the Bearer prefixObtain a new token and retry
403Wrong username or password; the account is deactivated or still pending activation; or the account is not permitted to perform this operationDo not retry — a new token will not help

Each 403 carries an error_description distinguishing these cases.

The distinction matters operationally. A client that treats every failure as “re-authenticate” will loop indefinitely against a permissions problem, because the token was never the reason.

Live positions — RTLS long polling

The RTLS endpoints deliver position updates by long polling: the request is held open until data is available, so a client receives updates promptly without polling in a tight loop.

EndpointScope
GET /rtls/venues/{recordId}positions within a venue
GET /rtls/floors/{recordId}positions within a floor
GET /rtls/zones/{recordId}positions within a zone

The cursor

Client Server GET /rtls/floors/next { "id": 36, "next": 37, "data": [ … ] } GET /rtls/floors/37 held open until new data arrives { "id": 37, "next": 38, "data": [ … ] }
Start with next, then follow the next value returned in each response. The cursor is what guarantees no update is skipped between polls.
  • Use recordId = next on the first call to get the latest state.
  • Every response carries a next field; use that value as the recordId of the following request.
  • 408 Request Timeout is expected on a quiet channel — reissue the same request rather than treating it as an error.

Filtering

A filter query parameter takes a comma-separated list of locations. Omitting it applies no filter.

Response body

{
  "id": 36,
  "next": 37,
  "data": [
    {
      "geojson": {
        "type": "Feature",
        "geometry": { "type": "Point", "coordinates": [30.5107845, 50.4375970] },
        "properties": {}
      },
      "locations": {
        "venue":   ["106"],
        "floor":   ["107"],
        "zone":    ["209"]
      },
      "device": { "uid": "f1:e8:4f:ec:62:76", "type": "ble" },
      "debugInfo": {
        "distances": [
          { "beacon": 217, "value": 1 },
          { "beacon": 218, "value": 12.429373244299626 }
        ],
        "cell": 210
      },
      "timestamp": "Mon, 07 Mar 2016 15:52:04 GMT"
    }
  ]
}
FieldContent
geojsonPosition as a GeoJSON Feature with a Point geometry — [longitude, latitude]
locationsThe venue, floor and zone records the position falls within; each is an array and may be empty
deviceDevice uid and type
debugInfo.distancesContributing anchors and their measured distances
debugInfo.cellCell used for the calculation
timestampTime of the position

Trackables, Equipment and Personnel

Trackable is the base type. Equipment and Personnel are its two specialisations, each carrying the properties that only apply to that kind of subject. The three resources are addressed separately because they return different data.

/trackables base type — properties and status common to all /equipment vehicles, machinery, tools equipment-specific properties /personnel workers personnel ID and person-specific properties
Read the base resource for what every tracked subject has in common; read the specialisation for what only equipment or only people have.
ResourceContent
/trackablesBase type — the properties and status shared by everything tracked, regardless of kind
/equipmentTracked assets — vehicles, machinery, tools and other equipment
/personnelTracked people — workers, with personnel ID

Each specialisation follows the standard CRUD pattern, and associates a tracked subject with the device that reports it:

MethodPathResult
GET/equipmentlist all tracked equipment
POST/equipmentcreate — 201 on success, 400 if properties are invalid
GET/equipment/{uid}read one — 404 if the uid is unknown
PATCH/equipment/{uid}update
DELETE/equipment/{uid}remove
GET, PUT/equipment/{uid}/groupsgroup membership

/personnel exposes the same set of methods.

Shared status and commands

Status and device commands sit on the base type, since they apply to any tracked subject whether it is equipment or a person:

MethodPathResult
GET/trackables/statusescurrent status of tracked entities
POST/trackables/statuses/sendMessagesend a text message to a device — see Smart Lamp Locator
POST/trackables/statuses/ledset the LED indicator
POST/trackables/statuses/haptictrigger haptic feedback

Archive

Historical records, queried rather than streamed. Where /rtls/… delivers live positions, the archive endpoints return what has already been recorded.

EndpointContent
GET /archive/alarmshistorical alarms
GET /archive/rtlshistorical positions
GET /archive/geofhistorical geofencing events
GET /archive/wifihistorical WiFi connectivity records
GET /archive/smshistorical messages

Resource tree

Resources follow a consistent CRUD pattern — GET to list, POST to create, and GET / PATCH / DELETE on /{uid} to read, update and remove a single record.

PathPurpose
/rtls/…Live positions by location (long polling)
/archive/…Historical alarms, positions, messages and geofencing events
/trackablesBase type shared by equipment and personnel; status, messaging, LED and haptic commands
/equipment, /personnelThe two trackable specialisations
/locations/venues, /floors, /zonesSite model — the spatial hierarchy positions are resolved against
/devices/…Device records, serial numbers, statuses and connections — see device resource names
/cellsPositioning cells
/groups/…Groups of devices, trackables or locations
/files/…File storage for floor plans, venue maps and trackable images
/users, /roles, /profileAccounts, permissions and the current session
/mobile-sdk/…Endpoints shaped for the mobile SDK
/public/…No authentication — version, password reset, secrets

Device resources

Devices are split into four resources by the role they play in a deployment:

Resource pathRoleProducts
/devices/anchors RTLS anchor — fixed infrastructure that observes tags Locator Pro, Fieldbus Anchor, Locator Lite
/devices/locators Reverse RTLS anchor — device carried on the asset or person that reports its own position Smart Lamp Locator, Locator Lite XT
/devices/tags Tags and beacons — the tracked or transmitting endpoints Wristband Pro, Fieldbus Anchor (Tag Mode), Locator Lite (Tag Mode), BLE Beacons
/devices/gates PowerGate — onsite edge RTLS server edge processing of RTLS and IoT data

A PowerGate processes RTLS and IoT data locally at the site rather than in the cloud, so positioning and alerting continue to run when the site's uplink is unavailable.

Corresponding serial-number resources exist under /devices/serialnumbers/, which additionally carries uwb-tags and third-party-beacons.

On the web portal, the endpoints that /devices/tags covers are presented as two separate entities — UWB Tags and BLE Beacons. The API path is a single resource, so an integration mapping portal entities to API calls should expect that one-to-many relationship.

Anchor vs. locator

The two are opposite arrangements and should not be confused:

  • /devices/anchorsfixed infrastructure that observes tags. The anchor reports about something else.
  • /devices/locators — a device carried on the asset or person, reporting its own position. Reporter and subject are the same device.

The same term is used consistently in the MQTT interface — the LocatorID field and the <prefix>/Locators/<LocatorID>/ topic tree — so a device that appears under /devices/locators publishes in that tree.

Device status

GET /devices/statuses/{recordId} accepts a returnState boolean query parameter (default false); when set, the current state of all devices is included in the response.

Version

GET /public/version requires no authentication and returns the server version — useful as a reachability check before authenticating.

Common responses

StatusMeaning
200Operation successful
201Created
400Provided properties are invalid
401Bad or expired access token
403Not permitted for this account
404Record not found
408Request timeout — reissue the request