Skip to content

Pushing data in ​

You already count or measure something Omaya cannot see itself — a video conferencing system's person count, a badge system's in-building tally, another sensor cloud. Send it in and it behaves like any other reading.

People counts from your own systems ​

POST /api/v1/occupancy/readings

Each reading names a source_id, a zone_uid (or a venue_uid for a building-wide source), a count, and when it was captured. Up to 200 readings per call, and a text/csv body is accepted as well as JSON — which is usually what a badge-system export already is.

count is a whole number from 0 to 100,000. captured_at is an ISO 8601 time, defaults to now, and may be up to 31 days in the past — which is how a badge export back-fills history — but not more than a few minutes ahead.

POST /api/v1/occupancy/readings
X-Tenant-ID: yourorg
X-Api-Key: <your key>
Content-Type: application/json

{"readings": [
  {"source_id": "rallybar-mr1", "zone_uid": "…", "count": 4, "captured_at": "…"}
]}

What arrives is stored like a decoded sensor reading, so with no further setup it feeds Right Now, Space Utilisation, the history endpoints, the occupancy webhook, the assistant and utilisation rules. A count for a zone is read like a fixed counting sensor's — source sensor. A count for a venue becomes that building's headline figure, with source external, so anyone reading the number can see where it came from.

Send a level, not a total

count is how many people are there now, not how many have entered. A badge system should send its net in-building count, not the turnstile tally. Sending entries makes a room that hosted forty people over a day look like it holds forty people.

Give each counting device or system a stable source_id and keep it stable — 1 to 13 characters, lowercase letters, digits and hyphens. It is how Omaya tells your two conference rooms apart.

Sensor data over MQTT ​

Gateways deliver BLE and LoRaWAN traffic over MQTT, and that path is open to your own devices too. It is the right route when you have real sensors rather than a system with an API — a gateway you already own, a fleet of devices on your own broker.

If the device model is one Omaya knows, that is all there is to it. If it is not, teach it the device — the onboarding wizard builds a decoder from the device's own live packets, and the decoder is then yours.

What the gateway has to publish — broker, topic, payload shape, and the checklist a manufacturer works through before saying their unit supports Omaya — is on its own page: Connecting a gateway over MQTT.

GPS positions from another platform ​

Omaya's own trackers are one source of positions; they need not be the only one. A fleet-tracking platform, another make of tracker, a phone app — anything that knows where a vehicle or person is can send the position in, and it then behaves exactly like a tracker's own report: the outdoor trail, geofence entries and exits, rules, webhooks, the Warehouse yard's trucks on the road.

  1. Register each tracker as a device, under Devices. In the identifier field, put whatever ID the source uses for it: an IMEI, a serial, the platform's own device ID (4 to 17 letters, digits, dots, dashes or underscores), or a MAC if it has one. Bind it to a person or an asset like any tag.
  2. Create an HTTP connector: Connectors → IoT Gateway (HTTP), payload format generic. It gives you the address to post to, https://{host}/api/ingest/{token}; the token in it is the key, so keep it like a password.
  3. Post the positions, one object per fix:
POST https://{host}/api/ingest/{token}
Content-Type: application/json

{"device": "861234567890123", "lat": 3.1390, "lng": 101.6869,
 "time": "2026-10-07T09:30:00+08:00", "accuracy": 8}

Several at once go as a JSON array of those objects, or under "fixes": [...], up to 500 per call. The device may be named device, device_id, imei, tracker_id or serial. The position may be lat/latitude and lng/lon/longitude, at the top or inside gps, location or position; accuracy is in metres and optional. time is when the fix was taken — ISO 8601, Unix seconds or milliseconds — and defaults to when it arrives. Send positions as they happen. A fix whose time is more than a minute or so away from the server's clock (the same allowance a gateway's clock gets) is stamped with the time it arrived instead, so a platform that holds fixes back and forwards them in batches puts them all at the moment of the batch. A fix at exactly 0, 0 is ignored as "no fix".

The call answers 202 with how many it accepted. A fix for an ID no device is registered with is accepted and then dropped, so check the trail: the device's Sensor Trail shows the trip or stop within a minute. While a gateway can also hear the same device indoors, the indoor room wins and the GPS fix is kept only as a point.

Tags heard by phones (Omaya Scout) ​

Phones can be finders for your Bluetooth tags outside the building, where no gateway hears them. The Omaya Scout app does this already; this section is for a team that wants the same from its own app or scanner. Omaya Scout is switched on per organisation by your Omaya contact; until it is, the calls below answer as if no tags were published.

What a phone may report is limited on purpose. There is no sign-in, so:

  • Only published tags are accepted: your organisation's tags, asset tags, beacons and trackers. Tags bound to a person are published too where your Omaya contact has turned that on, so each person's own phone can carry their tag outdoors.
  • A report for any other Bluetooth address is ignored and never stored, and a report never creates a device.
  • Positions sent this way go into the tag's outdoor trail like a tracker's own GPS. The tag's battery and sensor readings are decoded too, but a phone's report never fires a rule or a button press, and never changes which gateway heard the tag or its signal reading.

