The backend API uses REST endpoints for communication between the React frontend and multiple robots (Boston Dynamics Spot, Ghost Robotics Vision 60) through their respective SDKs.
- Development:
http://localhost:8000/api - Production:
http://<server-ip>:8000/api
Authentication uses JWT tokens. Log in to receive a token and pass it in the Authorization header for all API calls.
All responses are JSON with the following structure:
{
"success": true,
"data": { ... }
}{
"error": "Error message",
"code": "ERROR_CODE"
}POST /auth/login
Content-Type: application/json
{
"username": "admin",
"password": "<your_password>"
}Response:
{
"token": "eyJ...",
"user": "admin"
}Use token in headers:
Authorization: Bearer eyJ...
GET /robots
Authorization: Bearer <token>Response:
{
"robots": [
{
"id": "spot",
"name": "Boston Dynamics Spot",
"type": "spot",
"ip": "192.168.1.199",
"connected": true,
"active": true
},
{
"id": "ghost",
"name": "Ghost Vision 60",
"type": "ghost_v60",
"ip": "192.168.168.105",
"connected": true,
"active": false
}
]
}GET /robots/activeResponse: {"active": "spot"}
POST /robots/active
Content-Type: application/json
{"robot_id": "ghost"}Response: {"active": "ghost"}
All /robot/* endpoints operate on the currently active robot.
GET /robot/gaitResponse:
{
"gaits": {
"0": "TROT_WALK",
"1": "RUN",
"2": "HILL",
"3": "CRAWL",
"4": "SAND",
"5": "DOCK",
"6": "BLIND_STAIRS",
"7": "HIGH_STEP"
}
}POST /robot/gait
Content-Type: application/json
{"gait": 3}Response: {"success": true, "gait": 3}
Returns 400 if gait control is not supported on the active robot.
POST /robot/connect
Content-Type: application/json
{
"ip": "192.168.1.100"
}Response:
{
"success": true,
"message": "Connected to robot"
}POST /robot/disconnectGET /robot/statusResponse:
{
"connected": true,
"robot_ip": "192.168.1.100"
}GET /robot/stateResponse:
{
"battery": 87.5,
"is_powered": 2,
"timestamp": 1708331400
}Fields:
battery- Battery percentage (0-100)is_powered- Power state (0=OFF, 1=UNKNOWN, 2=ON)timestamp- Unix timestamp
GET /robot/pose
Authorization: Bearer <token>Returns the robot's current pose in the odom frame as position + quaternion. Used by the multi-robot RL coordination API.
Response:
{
"x": 1.23,
"y": -0.45,
"z": 0.52,
"qx": 0.0,
"qy": 0.0,
"qz": 0.1736,
"qw": 0.9848,
"frame": "odom"
}Fields:
x,y,z- Position in odom frame (meters)qx,qy,qz,qw- Orientation quaternion in odom frameframe- Always"odom"
POST /robot/goto
Authorization: Bearer <token>
Content-Type: application/json
{
"x": 2.0,
"y": 1.0,
"yaw": 0.5,
"frame": "odom"
}Sends the robot to an SE2 waypoint. Returns immediately without blocking.
Robot must be powered on and standing; returns 409 if not.
Used by the multi-robot RL coordination API.
Parameters:
x- Target x position in meters (required)y- Target y position in meters (required)yaw- Target heading in radians (optional, default0.0)frame- Reference frame (optional, default"odom")
Response (200):
{
"status": "success",
"x": 2.0,
"y": 1.0,
"yaw": 0.5,
"frame": "odom"
}Error (409 - not standing/powered):
{
"error": "Robot motors are not powered on"
}POST /robot/standResponse:
{
"success": true,
"message": "Stand command sent"
}POST /robot/sitPOST /robot/move
Content-Type: application/json
{
"vx": 0.5,
"vy": 0.0,
"v_rot": 0.0
}Parameters:
vx- Forward/backward velocity in m/s (-2.0 to 2.0)vy- Left/right (lateral) velocity in m/s (-2.0 to 2.0)v_rot- Rotation velocity in rad/s (-2.0 to 2.0)
Response:
{
"success": true
}POST /robot/stopGET /robot/obstacle_avoidanceResponse:
{
"enabled": true
}POST /robot/obstacle_avoidance
Content-Type: application/json
{
"enabled": false
}Response:
{
"success": true,
"enabled": false
}GET /camerasResponse:
{
"cameras": [
{
"name": "back_rgb",
"image_type": "RGB"
},
{
"name": "front_rgb",
"image_type": "RGB"
},
{
"name": "left_rgb",
"image_type": "RGB"
},
{
"name": "right_rgb",
"image_type": "RGB"
}
]
}GET /camera/{camera_name}/imageResponse:
- Content-Type:
image/jpeg - Binary JPEG image data
Example (with token for img tags):
GET /camera/frontleft_fisheye_image/image?token=eyJ...
GET /camera/{camera_name}/streamResponse:
- Content-Type:
multipart/x-mixed-replace; boundary=frame - Continuous MJPEG stream
Example:
<img src="/api/camera/frontleft_fisheye_image/stream?token=eyJ..." />| Code | Status | Meaning |
|---|---|---|
| 200 | OK | Request successful |
| 400 | Bad Request | Invalid parameters |
| 500 | Server Error | Internal server error |
| 503 | Unavailable | Robot not connected |
No rate limiting is currently implemented. In production, implement appropriate rate limiting.
Not applicable - all endpoints return complete data.
Not applicable - robot commands are global.
// Connect to robot
async function connectToRobot(ip) {
const response = await fetch('/api/robot/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ip })
});
return await response.json();
}
// Get robot state
async function getRobotState() {
const response = await fetch('/api/robot/state');
return await response.json();
}
// Move robot
async function moveRobot(vx, vy, v_rot) {
const response = await fetch('/api/robot/move', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ vx, vy, v_rot })
});
return await response.json();
}
// Stand
async function standUp() {
const response = await fetch('/api/robot/stand', {
method: 'POST'
});
return await response.json();
}import requests
BASE_URL = "http://localhost:5000/api"
# Connect to robot
response = requests.post(
f"{BASE_URL}/robot/connect",
json={"ip": "192.168.1.100"}
)
print(response.json())
# Get robot state
response = requests.get(f"{BASE_URL}/robot/state")
print(response.json())
# Move robot
response = requests.post(
f"{BASE_URL}/robot/move",
json={"vx": 0.5, "vy": 0, "v_rot": 0}
)
print(response.json())# Connect to robot
curl -X POST http://localhost:5000/api/robot/connect \
-H "Content-Type: application/json" \
-d '{"ip":"192.168.1.100"}'
# Get robot state
curl http://localhost:5000/api/robot/state
# Move robot forward
curl -X POST http://localhost:5000/api/robot/move \
-H "Content-Type: application/json" \
-d '{"vx":0.5,"vy":0,"v_rot":0}'
# Sit down
curl -X POST http://localhost:5000/api/robot/sit
# Stop
curl -X POST http://localhost:5000/api/robot/stopCurrently using HTTP polling for state updates. Consider upgrading to WebSocket for:
- Real-time state updates
- Lower latency
- Bidirectional communication
- Better performance with multiple camera streams
- Connection establishment: ~500-2000ms
- State update latency: 100-500ms
- Camera frame latency: 50-200ms (MJPEG)
- Typical bandwidth: 2-5 Mbps per camera stream
API Version: 1.0.0
Last Updated: February 19, 2026