Joining data to your own system
Most integrations join XY Sense data to an external system: a workplace app, a BMS, a digital twin, or a BI model. This page covers the identifier, time, and coordinate semantics that make that join reliable. They apply to every dataset and to both the GraphQL API and webhooks.
Identifiers are stable, names are labels
- Every entity (building, floor, floor space, sensor, entry) has a GUID
id. IDs are stable for the life of the entity, so they are the right key to store in your system. - Names, descriptions, and space types are display metadata and can be edited at any time. Treat them as labels to show, rather than keys to join on.
- Reference data changes as workplaces change: spaces are added, renamed, recategorised, and retired. Refresh your cached reference data periodically (daily is a good default) and treat an unknown
floorSpaceIdin an event as a signal to refresh.
Mapping to your own system
- Pull the portfolio once with a discovery query (see Building and floor discovery).
- Match each XY Sense space to your system's equivalent. A shared naming convention makes the first pass automatic, and names can then change freely afterwards because your stored link is by
id. - Store the XY Sense
idagainst your entity and join all events, polling results, and analytics rows on it.
Timestamps are UTC
All API and webhook timestamps are UTC in ISO 8601 format (2026-06-02T04:17:39.106Z), and every from/to argument is interpreted as UTC. Store them as UTC on your side and convert only for display.
If results seem to disagree with the XY Sense dashboard, the timezone of your from/to arguments is the first thing to check. The dashboard presents a building's data in that building's local time, and some processing is building-local too: analytics runs overnight per building, and active hours are configured per building. See How occupancy is determined.
Worked example: to request analytics for Tuesday 3 June 2026 in Sydney (AEST, UTC+10), query from: "2026-06-02T14:00:00Z" to: "2026-06-03T14:00:00Z".
Which timestamp means what
collectedDateis when the underlying observation was made. Use it as the event time for occupancy and sightings.occupancyStatusChangeDateis when a space last changed occupancy state. It stays put while headcount varies within the same state, so it is not an event time.collectedAt(space sensor readings) means the same ascollectedDate. The name differs for historical reasons only.CreatedandSenton a webhook batch describe the delivery, not the observation:Createdis when the batch started filling andSentchanges on every retry. See delivery and batching.
The floor plan coordinate system
Every floor has a floorPlanUrl (the floor plan image) and a scale.
- Coordinates are expressed in centimetres from the top-left corner of the floor plan, with
xincreasing to the right andyincreasing downward. - Floor space shapes are polygons of points in this coordinate system.
- Floor sightings are
x/ypoints in the same system. scaleis the floor plan's resolution in centimetres per image pixel. To place a coordinate on the floor plan image, divide byscale:
pixelX = x / scale
pixelY = y / scale
The same conversion works in reverse (cm = pixels * scale) when translating a position picked on the image back to sensor coordinates.
Coordinates in analytics and heatmaps
Historical heatmap cells use the same centimetre coordinate system, so a heatmap overlay and a live sightings overlay can share one rendering path. See Historical heatmap for a worked rendering example.