Analytics API v1
Saha Robotics Analytics API integration guide
Authentication
You must include your API key in the HTTP header for all requests:
x-api-key: <API_KEY>Your API key only grants access to projects assigned to you. If you send a request with an unassigned projectId, you will receive 403.
Base URL
| Environment | URL |
|---|---|
| Production | https://remote.saharobotik.com/api/client/analytics |
| Staging | https://staging.saharobotik.com/api/client/analytics |
Swagger Documentation
| Environment | URL |
|---|---|
| Production | https://remote.saharobotik.com/api/swagger/client/analytics |
| Staging | https://staging.saharobotik.com/api/swagger/client/analytics |
Rate Limit
A maximum of 6 requests per minute is allowed for each endpoint.
When the limit is exceeded, a 429 Too Many Requests error is returned and the limit resets after 60 seconds.
Endpoint Overview
Analytics
| Method | Path | Description |
|---|---|---|
POST | /nltx/summary/{projectId} | Summary statistics for a project |
POST | /nltx/summary/{projectId}/robot/{robotId} | Summary statistics for a specific robot |
POST | /nltx/positions/{projectId}/robot/{robotId} | Robot position data |
POST | /nltx/analyzes/{projectId}/latests | Latest analysis results for a project (max 10) |
GET | /nltx/anomalies/{projectId}/anomaly/{anomalyId} | Details of a specific anomaly |
GET | /nltx/deliveries/average | Average delivery times across all projects |
GET | /nltx/data/{projectId}/most-delivered-locations | Most delivered-to locations (last 3 months) |
Tablet Configuration
| Method | Path | Description |
|---|---|---|
GET | /projects/{projectId}/tablet-config/activated | Active tablet configuration for a project |
Note: In analytics endpoints (
summary,analyzes,anomaly, etc.),project_idin the response is a string (e.g."123"). In the tablet config endpoint,project_idis a number (e.g.7). The{projectId}path parameter is always numeric. UseString(project_id)when comparing.
Project summary statistics
POST /nltx/summary/{projectId}
Returns summary statistics for a project.
Request body
{
"interval": "week"
}interval values (required):
week— last 1 week (-1w)month— last 1 month (-1m)
Response
{
"last_km": 1250.5,
"last_wh": 340.2,
"last_iah": 280.1,
"data_km": [
{ "date": "2026-06-10T00:00:00Z", "value": 12.3 },
{ "date": "2026-06-11T00:00:00Z", "value": 15.7 }
],
"data_km_avg": 14.0,
"data_wh": [
{ "date": "2026-06-10T00:00:00Z", "value": 5.2 },
{ "date": "2026-06-11T00:00:00Z", "value": 6.1 }
],
"data_wh_avg": 5.65,
"data_iah": [
{ "date": "2026-06-10T00:00:00Z", "value": 4.1 },
{ "date": "2026-06-11T00:00:00Z", "value": 4.8 }
],
"data_iah_avg": 4.45,
"data_logs": [
{ "date": "2026-06-10T00:00:00Z", "code": "ROBOT_DELIVERY_TASK_SUCCESS", "value": 42 }
],
"data_logs_avg": [
{ "code": "ROBOT_DELIVERY_TASK_SUCCESS", "value": 38 }
],
"today": "2026-06-17T00:00:00Z",
"interval": ["2026-06-10T00:00:00Z", "2026-06-11T00:00:00Z"],
"most_delivered_locations": [
{ "key": "Table 5", "value": 120 }
]
}Robot summary statistics
POST /nltx/summary/{projectId}/robot/{robotId}
Returns summary statistics for a specific robot.
Request body
{
"interval": "week"
}interval values (required):
week— last 1 week (-1w)month— last 1 month (-1m)
Response
Returns summary statistics in the same structure as the summary endpoint.
Robot position data
POST /nltx/positions/{projectId}/robot/{robotId}
Returns robot position data.
Request body
{
"interval": "week",
"code": "ROBOT_FAILURE",
"map": "map_name"
}All of interval, code, and map are required.
interval values:
week— last 1 week (-1w)month— last 1 month (-1m)
code values: ROBOT_FAILURE, ROBOT_NAV_STUCK, ROBOT_LOC_LOST, ROBOT_INTERNET_CONN_FAILED, etc.
Response
[
{ "x": 12.34, "y": 56.78, "yaw": 1.57 }
]Latest analysis results
POST /nltx/analyzes/{projectId}/latests
Returns the latest analysis results for a project (max 10).
No request body is required. Only the projectId path parameter is sufficient.
POST requests respond with a 201 status code (NestJS default).
The anomaly_id value is obtained from this endpoint. If present, call GET /nltx/anomalies/{projectId}/anomaly/{anomalyId} for anomaly details.
Response
Returns an empty array if no analyses exist:
[]Returns up to 10 records if analyses exist:
[
{
"id": "analysis-id-001",
"project_id": "123",
"robot_id": "robot-001",
"calculator": "weekly",
"score": {
"value": 85,
"based_on": 100
},
"metrics": [
{
"id": "metric-id-001",
"key": "ODOM_KM",
"point": 10,
"weight": 1
}
],
"suggestions": [
{
"id": "suggestion-id-001",
"key": "SUGGESTION_INCREASE_DISTANCE_TRAVELED",
"code": "SUGGESTION_INCREASE_DISTANCE_TRAVELED",
"severity": "medium"
}
],
"created_at": "2026-01-15T10:00:00Z",
"start_date": "2026-01-08T00:00:00Z",
"end_date": "2026-01-15T00:00:00Z",
"anomaly_id": "anomaly-id-001",
"previous_scores": [
{
"value": 80,
"based_on": 100
}
]
}
]| Field | Type | Description |
|---|---|---|
id | string | Analysis record ID |
project_id | string | Project ID |
robot_id | string | Robot ID. Optional; may be absent for project-level analyses |
anomaly_id | string | Anomaly ID. If empty, no anomaly exists |
score | object | Analysis score |
metrics | array | List of metrics |
suggestions | array | List of suggestions |
Anomaly details
GET /nltx/anomalies/{projectId}/anomaly/{anomalyId}
Returns details of a specific anomaly.
The anomaly_id value is obtained from the analyzes/latests response.
If projectId and anomalyId do not match, 404 is returned.
Response
{
"id": "anomaly-id-001",
"project_id": "123",
"robot_id": "robot-001",
"detector": "threshold",
"anomalies": [
{
"detector": "threshold",
"key": "ODOM_KM",
"code": "ANOMALY_ODOM_KM_IS_HIGHER_THAN_EXPECTED",
"type": "too_high",
"level": 2,
"percentage": 35.5
}
],
"created_at": "2026-01-15T10:00:00Z"
}Average delivery times
GET /nltx/deliveries/average
Returns average delivery times across all projects.
This endpoint does not take a projectId in the URL. It returns the average delivery times for all projects in the system (not filtered by the API key's assigned projects).
Response type: Record<string, string> — project ID → duration string.
Response
{
"42": "8m45s",
"56": "12m30s"
}Most delivered locations
GET /nltx/data/{projectId}/most-delivered-locations
Returns the most delivered-to locations (last 3 months).
Returns data for the last 3 months (backend fixed -3m). Returns 403 for unauthorized projectId.
Response
[
{ "key": "Table 5", "value": 120 },
{ "key": "Lobby", "value": 85 }
]Active tablet configuration
GET /projects/{projectId}/tablet-config/activated
Returns the active tablet configuration for a project.
If no active configuration exists, returns 404 with message: Active tablet config not found.
Response
{
"id": 96,
"project_id": 7,
"name": "Configuration Name",
"activated": true,
"deleted": false,
"checksum": "2a308a87",
"created_at": "2023-03-29T20:29:57.539Z",
"updated_at": "2026-04-29T06:27:25.566Z",
"config": {
"videos": {
"home": {
"enabled": true,
"src": [
"https://assets.saharobotik.com/video/.../video1.mp4",
"https://assets.saharobotik.com/video/.../video2.mp4"
],
"loop": true,
"muted": true
},
"going": {
"enabled": false
},
"sleeping": {
"enabled": false
},
"pixelGoing": {
"enabled": false
},
"pixelSleeping": {
"enabled": false
},
"celebrating": {
"enabled": false
},
"celebratingAtTheTarget": {
"enabled": false
}
}
}
}Video Fields
| Field | Type | Description |
|---|---|---|
config.videos.home.src | string | string[] | Default video URLs on the pixel screen (single URL or array) |
config.videos.home.enabled | boolean | Optional. If false, video is disabled; if absent or true, video is enabled |
The
videosfield is optional; if no videos have been configured for the project, it will not be present insideconfig.
Error Codes
| Code | Description |
|---|---|
400 | Invalid request / NLTX service error |
401 | Invalid or missing API key |
403 | You do not have access to this project |
404 | Record not found |
429 | Rate limit exceeded, wait 60 seconds |
500 | Server error |