Skip to main content

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 floorSpaceId in an event as a signal to refresh.

Mapping to your own system

  1. Pull the portfolio once with a discovery query (see Building and floor discovery).
  2. 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.
  3. Store the XY Sense id against 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

  • collectedDate is when the underlying observation was made. Use it as the event time for occupancy and sightings.
  • occupancyStatusChangeDate is 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 as collectedDate. The name differs for historical reasons only.
  • Created and Sent on a webhook batch describe the delivery, not the observation: Created is when the batch started filling and Sent changes 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 x increasing to the right and y increasing downward.
  • Floor space shapes are polygons of points in this coordinate system.
  • Floor sightings are x/y points in the same system.
  • scale is the floor plan's resolution in centimetres per image pixel. To place a coordinate on the floor plan image, divide by scale:
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.