HTTP API
REST endpoints for managing Mori setup
HTTP API
All endpoints return application/json.
Most endpoints are protected by authentication except for the frontend static files and /auth/* endpoints. Protected API endpoints require an Authorization: Bearer <token> header.
The application is meant for a single user. Credentials are saved locally to user.json.
GET /auth/status
Check whether the master password has been configured yet.
Response
{ "registered": true }POST /auth/setup
Registers the master password for the application. This can only be done once.
Request Body
{ "password": "your_secure_password" }Response
| Status | Meaning |
|---|---|
204 | Setup successful |
409 | Already registered |
POST /auth/login
Returns a session token valid until the server restarts or the user logs out.
Request Body
{ "password": "your_secure_password" }Response
{ "token": "uuid-v4-token" }POST /auth/logout
Invalidates the current session token.
Response
| Status | Meaning |
|---|---|
204 | Logged out |
GET /
Serves the HTML dashboard.
GET /bots
Returns a summary list of all running bots.
Response
[
{
"id": 1,
"username": "string",
"status": "in_game",
"world": "string",
"pos_x": 0.0,
"pos_y": 0.0,
"gems": 0,
"ping_ms": 0
}
]POST /bots
Spawns a new bot.
Request Body
{
"username": "string",
"password": "string",
"proxy_host": "string",
"proxy_port": 1080,
"proxy_username": "string",
"proxy_password": "string"
}proxy_host and proxy_port are required together to enable SOCKS5 proxy. Username/password are optional.
Response
{ "id": 1 }POST /bots/ltoken
Spawns a new bot using a pre-existing ltoken instead of username/password. The token is validated immediately — if it fails the bot stops without retrying.
Request Body
{
"ltoken": "token|rid|mac|wk",
"proxy_host": "string",
"proxy_port": 1080,
"proxy_username": "string",
"proxy_password": "string"
}ltoken is a |-separated string of four fields: the refresh token, a 32-char hex RID, a MAC address (XX:XX:XX:XX:XX:XX), and a 32-char hex WK.
proxy_host and proxy_port are required together to enable SOCKS5 proxy. Username/password are optional.
Response
{ "id": 1 }DELETE /bots/{id}
Stops and removes a bot.
| Status | Meaning |
|---|---|
204 | Stopped successfully |
404 | Bot not found |
GET /bots/{id}/state
Returns the full state of a bot.
Response
{
"status": "in_game",
"world_name": "string",
"pos_x": 0.0,
"pos_y": 0.0,
"world_width": 100,
"world_height": 60,
"tiles": [
{
"fg_item_id": 0,
"bg_item_id": 0,
"flags": 0,
"tile_type": { "type": "Basic" }
}
],
"players": [
{
"net_id": 0,
"name": "string",
"pos_x": 0.0,
"pos_y": 0.0,
"country": "us"
}
],
"objects": [
{
"uid": 0,
"item_id": 0,
"x": 0.0,
"y": 0.0,
"count": 1
}
],
"inventory": [
{
"item_id": 0,
"amount": 0,
"is_active": false,
"action_type": 0
}
],
"inventory_size": 18,
"gems": 0,
"console": ["string"],
"ping_ms": 0,
"delays": {
"place_ms": 500,
"walk_ms": 500,
"twofa_secs": 120,
"server_overload_secs": 30,
"too_many_logins_secs": 5,
"maintenance_secs": 600
},
"track_info": {
"level": 0,
"grow_id": 0,
"install_date": 0,
"global_playtime": 0,
"awesomeness": 0
},
"auto_collect": true,
"auto_reconnect": true
}track_info is null until the server sends account data after login.
| Status | Meaning |
|---|---|
200 | OK |
404 | Bot not found |
POST /bots/{id}/cmd
Sends a command to a bot.
| Status | Meaning |
|---|---|
204 | Command sent |
404 | Bot not found |
All commands use a tagged union with a "type" field.
move
Move the bot to a pixel position.
{ "type": "move", "x": 0.0, "y": 0.0 }walk_to
Pathfind to a tile position.
{ "type": "walk_to", "x": 0, "y": 0 }run_script
Run a Lua script on the bot.
{ "type": "run_script", "content": "string" }stop_script
Stop the currently running script.
{ "type": "stop_script" }wear
Equip an item.
{ "type": "wear", "item_id": 0 }unwear
Unequip an item.
{ "type": "unwear", "item_id": 0 }drop
Drop items into the world.
{ "type": "drop", "item_id": 0, "count": 1 }trash
Permanently delete items.
{ "type": "trash", "item_id": 0, "count": 1 }set_delays
Configure action delays. place_ms and walk_ms are in milliseconds; the *_secs fields control how long the bot waits before reconnecting after each login failure type.
{
"type": "set_delays",
"place_ms": 500,
"walk_ms": 500,
"twofa_secs": 120,
"server_overload_secs": 30,
"too_many_logins_secs": 5,
"maintenance_secs": 600
}set_auto_collect
Enable or disable automatic collection of nearby dropped items.
{ "type": "set_auto_collect", "enabled": true }set_auto_reconnect
Enable or disable automatic reconnection after a disconnect.
{ "type": "set_auto_reconnect", "enabled": true }disconnect
Disconnect the bot from the current server. If auto-reconnect is enabled, the bot will reconnect automatically.
{ "type": "disconnect" }reconnect
Force a reconnect. If the bot is currently connected, it disconnects first and reconnects via the normal disconnect handler. If already disconnected, reconnects immediately.
{ "type": "reconnect" }accept_access
Accept a world lock access request from the nearest player. Wrenches the player and confirms both dialogs in sequence.
{ "type": "accept_access" }warp
Warp the bot to a world by name. id is the door ID to enter through and defaults to an empty string (main door).
{ "type": "warp", "name": "START", "id": "" }GET /growtopia-cdn/{*path}
Proxies a request to https://growserver-cache.netlify.app/{path} and returns the response body with the original content-type header.
Example
GET /growtopia-cdn/growtopia/game/fire.rttex
→ proxied to https://growserver-cache.netlify.app/growtopia/game/fire.rttex| Status | Meaning |
|---|---|
200 | Response from upstream |
502 | Upstream request failed or body could not be read |
POST /proxy/test
Tests a SOCKS5 proxy against three checks and returns the result of each.
All checks use the same proxy credentials. Each check is independent — a failed earlier check does not block later ones, except check 3 which requires a server address from check 2.
Request Body
{
"proxy_host": "103.160.95.181",
"proxy_port": 1080,
"proxy_username": "string",
"proxy_password": "string"
}proxy_username and proxy_password are optional.
Response
{
"socks5": {
"ok": true,
"error": null,
"detail": null
},
"server_data": {
"ok": true,
"error": null,
"detail": "1.2.3.4:17091"
},
"enet": {
"ok": true,
"error": null,
"detail": null
}
}Each check object has:
| Field | Type | Description |
|---|---|---|
ok | bool | Whether the check passed |
error | string | null | Error message if ok is false |
detail | string | null | Extra info on success (check 2 returns the resolved server:port) |
Checks
| # | Name | What it does |
|---|---|---|
| 1 | socks5 | TCP connect to the proxy + auth negotiation + UDP ASSOCIATE. Times out after 10 seconds. |
| 2 | server_data | HTTP POST through the proxy to growtopia1.com/growtopia/server_data.php, falling back to growtopia2.com if the first fails. |
| 3 | enet | Opens a second SOCKS5 UDP socket and attempts an ENet connect to the game server address obtained from check 2. Waits up to 10 seconds for a Connect event. Skipped if check 2 failed. |
GET /items/colors
Returns a flat map of all item IDs to their minimap color as 0xRRGGBB. Colors are derived from the base_color field in items.dat, which is stored as BGRA and converted server-side.
Response
{
"0": 0,
"2": 1588250666,
"8": 2303786022
}Keys are item IDs as strings. No query parameters.
GET /items/names
Returns a flat map of all item IDs to their names. Useful for quick lookups without pagination.
Response
{
"0": "x",
"2": "y",
"8": "z"
}Keys are item IDs as strings (standard JSON object key behaviour). No query parameters.
GET /items
Paginated search through the item database, or bulk fetch by ID.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-indexed) |
q | string | "" | Search by item ID (exact) or name (substring, case-insensitive) |
get-items | string | — | Comma-separated item IDs to fetch. When present, returns an array directly (bypasses pagination). |
Paginated response (default)
{
"items": [
{
"id": 0,
"name": "string",
"flags": 0,
"action_type": 0,
"material": 0,
"texture_file_name": "string",
"texture_hash": 0,
"visual_effect": 0,
"collision_type": 0,
"rarity": 0,
"max_item": 0,
"grow_time": 0,
"base_color": 0,
"overlay_color": 0,
"clothing_type": 0
}
],
"total": 0,
"page": 1,
"page_size": 50
}50 items per page.
Bulk fetch response (?get-items=2,4,6,8)
Returns a flat array containing only the items whose IDs were requested. Items not found in the database are silently omitted.
[
{
"id": 2,
"name": "string",
"flags": 0,
"action_type": 0,
"material": 0,
"texture_file_name": "string",
"texture_hash": 0,
"visual_effect": 0,
"collision_type": 0,
"rarity": 0,
"max_item": 0,
"grow_time": 0,
"base_color": 0,
"overlay_color": 0,
"clothing_type": 0
}
]