Every call carries an X-Scout-Install header: a random UUID the app makes once, on its first launch, and keeps. It is how a phone is told apart, how Monitor → Scout (phones) lists it, and how a misbehaving phone is shut out (its calls then answer 403). X-Scout-Platform (the phone's operating system) and X-Scout-Version (your app's version) are optional and are kept with the phone.

  1. Ask how to behave. GET /api/scout/v1/manifest answers whether scouting is on, how often to report (scan_interval, and min_interval, the fastest accepted), how long to listen each time (scan_seconds), how often to say it is alive (heartbeat_interval), the Bluetooth service UUIDs your tags advertise (service_uuids, which iPhones need to scan in the background), and devices_version.
  2. Fetch the tag list. GET /api/scout/v1/devices returns {"version", "generated_at", "devices": [{"mac", "name", "type"}, …]}. Send the ETag you were given back as If-None-Match; an unchanged list answers 304 with no body. Check again when devices_version in the manifest changes, or once a day.
  3. Report what you heard. When the manifest says "adverts": true, send every advertisement of a known tag type — Minew, MOKO, Eddystone, iBeacon — and let Omaya decide which are your tags, as it does for a gateway. You do not need the tag list for this, and it is the only way an iPhone's reports count, since iOS hides each tag's Bluetooth address. Up to 30 scans per call, each with the phone's position and up to 300 adverts:
POST /api/scout/v1/adverts
X-Scout-Install: 3f6c2a1e-8b7d-4c35-9a0e-5d2b7c41e9a8
Content-Type: application/json

{"scans": [
  {"location": {"lat": 3.1390, "lng": 101.6869, "accuracy": 12,
                "captured_at": "2026-10-18T09:30:10+08:00"},
   "adverts": [
     {"mac": "C3:00:00:12:34:56", "rssi": -71, "tx_power": -59,
      "seen_at": "2026-10-18T09:30:12+08:00",
      "adv_data": "0201060AFF4C001005031C..."}
   ]}
]}

rssi, seen_at and adv_data (the advertisement as hex) are required for each advert; mac is optional — send it where the phone can read it (Android) and leave it out where it cannot (iPhone). tx_power is optional, and source is raw (the default) or rebuilt for bytes you put back together from fields the phone's system had already parsed. Without a mac, an advert is matched by a registered address it carries inside it (Minew and MOKO frames do), or by an iBeacon, Eddystone or MOKO ID Omaya has learned from its gateways. The answer gives heard (adverts received), accepted (tags placed) and matched, which scan and advert were which tag, for the app's own screens.

An app that does not read the manifest flag can still report tags it has already picked out from the tag list, up to 200 sightings per call:

POST /api/scout/v1/sightings
X-Scout-Install: 3f6c2a1e-8b7d-4c35-9a0e-5d2b7c41e9a8
Content-Type: application/json

{"sightings": [
  {"mac": "C3:00:00:12:34:56", "rssi": -71, "tx_power": -59,
   "seen_at": "2026-10-18T09:30:12+08:00",
   "location": {"lat": 3.1390, "lng": 101.6869, "accuracy": 12,
                "captured_at": "2026-10-18T09:30:10+08:00"},
   "frames": [{"adv_data": "0201060AFF4C001005031C...", "rssi": -71}]}
]}

mac, rssi, seen_at and location (with lat, lng and captured_at) are required; tx_power, the phone's accuracy in metres, and frames — the tag's raw advertisements as hex, up to 8 — are optional. Send frames if you want the tag's battery and sensor values as well as where it was. The answer says how many were accepted and ignored. 4. Say you are alive. POST /api/scout/v1/heartbeat with scouting (true or false), bluetooth (its state) and optionally location, every heartbeat_interval seconds. It records whether the phone is scouting and where it last was, even when it has heard no tags.

A scan or sighting is ignored when the phone's position is worse than 300 m, at exactly 0, 0, more than 24 hours old (a phone may keep sightings while offline and send them later), or in the future. Where several phones hear the same tag at once, Omaya keeps the most accurate position, one per tag every 10 seconds, and counts the phones. The tag's distance from the phone is estimated from its signal and added to the phone's own accuracy. While a gateway also hears the tag indoors, the room wins and the phone's position is kept only as a point.

Calls are limited to 30 a minute per phone. A phone that reports once every 10 seconds, the fastest the manifest allows, stays well inside that.

Check it landed: open Monitor → Scout (phones). The phone appears in the phone list after its first call, and a tag it heard appears on the map with an accuracy circle within a minute.

Choosing between them ​

You haveSend it as
A system that knows how many people are in a roomA people count, over the API
A badge or access-control systemA venue-wide count, over the API — the net figure
Doorway counters on every entrance of a floorNothing — tick "every way in and out is counted" on the venue and Omaya nets them
Physical sensors of your ownMQTT, decoded like any other device
GPS positions from a fleet platform, another tracker or an appThe HTTP connector, one object per fix
An app that hears your Bluetooth tags on phones outsideThe Omaya Scout API, or the Omaya Scout app
A product on the connectors listNeither — configure the connector

Checking it landed ​

Right Now picks up a pushed count within ten minutes. A zone's count should match what you sent and be marked as a sensor count; a venue-wide one should be the venue's headline, marked as external.

If it does not: check the response body from the call itself — rejected readings come back individually with a reason, rather than the whole call failing. The usual causes are a zone_uid from a different organisation, a count outside 0 to 100,000, or a captured_at more than 31 days back. A captured_at within the 31 days but older than ten minutes is accepted and lands in history — it just never shows in Right Now, which only looks at the last ten minutes.

Last updated:

Omaya platform documentation