Build a bot algorithm, connect it via REST, and compete in battle arenas or races.
Two game modes: Battle Mode (fight to the death) and Race Mode (first to the finish line). Both modes use the same core API.
POST /api/battle/join or POST /api/race/join with your bot’s name. You’ll get back a botId. Your bot starts on a waiting list.GET /api/bot/:botId/status every 1–2 seconds until status changes from "waiting"."ready" (bot is placed in the arena but frozen). A viewer starts the match. Poll status every 100–200ms until it becomes "active".GET /api/battle/state or GET /api/race/stateid, find enemies, decide what to doPOST /api/bot/:botId/commandPOST /api/bot/:botId/leave (works from waiting list or active match)A3K7 or RACE-B2N5). To join a private room instead of the main one, use POST /api/battle/:joinCode/join or POST /api/race/:joinCode/join. State is available at GET /api/battle/:joinCode/state or GET /api/race/:joinCode/state./status and /command endpoints are limited to 1 request per 100ms per bot (each endpoint has its own limit, so calling both in the same 100ms is fine). Other endpoints are not rate-limited. Retry with a short backoff on 429 Too Many Requests./status to stay alive while waiting for promotion."thrust": "forward", your bot keeps driving forward until you send a different command. You don’t need to resend the same command repeatedly — only send when you want to change direction. Sending just { "thrust": "forward" } changes thrust without affecting the current turn state, and vice versa.Bots fight in a 20m × 20m square with walls on all sides. Your bot is a small tank that can drive forward/backward and turn left/right. The goal: reduce other bots to 0 health using your saw blade, ramming, or bombs.
| Property | Value | Details |
|---|---|---|
| Arena size | 20 × 20m | X: −10 to +10, Z: −10 to +10 |
| Health | 100 HP | When health reaches 0, your bot is destroyed |
| Bot size | 0.6m radius | Bots are circles for collision purposes |
| Max speed | 5 m/s | At full health. Slows to 40% at 0 HP |
| Turn rate | π rad/s | At full health. Slows with damage (same curve as speed) |

The rotation field tells you which direction a bot is facing, measured in radians:
| Rotation value | Facing direction |
|---|---|
| 0 | Toward +Z (up on the map) |
| 1.57 (π/2) | Toward +X (right) |
| 3.14 (π) | Toward −Z (down) |
| −1.57 (−π/2) | Toward −X (left) |
"turn": "left" increases rotation (counter-clockwise on the map). "turn": "right" decreases it (clockwise).
Saw Attack — your main weapon. Swings forward and damages any bot directly in front of you within 1.5 meters. The attack takes about 0.5 seconds to complete, then needs 2 seconds to recharge. Only hits bots in a 60° cone. Deals more damage the faster you’re moving. Check sawCooldown — when it’s 0, you can attack again.
Ram Damage — crashing into another bot at speed deals damage to both bots. Faster collisions deal more damage (up to 15 HP per hit). Combine boost + ramming for maximum impact.
Boost — activates a 0.5-second burst of 2.5× speed. Great for charging into enemies or escaping. Has a 10-second cooldown. Check boostCooldown — when it’s 0, boost is ready.
Damage Slowdown — as your bot takes damage, it gets slower and turns more sluggishly. At full health: 100% speed. At 50 HP: ~70%. Near death: 40%. This means a damaged bot is easier to finish off.
Objects spawn on the arena floor every 15 seconds (up to 3 at a time). Check the objects array in the state response for positions and types.
| Type | Effect |
|---|---|
health | Instantly heals 35 HP on contact. Always picks up |
bomb_pickup | Picked up and held by your bot (check heldItem). You can only hold one at a time. Use { "action": "useItem" } to drop it 1.5m behind you as an active bomb |
bomb_active | Deals 60 damage + knockback to any bot that touches it (including the bot that placed it). Disappears after detonating or after 10 seconds. If a bot is destroyed while holding a bomb, it drops automatically |
Same 20m × 20m arena but with interior walls creating a winding track. First bot to complete the full circuit and cross the finish line wins. All combat mechanics still work (saw, ram, boost) — you can attack opponents while racing. No items or pickups spawn.
| Property | Value |
|---|---|
| Starting grid | Rows of 5, behind the start/finish line |
| Max racers | 20 |
| Countdown | 5 seconds (bots frozen until countdown ends) |
The 20×20m arena has the same outer walls as battle mode, plus four interior walls that create corridors. Bots race through the corridors in order.

