> For the complete documentation index, see [llms.txt](https://docs.veerobot.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.veerobot.com/ros-robots/beetle-bot-plus/for-developers/http-and-webhooks.md).

# HTTP API and Webhooks

OpenAPI on port 8080, allowlisted publish, and event webhooks

Base URL: `http://<robot-ip>:8080`

Interactive contract: **`http://<robot-ip>:8080/docs`**, that page is the source of truth for request bodies. The snippets below are orientation.

Same contract overview: [VEEStack → HTTP API](/veestack/research/http-api.md) (limits). This page is the worked example.

## Login

Sign in as **`developer`** (sheet password) for teleop and topic tools. Webhook configuration needs the **`admin`** role (IT / VEERobot, not on the student sheet).

```bash
TOKEN=$(curl -s -X POST http://<robot-ip>:8080/api/v1/auth/login \
 -H 'Content-Type: application/json' \
 -d '{"username":"developer","password":"<password>"}' \
 | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
```

## Drive

The HTTP body uses linear / angular floats. The gateway wraps them for the robot.

```bash
curl -X POST http://<robot-ip>:8080/api/v1/robot/teleop \
 -H "Authorization: Bearer $TOKEN" \
 -H 'Content-Type: application/json' \
 -d '{"linear": 0.2, "angular": 0.0}'
```

ARM from the dashboard (or `/veeros/arm` over ROS) before you expect wheels to move.

## Introspection

```bash
curl -H "Authorization: Bearer $TOKEN" http://<robot-ip>:8080/api/v1/developer/topics
curl -H "Authorization: Bearer $TOKEN" http://<robot-ip>:8080/api/v1/developer/tf
```

## Allowlisted publish

Topic publish from HTTP is **allowlist-only**. `/goal_pose` is typical:

```bash
curl -X POST "http://<robot-ip>:8080/api/v1/developer/topics/goal_pose/publish" \
 -H "Authorization: Bearer $TOKEN" \
 -H 'Content-Type: application/json' \
 -d '{"x": 1.0, "y": 0.5, "theta": 0.0}'
```

Need an arbitrary topic? Use SSH and `ros2 topic pub` or `ros2 run`, see [ROS 2](/ros-robots/beetle-bot-plus/for-developers/ros2.md).

Navigation REST (`/api/v1/robot/nav-goal`, `/api/v1/maps/*`, `/api/v1/mapping/*`) needs the navigation license.

## Webhooks

The gateway POSTs JSON to your server on robot events. Configure endpoints with an **admin** token (IT only):

`GET` / `PUT` `/api/v1/config/developer/webhooks`

```bash
ADMIN=$(curl -s -X POST http://<robot-ip>:8080/api/v1/auth/login \
 -H 'Content-Type: application/json' \
 -d '{"username":"admin","password":"<admin-password>"}' \
 | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

curl -X PUT http://<robot-ip>:8080/api/v1/config/developer/webhooks \
 -H "Authorization: Bearer $ADMIN" \
 -H 'Content-Type: application/json' \
 -d '{
 "webhooks": [
 {
 "url": "https://example.com/hooks/beetlebot",
 "events": ["robot.armed", "robot.disarmed", "estop.triggered", "mission.completed"],
 "secret": "optional-hmac-secret"
 }
 ]
 }'
```

| Event                                   | When               |
| --------------------------------------- | ------------------ |
| `estop.triggered` / `estop.cleared`     | E-stop             |
| `robot.armed` / `robot.disarmed`        | ARM                |
| `mission.started` / `mission.completed` | Dashboard missions |
| `health.fault`                          | Fault              |

Body shape:

```json
{
 "event": "robot.armed",
 "payload": {},
 "timestamp": "2026-09-20T07:00:00.000000+00:00"
}
```

If you set `secret`, the request includes `X-VEECore-Signature`: hex HMAC-SHA256 of the raw JSON body.

Empty `events` or `"*"` receives every event. Details stay on OpenAPI `/docs`.
