Telemetry API
Overview
Section titled “Overview”The Botbit Telemetry API allows your robot fleet’s primary controllers to push operational metrics directly to Botbit. Each telemetry report updates the robot’s cumulative counters and automatically evaluates usage-based maintenance rules — generating tasks when robots approach service thresholds.
What the API accepts:
- Operating hours (lifetime cumulative)
- Miles driven (lifetime cumulative)
- Battery charge cycles (lifetime cumulative)
- Software versions (firmware, OS, app)
What happens when data arrives:
- Telemetry is stored (one row per robot per day)
- Robot aggregate counters are updated
- Usage-based maintenance rules are evaluated
- Tasks are auto-created when a robot is within 10% of a service interval
Architecture: Push Model
Section titled “Architecture: Push Model”Your robot’s primary controller sends data to Botbit. Botbit does not poll your robots.
┌──────────────────────┐ ┌─────────────────────────┐│ Primary Controller │ │ Botbit OpsCenter ││ (on the robot) │────────▶│ POST /api/telemetry/ ││ │ HTTPS │ ingest │└──────────────────────┘ └─────────────────────────┘ │ ├─ Store telemetry ├─ Update robot counters └─ Evaluate maintenance rules └─ Create tasks if within 10%Why push?
- Lower latency: Maintenance rules evaluate the moment new data arrives, not on a polling schedule
- Simpler networking: Robots need outbound HTTPS only — no inbound ports to open
- Idempotent: Sending the same report twice is harmless (upsert by robot + date)
- Scales naturally: Each robot reports independently; no central poller to bottleneck
Scope: What Data Can Be Sent
Section titled “Scope: What Data Can Be Sent”One API key covers your entire organization
Section titled “One API key covers your entire organization”An API key is scoped to your organization, not to an individual robot. Any robot in the org can be identified by its serial_number in the request body.
You can create multiple keys for different purposes (one per factory, one per site, etc.), but each key works for all robots in the org.
Robot-level metrics only
Section titled “Robot-level metrics only”The API accepts robot-level cumulative totals — the values that the primary controller tracks for the whole robot:
| Metric | Field | Example |
|---|---|---|
| Operating hours | operating_hours | 1250.5 |
| Miles driven | miles_driven | 843.2 |
| Battery charge cycles | battery_charge_cycles | 312 |
It does not accept per-component health scores or status. Telemetry is about the robot as a whole, not individual components like a LIDAR or motor. Component health tracking is a separate planned feature.
Cumulative lifetime values
Section titled “Cumulative lifetime values”All metrics are lifetime cumulative totals — “this robot has driven 843 miles total”, not “it drove 5 miles since last report.” This makes the endpoint idempotent: re-sending the same report doesn’t double-count anything.
Authentication
Section titled “Authentication”Creating an API Key
Section titled “Creating an API Key”- Go to Settings → API & Integrations in the Botbit dashboard
- Click Create API Key
- Enter a name (e.g., “Factory Floor Controller”)
- Copy the key immediately — it is shown once and cannot be retrieved later
- The key starts with
bb_live_followed by a random string
Only organization admins can create and revoke API keys.
Using the Key
Section titled “Using the Key”Include the key in the Authorization header:
POST /api/telemetry/ingestAuthorization: Bearer bb_live_a1b2c3d4e5f6...Content-Type: application/jsonKey Security
Section titled “Key Security”- Only the SHA-256 hash is stored — Botbit cannot recover your key
- Keys can be revoked instantly in Settings (the key stops working immediately)
- If a key is compromised, revoke it and create a new one
- Keys have no expiration by default
Endpoint Reference
Section titled “Endpoint Reference”POST /api/telemetry/ingest
Section titled “POST /api/telemetry/ingest”Send telemetry data for a single robot.
Request Body
Section titled “Request Body”{ "serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T14:30:00Z", "operating_hours": 1250.5, "miles_driven": 843.2, "battery_charge_cycles": 312, "firmware_version": "3.2.1", "os_version": "1.0.4", "app_version": "2.1.0"}Required Fields
Section titled “Required Fields”| Field | Type | Description |
|---|---|---|
serial_number | string | The robot’s serial number or display ID (e.g., ROB-2024-00142 or BOT-2026-00028) |
timestamp | string | ISO 8601 datetime of the telemetry reading |
Plus at least one of:
| Field | Type | Description |
|---|---|---|
operating_hours | number | Lifetime cumulative operating hours |
miles_driven | number | Lifetime cumulative miles driven |
battery_charge_cycles | number | Lifetime cumulative charge cycles |
Optional Fields
Section titled “Optional Fields”| Field | Type | Description |
|---|---|---|
firmware_version | string | Current firmware version |
os_version | string | Current OS version |
app_version | string | Current application version |
Success Response (200)
Section titled “Success Response (200)”{ "success": true, "robot_id": "uuid-of-the-robot", "telemetry_date": "2026-01-29", "tasks_generated": 1}tasks_generated indicates how many maintenance tasks were automatically created based on the new telemetry data.
Error Responses
Section titled “Error Responses”| Status | Body | Meaning |
|---|---|---|
400 | {"error": "serial_number is required"} | Missing or invalid request body |
400 | {"error": "At least one metric ... is required"} | No metrics provided |
400 | {"error": "timestamp must be a valid ISO 8601 date"} | Unparseable timestamp |
401 | {"error": "API key invalid"} | Missing, malformed, or revoked key |
401 | {"error": "API key expired"} | Key has passed its expiration date |
404 | {"error": "Robot '...' not found in this organization"} | Serial number / display ID doesn’t match any robot in this org |
429 | {"error": "Rate limit exceeded"} | Too many requests (see Rate Limiting) |
500 | {"error": "Internal server error"} | Server-side failure |
Response Headers
Section titled “Response Headers”| Header | Description |
|---|---|
X-RateLimit-Remaining | Requests remaining in the current window |
Retry-After | Seconds to wait (only on 429 responses) |
Rate Limiting
Section titled “Rate Limiting”Each API key is limited to 60 requests per minute. This is a sliding window — the counter resets 60 seconds after the first request in a window.
If you exceed the limit, you’ll receive a 429 response with a Retry-After header indicating how many seconds to wait.
For most deployments, sending telemetry once per hour or once per day per robot is sufficient.
How Maintenance Tasks Are Generated
Section titled “How Maintenance Tasks Are Generated”When telemetry arrives, Botbit evaluates all usage-based maintenance rules for that robot’s build configuration. Here’s the logic:
The 10% Threshold
Section titled “The 10% Threshold”A maintenance task is created when a robot is within 10% of the next service interval.
Example: A rule says “service every 100 miles.”
| Robot’s Current Miles | Next Threshold | Remaining | 10% of Interval | Task Created? |
|---|---|---|---|---|
| 50 | 100 | 50 | 10 | No (50 > 10) |
| 85 | 100 | 15 | 10 | No (15 > 10) |
| 91 | 100 | 9 | 10 | Yes (9 ≤ 10) |
| 143 | 200 | 57 | 10 | No (57 > 10) |
| 192 | 200 | 8 | 10 | Yes (8 ≤ 10) |
Deduplication
Section titled “Deduplication”Botbit will not create duplicate tasks for the same threshold. If a task already exists for robot + rule + threshold value (regardless of task status — To Do, Done, Skip, etc.), it is skipped.
This means:
- Sending telemetry multiple times at 91 miles → only one task for the 100-mile threshold
- Completing the task at 98 miles, then sending telemetry at 99 miles → no new task (the 100-mile threshold is already covered)
- After crossing 100 miles, the next threshold becomes 200 miles
Task Details
Section titled “Task Details”Auto-generated tasks include:
- Title: The maintenance action name from the rule
- Due date: 7 days from when the threshold was crossed
- Priority: Inherited from the maintenance rule
- Criteria: Human-readable explanation, e.g., “Within 10% of 100 miles threshold (91/100)“
Testing the API
Section titled “Testing the API”Prerequisites
Section titled “Prerequisites”- A robot activated in Botbit with a known serial number
- A maintenance rule with
interval_milesorinterval_hourson that robot’s build configuration - An API key (created in Settings → API & Integrations)
Step 1: Send Telemetry
Section titled “Step 1: Send Telemetry”curl -X POST https://your-app.com/api/telemetry/ingest \ -H "Authorization: Bearer bb_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T14:30:00Z", "operating_hours": 1250.5, "miles_driven": 843.2, "battery_charge_cycles": 312 }'For local development, replace https://your-app.com with http://localhost:9002.
Step 2: Verify the Response
Section titled “Step 2: Verify the Response”A successful response looks like:
{ "success": true, "robot_id": "abc-123-def", "telemetry_date": "2026-01-29", "tasks_generated": 0}tasks_generated: 0 means no thresholds were crossed. To trigger a task, set miles_driven or operating_hours to within 10% of a rule’s interval.
Step 3: Verify in the Dashboard
Section titled “Step 3: Verify in the Dashboard”- Assets page: The robot’s miles/hours should reflect the new values
- Maintenance page: If a task was generated, it appears in the “To Do” column
Step 4: Test Error Cases
Section titled “Step 4: Test Error Cases”# Missing API key → 401curl -X POST https://your-app.com/api/telemetry/ingest \ -H "Content-Type: application/json" \ -d '{"serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T14:30:00Z", "miles_driven": 100}'
# Wrong serial number → 404curl -X POST https://your-app.com/api/telemetry/ingest \ -H "Authorization: Bearer bb_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{"serial_number": "NONEXISTENT", "timestamp": "2026-01-29T14:30:00Z", "miles_driven": 100}'
# No metrics → 400curl -X POST https://your-app.com/api/telemetry/ingest \ -H "Authorization: Bearer bb_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{"serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T14:30:00Z"}'Step 5: Test Task Generation
Section titled “Step 5: Test Task Generation”If you have a rule “service every 100 miles”:
# Robot at 91 miles → should generate a task (within 10%)curl -X POST http://localhost:9002/api/telemetry/ingest \ -H "Authorization: Bearer bb_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T15:00:00Z", "miles_driven": 91 }'# Expected: tasks_generated: 1
# Send again at 92 miles → should NOT create duplicatecurl -X POST http://localhost:9002/api/telemetry/ingest \ -H "Authorization: Bearer bb_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "serial_number": "BOT-2025-00001", "timestamp": "2026-01-29T16:00:00Z", "miles_driven": 92 }'# Expected: tasks_generated: 0Integration Patterns
Section titled “Integration Patterns”Single Controller per Robot
Section titled “Single Controller per Robot”The most common pattern. Each robot’s primary controller sends its own telemetry on a schedule (e.g., every hour):
Robot A ──POST──▶ /api/telemetry/ingest (serial_number: "BOT-001")Robot B ──POST──▶ /api/telemetry/ingest (serial_number: "BOT-002")Robot C ──POST──▶ /api/telemetry/ingest (serial_number: "BOT-003")All three use the same API key.
Gateway / Fleet Aggregator
Section titled “Gateway / Fleet Aggregator”A central service collects telemetry from all robots and forwards it to Botbit:
Robot A ──▶ ┌──────────┐Robot B ──▶ │ Gateway │──POST──▶ /api/telemetry/ingest (one call per robot)Robot C ──▶ └──────────┘The gateway makes one API call per robot. There is no batch endpoint — each robot is a separate POST.
Recommended Reporting Frequency
Section titled “Recommended Reporting Frequency”| Use Case | Frequency | Rate Limit Impact |
|---|---|---|
| Standard fleet | Every 1 hour | ~0.02 req/min per robot |
| High-utilization | Every 15 minutes | ~0.07 req/min per robot |
| Daily summary | Once per day | Negligible |
With the 60 req/min limit, a single API key can support hundreds of robots reporting hourly.
Can I send telemetry for a robot that doesn’t exist yet?
No. The robot must be activated in Botbit first. The serial_number field accepts either the robot’s hardware serial number (e.g., ROB-2024-00142) or its Botbit display ID (e.g., BOT-2026-00028). You’ll get a 404 error if neither matches.
What happens if I send the same data twice? Nothing bad. Telemetry is upserted by robot + date, so duplicate reports overwrite the previous values. Maintenance rules re-evaluate but won’t create duplicate tasks.
Do maintenance counters reset when a task is completed?
No. Counters are lifetime cumulative. The algorithm uses floor(current / interval) to determine which cycle the robot is in. After completing a task at 98 miles (interval = 100), the next threshold is automatically 200 miles.
Can I send data about individual components? Not currently. The API accepts robot-level metrics only. Per-component telemetry (health scores, individual sensor data) is a planned future feature.
Can I use this API to pull data from Botbit? No. This is an ingest-only endpoint. There is no read API for telemetry data at this time.
What if my robot skips past a threshold? The algorithm handles this. If a robot jumps from 80 miles to 150 miles in one report, it calculates the correct cycle and targets the next threshold (200 miles). The skipped threshold (100) does not generate a retroactive task.