curl -X POST https://api.bota.dev/v1/devices/dev_abc123/heartbeat \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"device_state": "idle",
"pending_recordings": 3,
"connection_type": ["ble"]
}'
curl -X POST https://api.bota.dev/v1/devices/me/heartbeat \
-H "Authorization: Bearer dtok_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"battery_mv": 3820,
"is_charging": false,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"signal_strength_dbm": -75,
"firmware_version": "1.2.3",
"device_state": "idle",
"pending_recordings": 3,
"flags": 8,
"connection_type": ["wifi", "4g"],
"lte_status": "connected",
"wifi_status": "connected"
}'
// Developer's backend relays device status read over BLE
app.post('/devices/:id/heartbeat', auth, async (req, res) => {
const response = await fetch(
`https://api.bota.dev/v1/devices/${req.params.id}/heartbeat`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${BOTA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
...req.body,
connection_type: ['ble'],
}),
}
);
res.json(await response.json());
});
{
"status": "ok",
"pending_commands": [
{
"id": "cmd_xyz789",
"type": "factory_reset",
"params": {},
"grant_token": "rct_...",
"expires_at": null
}
]
}
{
"error": {
"code": "forbidden",
"message": "Device token does not match device ID"
}
}
Devices
Device Heartbeat
Report device health status for fleet monitoring
POST
/
devices
/
{id}
/
heartbeat
curl -X POST https://api.bota.dev/v1/devices/dev_abc123/heartbeat \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"device_state": "idle",
"pending_recordings": 3,
"connection_type": ["ble"]
}'
curl -X POST https://api.bota.dev/v1/devices/me/heartbeat \
-H "Authorization: Bearer dtok_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"battery_mv": 3820,
"is_charging": false,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"signal_strength_dbm": -75,
"firmware_version": "1.2.3",
"device_state": "idle",
"pending_recordings": 3,
"flags": 8,
"connection_type": ["wifi", "4g"],
"lte_status": "connected",
"wifi_status": "connected"
}'
// Developer's backend relays device status read over BLE
app.post('/devices/:id/heartbeat', auth, async (req, res) => {
const response = await fetch(
`https://api.bota.dev/v1/devices/${req.params.id}/heartbeat`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${BOTA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
...req.body,
connection_type: ['ble'],
}),
}
);
res.json(await response.json());
});
{
"status": "ok",
"pending_commands": [
{
"id": "cmd_xyz789",
"type": "factory_reset",
"params": {},
"grant_token": "rct_...",
"expires_at": null
}
]
}
{
"error": {
"code": "forbidden",
"message": "Device token does not match device ID"
}
}
Report device health status including battery level, storage usage, and signal strength. Health data is stored on the device record and returned in Get Device and List Devices responses.
Authentication
This endpoint accepts two authentication methods depending on the device connectivity:| Path | Auth | Use case |
|---|---|---|
| 4G/WiFi direct | Device token | Device reports its own status directly |
| BLE relay | API key | Developer’s backend relays status read from device over Bluetooth |
curl -X POST https://api.bota.dev/v1/devices/dev_abc123/heartbeat \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"device_state": "idle",
"pending_recordings": 3,
"connection_type": ["ble"]
}'
curl -X POST https://api.bota.dev/v1/devices/me/heartbeat \
-H "Authorization: Bearer dtok_..." \
-H "Content-Type: application/json" \
-d '{
"battery_percent": 85,
"battery_mv": 3820,
"is_charging": false,
"storage_used_mb": 512,
"storage_total_mb": 32768,
"signal_strength_dbm": -75,
"firmware_version": "1.2.3",
"device_state": "idle",
"pending_recordings": 3,
"flags": 8,
"connection_type": ["wifi", "4g"],
"lte_status": "connected",
"wifi_status": "connected"
}'
// Developer's backend relays device status read over BLE
app.post('/devices/:id/heartbeat', auth, async (req, res) => {
const response = await fetch(
`https://api.bota.dev/v1/devices/${req.params.id}/heartbeat`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${BOTA_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
...req.body,
connection_type: ['ble'],
}),
}
);
res.json(await response.json());
});
Path Parameters
string
required
The device’s unique identifier (e.g.,
dev_abc123), or me when using a device token. The me alias resolves to the device ID associated with the token, so the device doesn’t need to know its own Bota ID. When using an explicit device ID with a device token, it must match the token’s device.Request Body
All fields are optional — send only the metrics your device can report.integer
Current battery level (0-100).
integer
Battery voltage in millivolts (e.g., 3700 = 3.7V). Useful for diagnosing power issues.
boolean
Whether the device is currently charging.
integer
Storage used in megabytes.
integer
Total storage capacity in megabytes.
integer
Cellular signal strength in dBm (typically -50 to -120, where higher/less negative is better).
string
Current firmware version string (max 32 characters).
string
Device name (max 64 characters). Updated in the device record when provided.
string
Current device operational state (max 32 characters). One of:
idle, recording, syncing, uploading, charging, lowBattery, storageFull, error.integer
Number of recordings on the device pending sync/upload.
integer
Device status flags as a 1-byte bitmask (0-255). Bit 0: charging, Bit 1: low battery, Bit 2: storage full, Bit 3: WiFi connected, Bit 4: LTE connected, Bit 5: sync active.
string
LTE/4G modem status. One of:
off, searching, registered, connected, denied, no_sim, error, low_voltage, disabled.string
WiFi radio status. One of:
off, scanning, connecting, connected, connect_failed, no_credentials, disabled, error.string[]
Active device connections. Array of:
wifi, 4g, ble.string
The channel currently being used to upload recordings. One of:
wifi, 4g, ble. Set to null to clear. Omit if no upload is in progress.Response
Returns{ "status": "ok" } on success. A direct WiFi/4G device heartbeat may
also include pending_commands. A delivered factory_reset remains in this
array until the device successfully acknowledges it; ordinary commands are not
redelivered after their first delivery.
{
"status": "ok",
"pending_commands": [
{
"id": "cmd_xyz789",
"type": "factory_reset",
"params": {},
"grant_token": "rct_...",
"expires_at": null
}
]
}
{
"error": {
"code": "forbidden",
"message": "Device token does not match device ID"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
status | string | ok on success |
pending_commands | array | Commands for direct device execution; omitted when empty |
Recommended Heartbeat Interval
| Scenario | Interval |
|---|---|
| Normal operation | Every 15-30 minutes |
| Low battery (< 20%) | Every 5 minutes |
| Charging | Every 30-60 minutes |
| Poor signal (< -100 dBm) | Every 5-10 minutes |
Field Constraints
| Field | Type | Range |
|---|---|---|
battery_percent | integer | 0-100 |
battery_mv | integer | >= 0 (millivolts) |
is_charging | boolean | true / false |
storage_used_mb | integer | >= 0 |
storage_total_mb | integer | >= 0 |
signal_strength_dbm | integer | <= 0 (typically -50 to -120) |
firmware_version | string | max 32 characters |
device_name | string | max 64 characters |
device_state | string | max 32 characters |
pending_recordings | integer | >= 0 |
flags | integer | 0-255 |
lte_status | string | off, searching, registered, connected, denied, no_sim, error, low_voltage, disabled |
wifi_status | string | off, scanning, connecting, connected, connect_failed, no_credentials, disabled, error |
connection_type | string[] | Array of wifi, 4g, ble |
upload_channel | string | null | wifi, 4g, or ble; null to clear |
Was this page helpful?

