Snapshots and tracks

One JSON per room, with everyone Cymo detects listed inside it.

The room snapshot

GET /v1/rooms/{room} describes one room at one moment: whether it is observed and occupied, how many people and pets are in it, and a people list with each person's zones and signals. The vitals, presence and movement reads are filtered views of the same object.

room.snapshot
{
  "data": {
    "object": "room.snapshot",
    "room_id": "room_bedroom",
    "timestamp": "2026-10-24T23:55:30.000Z",
    "observation_status": "observed",
    "occupied": true,
    "person_count": 1,
    "pet_count": 0,
    "people": [
      {
        "track_id": "trk_001",
        "person_id": "person_001",
        "identity_confidence": 0.9,
        "timestamp": "2026-10-24T23:55:30.000Z",
        "zone_ids": [
          "zone_bed"
        ],
        "signals": {
          "heart_rate_bpm": {
            "value": 62,
            "timestamp": "2026-10-24T23:55:30.000Z",
            "confidence": 0.92
          },
          "respiration_rate_per_min": {
            "value": 14,
            "timestamp": "2026-10-24T23:55:30.000Z",
            "confidence": 0.92
          }
        }
      }
    ],
    "pets": []
  },
  "meta": {
    "request_id": "req_01",
    "project_id": "proj_demo",
    "livemode": false,
    "generated_at": "2026-10-24T23:55:30.000Z"
  }
}

Why one snapshot, not one stream per person

People walk in and out. Separate streams per person would open and close all the time, and you would have to merge them again to answer simple questions such as how many people are in the room. One snapshot per room gives you the whole picture in one read, and it is the shape agents find easiest to reason about.

Tracks and people

Each person gets a track_id such as trk_001. A track means "a person, tracked continuously". It is not an identity, and it can change when someone leaves and comes back.

person_id is a stable pseudonym that stays null until identity is established, with its own identity_confidence. Cymo never stores names: if your product needs to know who someone is, map the person_id to a person in your own app.

Null means not measurable

Every signal is a measurement with its own value, timestamp and confidence. When Cymo can't measure something, such as heart rate while a person walks, the value is null and reason says why when it is known, for example motion. Cymo never fills a gap with a guess, so a number in the response is always a measurement.

The same goes for the room: observation_status is observed, partial or unavailable, and an unavailable room has null counts. An offline Cymo is not an empty room.