Skip to main content

HTTP API

The server runs an HTTP server on the same port as the main game port (9999 by default), on TCP. Besides delivering resource files to connecting players, it serves two endpoints you can use yourself.

Stats

GET /stats

Everything the operator needs to see whether the server is healthy: uptime, player count, tick times, network counters and the cost of every running resource.

info

The endpoint only exists while statstoken is set in settings.xml. As long as the setting is empty, the server does not register the route at all and a request returns 404.

Authenticate with the token in the X-Stats-Token header. A missing or wrong token answers 401 Unauthorized.

curl -H "X-Stats-Token: your-token" http://127.0.0.1:9999/stats
Response
{
"version": "2.2.1",
"uptime": 3600,
"players": 7,
"maxplayers": 32,
"tick": { "average": 0.42, "peak": 3.10 },
"enet": {
"sentPackets": 120034, "sentBytes": 41203311,
"receivedPackets": 98122, "receivedBytes": 22930011,
"droppedNoPeer": 0, "sendErrors": 0, "oversized": 0,
"outgoingQueued": 0, "incomingQueued": 0,
"peakRoundTripMs": 91, "worstPacketLossPercent": 1
},
"relay": {
"running": true, "port": 9998, "bound": 7,
"relayed": 884120, "noTarget": 0, "badToken": 0,
"badSource": 0, "malformed": 0, "sendErrors": 0
},
"resources": [
{ "name": "gamemodes/freeroam", "started": true, "peakCallMs": 1.8, "peakMemoryBytes": 4194304 }
]
}

What to watch

FieldMeaning
uptimeSeconds since the server started.
tick.average, tick.peakMilliseconds one server tick took. A peak in the hundreds means a resource is doing too much work in one go.
relay.runningfalse means no game traffic can be forwarded at all, so players will connect but see nobody.
relay.boundHow many of the connected players actually reached the relay. Anything below players means the relay port is not reachable for some of them.
enet.peakRoundTripMs, enet.worstPacketLossPercentWorst ping and worst packet loss across all players.
resources[].peakCallMsLongest single script call of that resource. The limit is 5000 ms, see Sandbox & Limits.
resources[].peakMemoryBytesHighest memory the script VM reached. The limit is 256 MiB.
caution

peakCallMs and peakMemoryBytes stay 0 for Squirrel resources, because only the Lua VM measures them.

info

The numbers come from a snapshot the server rebuilds once a second, so polling faster than that returns the same values.

Query

GET /query

The public server information the launcher uses to fill the server list: name, episode, player count and names, the resources and addons a player will download, and the total download size.

danger

This is the internal protocol between launcher and server, not a stable API. Its fields, its format and the way it is requested can change without notice in any release. Nothing here is promised to keep working, so if you build on it, expect to fix it after an update.

curl -H "User-Agent: HappinessMP/1" http://127.0.0.1:9999/query
warning

The request has to carry the User-Agent header HappinessMP/1 exactly. Without it the server does not answer the request as a query at all, which looks like a 404 in a browser.

Response
{
"name": "My Server",
"episode": 0,
"players": 7,
"maxplayers": 32,
"version": "2.2.1",
"resources": ["core/chat", "gamemodes/freeroam"],
"addons": ["vehicles/police"],
"downloadSize": 18234455,
"playerlist": ["Niko", "Roman"]
}
caution

Every request rebuilds the answer from scratch and walks through all resources and all connected players. If you show the player count on a website, cache the result there and refresh it every 30 to 60 seconds. Polling once per second, per visitor, puts that work on the machine that is supposed to be running your server.

info

This endpoint needs no token and returns player names, so treat it as public information. It is also the answer to "why does my server show 0 players in the list": if the query does not reach your server, the list has nothing to show.