The Server Browser API allows game servers to advertise themselves and clients to discover available servers. The system uses a simple REST API with token-based authentication.
https://abagrow.pope.games/apiWhen your game server starts for the first time, it must register to obtain an authentication token. Tokens are independent of groups - you subscribe to groups separately.
POST /api/register{
"serverId": "550e8400-e29b-41d4-a716-446655440000", // UUID you generate
"serverName": "My Awesome Server",
"nonce": "123e4567-e89b-12d3-a456-426614174000" // Random UUID for security
}{
"success": true,
"serverId": "550e8400-e29b-41d4-a716-446655440000",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"nonce": "123e4567-e89b-12d3-a456-426614174000",
"message": "Server registered successfully. Use CLI to subscribe to groups."
}After registration, use the CLI tool to subscribe your token to groups:
deno run -A mod.ts subscribe --token "eyJ..." --group "myguild"This allows your server to advertise in that group. Subscribe to multiple groups to advertise across them.
Maximum 4 server registrations per IP address. If exceeded, you'll receive a 429 error.
Once registered, your server should advertise itself every 30 seconds to remain visible in the server list.
POST /api/{group}/advertiseAuthorization: Bearer {your-token}{
"serverId": "550e8400-e29b-41d4-a716-446655440000",
"serverName": "My Awesome Server",
"ipAddress": "0.0.0.0:7777", // API will replace 0.0.0.0 with your real IP
"currentPlayers": 2,
"maxPlayers": 8,
"gameVersion": "1.0.0",
"lastSeen": 1709251200,
"region": "us-east", // Use: us-east, us-west, eu-west, eu-central, asia-pacific, oceania, global
"isDedicated": true
}0.0.0.0:port and it will be replaced.Servers not updated within 60 seconds are automatically removed from the listing.
When your server shuts down, you can remove it immediately instead of waiting for the stale timeout:
DELETE /api/{group}/advertiseHeaders (Required):
Authorization: Bearer {your-token}Request Body: None required. The token identifies which server to delete.
Response:
{
"success": true,
"serverId": "550e8400-e29b-41d4-a716-446655440000",
"message": "Server removed successfully"
}Game clients can retrieve the server list without authentication (for public groups).
GET /api/{group}/list{
"servers": [
{
"serverId": "550e8400-e29b-41d4-a716-446655440000",
"serverName": "My Awesome Server",
"ipAddress": "203.0.113.42:7777",
"currentPlayers": 2,
"maxPlayers": 8,
"gameVersion": "1.0.0",
"lastSeen": 1709251200,
"region": "us-east", // Geographic location
"isDedicated": true,
"group": "myguild" // Social organization
}
],
"total": 1,
"group": "myguild"
}Get all servers you have access to (public + subscribed private groups):
GET /api/listAuthorization: Bearer {your-token}Without token: Returns only public servers. With token: Returns public + subscribed private servers.
Use the CLI tool to manage which groups your token can advertise to.
deno run -A mod.ts subscribe --token "eyJ..." --group "myguild"deno run -A mod.ts unsubscribe --token "eyJ..." --group "myguild"deno run -A mod.ts list --token "eyJ..."Groups are social organizations (clans, communities, tournaments, etc.) that can have servers in any region. Groups can be public or private.
PUT /api/groups/{name}{
"isPublic": false,
"description": "Private tournament servers"
}GET /api/groups?public=trueisPublic: trueusing UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class ServerAdvertiser : MonoBehaviour
{
private string apiUrl = "https://abagrow.pope.games/api";
private string groupName = "myguild"; // The group to advertise in
private string authToken;
private string serverId;
void Start()
{
serverId = System.Guid.NewGuid().ToString();
StartCoroutine(RegisterServer());
}
IEnumerator RegisterServer()
{
var nonce = System.Guid.NewGuid().ToString();
var json = JsonUtility.ToJson(new {
serverId = serverId,
serverName = "My Unity Server",
nonce = nonce
});
// Register without group
using (UnityWebRequest www = UnityWebRequest.Post($"{apiUrl}/register", json, "application/json"))
{
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
var response = JsonUtility.FromJson<RegisterResponse>(www.downloadHandler.text);
authToken = response.token;
// IMPORTANT: Use CLI to subscribe token to groups before advertising
// deno run -A mod.ts subscribe --token "TOKEN" --group "myguild"
StartCoroutine(AdvertisePeriodically());
}
}
}
IEnumerator AdvertisePeriodically()
{
while (true)
{
yield return new WaitForSeconds(30f);
var json = JsonUtility.ToJson(new {
serverId = serverId,
serverName = "My Unity Server",
ipAddress = "0.0.0.0:7777",
currentPlayers = GetCurrentPlayers(),
maxPlayers = 8,
gameVersion = "1.0.0",
lastSeen = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
region = "us-east", // or us-west, eu-west, etc.
isDedicated = true
});
using (UnityWebRequest www = UnityWebRequest.Post($"{apiUrl}/{groupName}/advertise", json, "application/json"))
{
www.SetRequestHeader("Authorization", $"Bearer {authToken}");
yield return www.SendWebRequest();
}
}
}
int GetCurrentPlayers()
{
// Your player count logic here
return 0;
}
void OnApplicationQuit()
{
// Gracefully remove server from listing on shutdown
StartCoroutine(RemoveServer());
}
IEnumerator RemoveServer()
{
using (UnityWebRequest www = UnityWebRequest.Delete($"{apiUrl}/{groupName}/advertise"))
{
www.SetRequestHeader("Authorization", $"Bearer {authToken}");
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
Debug.Log("Server removed from listing");
}
}
}
}// Register server (no group in URL)
const response = await fetch('https://abagrow.pope.games/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
serverId: crypto.randomUUID(),
serverName: 'My JS Server',
nonce: crypto.randomUUID()
})
});
const { token, serverId } = await response.json();
// IMPORTANT: Use CLI to subscribe token to groups before advertising
// deno run -A mod.ts subscribe --token "TOKEN" --group "myguild"
// Advertise periodically (to a specific group)
const groupName = 'myguild'; // Must be subscribed via CLI first
const advertiseInterval = setInterval(async () => {
await fetch(`https://abagrow.pope.games/api/${groupName}/advertise`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
serverId: serverId,
serverName: 'My JS Server',
ipAddress: '0.0.0.0:3000',
currentPlayers: 0,
maxPlayers: 10,
gameVersion: '1.0.0',
lastSeen: Date.now(),
region: 'us-east', // or us-west, eu-west, asia-pacific, etc.
isDedicated: true
})
});
}, 30000);
// Graceful shutdown - remove server from listing
process.on('SIGINT', async () => {
clearInterval(advertiseInterval);
await fetch(`https://abagrow.pope.games/api/${groupName}/advertise`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
console.log('Server removed from listing');
process.exit(0);
});