YipiiYipii IoT Docs

Integrator setup

From nothing to a live position stream — create a key yourself, find your account key, list assets, and open the socket. The whole integration in four calls.

Share

Four calls from nothing to vehicles moving on your map: make a key, find your account key, list the assets, open the socket. Everything else in this section is detail on those four.

Before you start — you need a Yipii IoT account with the assets you want to read, and a role that can reach Settings. You do not need anything from Yipii to begin; the key is self-service.

1. Create an API key

In Yipii IoT, open Settings → API.

Click Create API Key and give it a name that says where it runs — Dispatch bridge, Warehouse dashboard. You will be reading this name in a list in a year's time.

Copy the key. It is shown once.

That key is a Bearer token. It works on the REST API and on the live stream, and it does not expire on a schedule — revoke it from the same screen when it should stop working.

Older integrations use an OAuth2 password grant — a client_id and client_secret issued by Yipii, exchanged with a username and password at POST /oauth/token. That still works and is unchanged. It is not self-service: the client has to be minted for you. Prefer the key above for anything new — it is one screen, it is revocable per integration, and it carries no user password.

2. Find your account key

The account key is the slug in every account-scoped URL. Ask for it rather than copying it out of the address bar:

curl -s https://api.yipii.io/api/user_accounts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Everything below is scoped to it.

3. List the assets

curl -s "https://api.yipii.io/api/$ACCOUNT_KEY/asset_map" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
{
  "data": [
    {
      "id": 516,
      "view_only": false,
      "group": { "id": 115 },
      "tracker_imei": "352094087883606",
      "current_driver": { "id": 123, "first_name": "John", "last_name": "Borg" },
      "fixed_name": "KPW 443",
      "custom_name": "Ford Transit — Depot 2",
      "nick_name": "Big Transit"
    }
  ]
}

Keep id. That is what the stream is keyed on — not the IMEI, not the plate.

ASSET_IDS=$(curl -s "https://api.yipii.io/api/$ACCOUNT_KEY/asset_map" \
  -H "Authorization: Bearer $TOKEN" | jq -c '[.data[].id]')

4. Open the stream

One connection for the whole account, with every asset id on it.

import { io } from "socket.io-client";
 
const socket = io("https://avl.dazzlepanel.com", {
  query: {
    access_token: TOKEN,
    asset_ids: JSON.stringify([516, 517, 908]),
  },
});
 
socket.on("connect", () => console.log("live"));
 
socket.on("location", (data) => {
  // The FIRST message is an array — the last known position of every asset.
  // Everything after it is a single object.
  for (const u of Array.isArray(data) ? data : [data]) {
    console.log(u.assetId, u.latitude, u.longitude, `${u.speed} km/h`);
  }
});
 
socket.on("disconnect", (reason) => console.warn("dropped:", reason));

Python, with python-socketio:

import json, urllib.parse, socketio
 
sio = socketio.Client()
 
@sio.on("location")
def on_location(data):
    for u in (data if isinstance(data, list) else [data]):
        print(u["assetId"], u["latitude"], u["longitude"], u["speed"])
 
# The credentials and the subscription go in the URL. python-socketio has no
# separate query argument, and anything passed as headers is sent as HTTP
# headers, which this server does not read.
qs = urllib.parse.urlencode({
    "access_token": TOKEN,
    "asset_ids": json.dumps([516, 517, 908]),
})
 
sio.connect(f"https://avl.dazzlepanel.com?{qs}", transports=["websocket"])
sio.wait()

That is the integration. What follows is what you will hit next.

What you actually receive

The default payload is slim — ten fields — and a token alone does not change that. The full record needs style=detailed on the handshake and an account entitled to it. Both, not either.

Live tracking has the field lists, the throttle, and which channels an account is granted. Read it before deciding what you can build; several fields integrators reach for first — address, sensors, trip, driver behaviour — are on the detailed side of that line.

A full location payload