When a bot finishes the race, it is removed from the arena and placed back on the waiting list. The race ends when all bots have finished or died, or when a viewer stops it.
Join the main battle arena’s waiting list.
// Request
{ "name": "MyBot" }
// Response
{ "botId": "your-bot-uuid", "name": "MyBot", "status": "waiting" }
Name max 32 characters.
Join a private battle arena’s waiting list. Same request/response format.
Join the main race room’s waiting list. Same request/response format.
Join a private race room’s waiting list. Same request/response format.
Check your bot’s current status. While on the waiting list, each call resets the 30-second timeout.
// Response
{ "status": "waiting" } // on waiting list, not yet promoted
{ "status": "ready" } // promoted into match, waiting for match to start
{ "status": "active" } // match is running, commands accepted
{ "status": "dead" } // bot was destroyed
{ "status": "not_found" } // bot doesn't exist (removed or expired)
Control your bot. Only works when status is "active". Returns 400 if match hasn’t started, 409 if bot is still on the waiting list.
Movement commands are sticky — they stay active until you send a different value. You can set thrust and turn independently.
{ "thrust": "forward", "turn": "left" } // drive forward while turning left
{ "thrust": "forward", "turn": null } // drive straight, stop turning
{ "thrust": null, "turn": "right" } // stop driving, spin in place
{ "thrust": null, "turn": null } // full stop
{ "thrust": "forward" } // change thrust only, turn unchanged
{ "turn": "left" } // change turn only, thrust unchanged
thrust: "forward" | "backward" | null
turn: "left" | "right" | null
One-shot commands that trigger immediately. Your current movement continues — actions don’t cancel thrust/turn.
{ "action": "attack" } // swing your saw blade (check sawCooldown first)
{ "action": "boost" } // 2.5x speed burst for 0.5s (check boostCooldown first)
{ "action": "useItem" } // drop held bomb behind you (battle only)
Remove your bot from the room. Works whether your bot is on the waiting list, on the grid, or in an active match.
// Response
{ "ok": true }
Current battle arena state. Only returns alive bots (dead bots excluded so you don’t target wrecks).
Private battle arena state.
Current race room state. Includes track info.
Private race room state.
Example battle state response:
{
"tick": 1420,
"timestamp": 1712345678000,
"matchStatus": "active",
"bots": [{
"id": "bot-uuid",
"name": "MyBot",
"x": 3.21,
"z": -1.54,
"rotation": 1.571,
"health": 85,
"speed": 2.12,
"sawCooldown": 0,
"boostCooldown": 0,
"heldItem": null,
"alive": true
}],
"objects": [
{ "id": "uuid", "x": 5.0, "z": -2.0, "type": "health" },
{ "id": "uuid", "x": -3.5, "z": 7.1, "type": "bomb_active" }
]
}
| Field | Description |
|---|---|
id | Unique bot identifier (use this to find yourself in the array) |
name | Bot display name |
x, z | Position in meters from arena center (−10 to +10) |
rotation | Direction the bot is facing in radians (see Rotation table) |
health | Remaining HP (0–100). 0 = destroyed |
speed | How fast the bot is currently moving (m/s) |
sawCooldown | Seconds until saw can be used again (0 = ready) |
boostCooldown | Seconds until boost can be used again (0 = ready) |
heldItem | null or "bomb" (battle only) |
alive | Whether bot is alive |
| Field | Description |
|---|---|
id | Unique object identifier |
x, z | Position in meters from arena center |
type | "health", "bomb_pickup", or "bomb_active" |