HTTP API¶
XPARO has three HTTP interfaces. Everything on this page was run against an XPARO server; the responses shown are real.
Address |
Signs in with |
For |
|---|---|---|
|
the secret key or the robot’s credential, in the address |
Robots: get the project sync, send any robot message. |
|
|
Robots: upload recordings. |
|
your XPARO username and password |
Your own scripts: read project data. |
All addresses start with https://xparo.in.
Robot API¶
GET returns the same project sync a robot receives when its WebSocket
connects:
curl https://xparo.in/chatbot_api/<secret-key>/<project-id>/
{"title": "Hospital Delivery Bot", "status": true, "aiml": "...", "custom_aiml": {...},
"maps": "...", "custom_maps": {...}, "Sets": "...", "custom_Sets": {...}, "properties": "...",
"custom_tasks": {...}, "custom_node_files": {...}, "System": ""}
POST takes one JSON message, exactly as it would be sent over the
WebSocket (see Message catalogue), and returns the server’s reply, {} when
there is none. This is how xparo_ros sends its heartbeat:
curl -X POST -H "Content-Type: application/json" \
-d '{"ROBOT_HEARTBEAT": {"device_id": "my-robot-0001"}}' \
https://xparo.in/chatbot_api/<key>/<project-id>/
{}
Things to know:
Every response has status 201, including errors. A wrong key returns
{"error": "user not exists go to ... and check"}, so check the body, not only the status.HTTP is one way: the robot asks, the server answers. Dashboard commands (Run now, terminal, teleop, files…) cannot reach a robot this way; they need the WebSocket (Connection protocol).
Uploading recordings¶
xparo_ros uploads ROS bag files here (see ROS bag recording). The
token is the REST_API_TOKEN the server sends in reply to
ADD_robots_info.
curl -H "Authorization: Token <REST_API_TOKEN>" \
-F "bag_file=@rosbag2_2026_10_06-08_30_00_0.mcap.zstd" \
-F "robot_id=my-robot-0001" \
-F 'data={"note": "test"}' \
https://xparo.in/api/upload_rosbag/
{"status":"success","message":"File rosbag2_2026_10_06-08_30_00_0.mcap.zstd saved to Azure","db_id":"9d022794-bec6-48e1-8adf-ef0d0f78a2ff"}
robot_id is the robot’s device_id; data is optional JSON stored
with the file. The file appears in Database → Sensors.
Status |
Meaning |
|---|---|
201 |
Stored. |
400 |
No |
401 |
No token: |
402 |
The project is out of storage credits. Uploads pause until you top up; existing data is kept. |
403 |
The token’s account is not a member of the robot’s project, or is a Viewer. |
404 |
No robot with that |
Reading project data from a script¶
/get_project_data/-/<project-id>/ lets a script read what the dashboard
shows, signing in with your XPARO username and password (HTTP Basic). It
takes a form field data holding the same JSON the dashboard sends; the
answer is under u → project ID.
import json
import requests
SERVER = "https://xparo.in"
PROJECT_ID = "<your-project-id>"
AUTH = ("<your-username>", "<your-password>")
def ask(key, payload):
data = json.dumps({"p": {PROJECT_ID: {key: payload}}})
reply = requests.post(f"{SERVER}/get_project_data/-/{PROJECT_ID}/",
data={"data": data}, auth=AUTH, timeout=30)
reply.raise_for_status()
return reply.json()["u"][PROJECT_ID]
for task in ask("GET_services", {})["services"]:
print(task["id"], task["title"], task["status"])
history = ask("GET_Task_history_database", {"current_page": 1})["task_history"]
print(history["totalRecords"], "runs saved")
for run in history["records"]:
out = run["fields"]["output_data"]
print(run["fields"]["created_at"], out.get("outcome"), f"{out.get('duration_s', 0):.1f}s")
Output:
3dffb995-298e-4335-a0a9-b38aecc396fa Deliver medicine development
2 runs saved
2026-10-06T02:30:03.340Z failed 0.3s
2026-10-06T02:29:47.379Z success 11.9s
curl -u '<your-username>:<your-password>' \
--data-urlencode 'data={"p": {"<project-id>": {"GET_Task_history_database": {"current_page": 1}}}}' \
https://xparo.in/get_project_data/-/<project-id>/
{"u": {"<project-id>": {"task_history": {"records": [...], "totalRecords": 2,
"currentPage": 1, "pageSize": 10, "columns": ["id", "type", "created_at"]}}}}
GET_services lists the project’s tasks; GET_Task_history_database
returns saved task runs, 10 per page. Without a username and password, or
with a wrong one, the answer is 403.
You can read data this way, but you cannot run or cancel tasks:
RUN_TASK answers
{"error": "RUN_TASK cannot be dispatched over the REST endpoint -- it requires a live robot connection to relay to. Use the dashboard's live session instead."}
To start a task from outside the dashboard, publish on the robot’s /xparo/run_task topic instead.
Reports¶
The PDF report and Excel buttons on the project’s Dashboard page
(/api/download-report/pdf/<project-slug>/ and .../excel/...) need a
signed-in browser session. They are not available to scripts.