---
title: "Get Device Heartbeat"
method: GET
path: "/api/v1/device/heartbeat"
tags: ["Device"]
---

# Get Device Heartbeat

`GET /api/v1/device/heartbeat`

## Request

- Base URL: `https://api.neosapien.xyz` (the document declares no server; this is the origin it was published from)
- URL: `https://api.neosapien.xyz/api/v1/device/heartbeat`
- Auth: HTTP bearer

## Query parameters

- `cursor` string, nullable: Opaque pagination cursor
- `limit` integer: Number of devices per page

## Response `200`

Successful Response

- DeviceHeartbeatResponse
  - `items` DeviceHeartbeatItem[]
    - `user_id` string, required
    - `display_name` string, nullable
    - `last_seen` string, nullable
    - `device_id` string, required
    - `device_status` 'online' | 'offline' | 'never_seen', required
    - `battery_percentage` integer, nullable: Pendant charge in percent (0-100), from the latest valid presence report for this user and device still held in the presence history (about seven days). null when no such report is retained: the device either never reported or last reported before the retention window. This is the app's reported charge, which may be cached.
    - `battery_reported_at` string, nullable: UTC server receipt time of the battery report, not the hardware measurement time. null when battery_percentage is null.
    - `cumulative_usage_minutes` integer, required: Device active time in the window: minutes the pendant was powered on and paired to the phone, whether or not it was recording. Paused and mic-idle time is included. Where no pairing history exists for a user, this falls back to their recording time, so it is never below what recordings alone prove. Not comparable with device_status, which reflects recent audio uploads only: a paused device reads offline while this keeps rising.
    - `report_timestamp` string, nullable: When this response was generated. device_status and cumulative_usage_minutes are as of this instant.
  - `pagination` DeviceHeartbeatPagination
    - `count` integer
    - `has_more` boolean
    - `next_cursor` string, nullable
    - `per_page` integer
    - `total_count` integer
  - `user_code_config` OrgUserCodeConfig
    - `enabled` boolean
    - `label` string
  - `cumulative_usage_window` CumulativeUsageWindow: The 08:00-19:00 IST window, clipped to the report time, that `cumulative_usage_minutes` was measured over.
    - `start` string, nullable, required
    - `end` string, nullable, required

## Other responses

- `400`: Missing organization ID or invalid cursor
- `422`: Validation Error

## Changes

- **2026-10-21** `0408949a6876`: 2 info
  - added the optional property `items/items/battery_percentage` to the response with the `200` status
  - added the optional property `items/items/battery_reported_at` to the response with the `200` status
- **2026-09-22** `4bcce70bd329`: 1 info
  - added the optional property `user_code_config` to the response with the `200` status
- **2026-09-20** `4486a25162fc`: 1 warning, 1 info
  - removed the optional property `report_timestamp` from the response with the `200` status
  - added the optional property `items/items/report_timestamp` to the response with the `200` status
- **2026-09-19** `a60bc05c9244`: 2 info
  - added the optional property `cumulative_usage_window` to the response with the `200` status
  - added the optional property `report_timestamp` to the response with the `200` status
- **2026-09-12** `ae5a08ae5299`: 1 info
  - added the required property `items/items/cumulative_usage_minutes` to the response with the `200` status

[Operation history](https://skmtc.dev/neosapien/apis/neocore/changes/api/v1/device/heartbeat/get.md)

---

[API](https://skmtc.dev/neosapien/apis/neocore.md) - [All operations](https://skmtc.dev/neosapien/apis/neocore/llms.txt) - [OpenAPI document](https://skmtc.dev/neosapien/apis/neocore/revisions/a42bfdafa6fe?raw)