Abridged. This is one asset, one fix, with style=detailed on an entitled account.

{
  "assetId": 908,
  "trackerId": 1060,
  "trackerImei": "352094087883606",
  "latitude": 35.9873716,
  "longitude": 14.3283183,
  "speed": 13,
  "course": 146,
  "power": 14,
  "battery": 4,
  "gpsSignal": 14,
  "driverId": 123456,
  "groupId": 123456,
  "protocol": "teltonika",
  "dateUpdated": 1745333252000,
  "dateMoved": 1745333252000,
  "dateIgnition": 1745333252000,
  "dateValid": true,
  "wsSeq": 84213,
  "status": {
    "id": 64,
    "name": "Slow Moving",
    "color": "#6FB98F",
    "ignition": true,
    "movement": true,
    "engine": true,
    "priority": 1,
    "manual": false
  },
  "geoPoint": {
    "latitude": 35.9875564,
    "longitude": 14.3281216,
    "country": "Malta",
    "town": "Mellieħa",
    "street": "1",
    "number": ""
  },
  "sensors": [
    { "id": 316, "value": -48, "type": "temperature" }
  ],
  "beacons": [],
  "ioData": [
    { "id": 11, "value": "true", "type": "ignition" },
    { "id": 92, "value": "true", "type": "engine" },
    { "id": 421, "value": "32", "type": "adc1" }
  ],
  "startStopTrip": {
    "dateStarted": 1745329443000,
    "dateEnded": 1745333252000,
    "totalDistance": 33584,
    "avgSpeed": 29.86,
    "maxSpeed": 68,
    "idleDuration": 297900,
    "movingDuration": 3511100,
    "tripCoordinates": "[[35.820375,14.506705], …]"
  }
}

Three fields worth knowing about before you use them:

FieldRead this first
odometerDo not use it. It is not a distance you can trust; take mileage from a report
status.manualtrue means the status was synthesised — the device went to standby or lost connectivity — not that it was observed
wsSeqThe server's monotonic counter, and the only safe thing to order or deduplicate by. dateUpdated comes from the device clock and can go backwards

Connection etiquette

The stream is built for one persistent connection per account holding every asset you care about. A connection per asset is the pattern it is not built for, and a fleet opened that way will be throttled or refused.

  • Persist and reconnect with backoff. Do not connect per request.
  • One socket, many asset_ids. Change the set by reconnecting, not by opening more sockets.
  • Cache the token. It does not expire on a schedule.
  • Size the first handler for an array.

If it doesn't work

SymptomCauseFix
Connects, then disconnects immediatelyThe token was rejected. A bad token is disconnected, never downgradedCheck the key has not been revoked, and that you sent the raw token with no Bearer prefix
Connects and stays quietEvery id in asset_ids was dropped — they are scoped against what your account can actually seeRebuild the list from asset_map on the same token. Ids from another account, or stale ones, vanish silently
Positions arrive but only every 25 secondsYou are on the slim payload, which is throttled per assetThat is the restricted rate. Detail and cadence are an account entitlement — talk to Yipii
No address, sensors or trip in the payloadSlim again — those are detailed-only fieldsAdd style=detailed, and check the account is entitled. Both are required
Subscribed to vehicle_health or driver_behavior, never see oneNon-granted channels are dropped silently at connectvehicle_health needs Mobility on the account; driver_behavior needs a driver add-on
Positions appear to jump backwardsOrdering on dateUpdated, which is the device's clockOrder and deduplicate on wsSeq
It worked, then everything stopped after an outageThe stream fails closed: with the auth service unreachable and no cached result, connections are refused rather than served unscopedReconnect with backoff. It recovers on its own
  • Live tracking — the full stream contract, slim versus detailed, and the public tracking channel.
  • API keys — creating, using and revoking keys.
  • Authentication — the OAuth2 password grant, for integrations that already use it.
  • Reporting service — history and aggregates, which is where mileage and trips belong rather than the live stream.

Was this page helpful?

On this page