Bots
Per-bot REST routes. The :id segment maps to the dispatcher's
id argument — same identifier shown in the dashboard's bot list
(bot-1, bot-2, …).
| Method | Path | Body |
|---|---|---|
GET | /api/bots | — |
GET | /api/bots/{id} | — |
POST | /api/bots/{id}/connect | — |
POST | /api/bots/{id}/reconnect | — — alias of connect |
POST | /api/bots/{id}/disconnect | — |
POST | /api/bots/{id}/warp | {world} |
POST | /api/bots/{id}/leave | — |
POST | /api/bots/{id}/walk_to | {x, y} |
GET | /api/bots/{id}/collectables | — |
GET | /api/bots/{id}/enemies | — |
GET | /api/bots/{id}/minimap | — |
GET | /api/bots/{id}/recent_worlds | ?timeout_ms (opt) — server reply with the bot's last visited worlds |
GET | /api/bots/{id}/active_worlds | ?timeout_ms (opt) — list of currently-populated worlds |
GET | /api/bots/{id}/world_info | ?world&timeout_ms — single-world player count + flags |
POST | /api/bots/{id}/tutorial | — |
All endpoints require the bearer header. Responses share the
{"error": "..."} envelope on failure.
GET /api/bots
List all spawned bots with a lite snapshot (no inventory contents, no full world tile grid) so the response stays under a few KB.
Response (200):
{
"bots": [
{
"id": "bot-1",
"status": "in_world",
"device_id": "ae7b7219cfb72594",
"current_host": "game-lava.pixelworlds.pw",
"current_port": 10001,
"current_world": "MINEWORLD",
"pending_world": null,
"username": "P71710199",
"user_id": "69fd4201a4fa2bc68c51dc27",
"player_position": { "map_x": 42.0, "map_y": 18.0,
"world_x": 13.44, "world_y": 5.76 },
"inventory_count": 18,
"gems": 1250,
"byte_coins": 180,
"xp_amount": 420,
"experience": 1200,
"xp_level": 3,
"slots": 32,
"tutorial_state": 7,
"tutorial_running": false,
"ping_ms": 47,
"proxy_name": null,
"proxy_kind": null,
"connected_since": 1778205616123,
"fishing_active": false,
"fishing_info": null,
"last_error": null
}
]
}
status is one of: connecting, authenticating, menu_ready,
joining_world, loading_world, awaiting_ready, in_world,
redirecting, reconnecting, disconnected, already_connected,
banned, kicked, error.
GET /api/bots/{id}
Full snapshot for a single bot, including the inventory list and world tile counts.
Response (200): every field from the list snapshot above, plus:
{
"world": {
"world_name": "MINEWORLD",
"width": 100,
"height": 60,
"spawn_map_x": 50.0,
"spawn_map_y": 30.0,
"spawn_world_x": 16.0,
"spawn_world_y": 9.6,
"collectables_count": 12,
"world_items_count": 48,
"tile_counts": [
{ "tile_id": 8, "count": 412 },
{ "tile_id": 14, "count": 96 }
]
},
"inventory": [
{
"block_id": 1041,
"inventory_type": 49,
"amount": 1,
"name": "WeaponPickaxeBasic",
"category": "tool"
}
],
"tutorial_stage": null,
"sf_token": "<JWT>"
}
POST /api/bots/{id}/connect
Resume a previously-created bot. Re-runs the auth chain (PlayFab + sclfrst), then opens the TCP socket.
Response (200):
{ "ok": true }
Errors (200, body): if the auth fails Seraph still returns 200
but with the failure surfaced in the bot snapshot — poll
GET /api/bots/{id} and read status + last_error. Truly fatal
failures (bad credentials, license invalid) come back as 500 with
the verbatim error string.
POST /api/bots/{id}/disconnect
Drop the TCP socket cleanly. Sends DD to the server first so the
session ledger releases the slot.
Response (200): { "ok": true }
POST /api/bots/{id}/warp
Join the named world. Same wire burst the real client emits
(MWli → TTjW → Gw + ActionEvents + GSb + ST). OoIP redirects
are followed automatically.
Body:
{ "world": "MINEWORLD" }
Response (200): { "ok": true } — the bot transitions through
joining_world → loading_world → awaiting_ready → in_world.
Watch the event stream or poll the snapshot to know when
it's settled.
POST /api/bots/{id}/leave
Send LW (LeaveWorld) and return to menu_ready status.
Response (200): { "ok": true }
POST /api/bots/{id}/walk_to
Plan a path through the current world's tile graph and walk to the
target tile. Emits mp + mP movement bursts; waits for the server's
position-update echo before returning.
Body:
{ "x": 42, "y": 18 }
Response (200): { "ok": true }
GET /api/bots/{id}/collectables
Live list of dropped items in the bot's render range.
Response (200):
{
"collectables": [
{
"id": 12,
"block_type": 1041,
"amount": 1,
"inventory_type": 49,
"pos_x": 13.44,
"pos_y": 5.76,
"is_gem": false
}
]
}
GET /api/bots/{id}/enemies
AI / mob entities visible to the bot.
Response (200):
{
"enemies": [
{
"ai_id": 17,
"x": 41,
"y": 28,
"ai_kind": "Spider",
"hp": 80,
"max_hp": 100
}
]
}
GET /api/bots/{id}/minimap
Compact representation of the world's foreground / background /
water / wiring layers — every tile id as a flat array of length
width * height. Useful for rendering an overlay or feeding a
pathfinder.
Response (200):
{
"width": 100,
"height": 60,
"foreground_tiles": [0, 0, 8, 14, 0, ...],
"background_tiles": [0, 0, 0, 0, 12, ...],
"water_tiles": [0, 0, 0, ...],
"wiring_tiles": [0, 0, 0, ...],
"player_position": { "map_x": 42.0, "map_y": 18.0,
"world_x": 13.44, "world_y": 5.76 },
"other_players": [
{
"user_id": "69fd4201a4fa2bc68c51dc27",
"nick": "Devastres22",
"position": { "map_x": 50.0, "map_y": 30.0,
"world_x": 16.0, "world_y": 9.6 }
}
]
}
POST /api/bots/{id}/tutorial
Kick off the canonical Rust tutorial automation flow (TUTORIAL2 join → CharC → spawn pods → exit to PIXELSTATION). Use this on a freshly- minted account to land it in the post-tutorial world without writing any Lua glue.
Response (200): { "ok": true } — the bot's
tutorial_running flag flips to true. Watch
tutorial_stage on the snapshot for human-readable progress
("character creation", "spawn pod walk", …).