Generic Connector Protocol Reference
This page documents the WebSocket message formats for the Generic Game Protocol (also called the generic connector protocol). Your integration (whether an in-game mod or a sidecar process) needs to handle these messages.
For architecture guidance, concepts like gameId and player objects, and connection setup, see Adding Support for a New Game.
Functions
Section titled “Functions”Takaro will request data from the server and it will perform actions on the server. The game mod should implement the following functions.
Each of these will be sent over the websocket connection as a JSON message. The game server will receive a message like:
{ type: 'request', payload: { action: 'getPlayers', args: '{}' }, requestId: '1234',}The above message means that Takaro wants to call the getPlayers function on the game server. The game server should respond with a message like:
{ type: 'response', payload: [... player objects], requestId: '1234',}Note the requestId field. This is used to match the request and response. The game server should always respond with the same requestId as the request. Takaro might send multiple requests at the same time, so it is important to keep track of the request IDs.
The args field is always a JSON-encoded string. An action without arguments gets "{}".
Errors
Section titled “Errors”- On version 0, report a failure with a top-level
erroron the response, or atype: "error"frame with the request’srequestId(message inpayload.message). Takaro treats both as a failure with codegame_error. - On version 1, use the standard error shape, see Requests, responses and errors.
- A payload that fails validation is answered with a
type: "error"frame.
getPlayer
Section titled “getPlayer”Capability (v1): players.get
Retrieves information about a specific player.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "getPlayer", "args": "{\"gameId\": \"12345\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": { "gameId": "12345", "name": "PlayerName", "steamId": "76561198123456789", "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": null, "ip": "192.168.1.1", "ping": 50 }, "requestId": "request-uuid"}If the player is not found, return null:
{ "type": "response", "payload": null, "requestId": "request-uuid"}getPlayers
Section titled “getPlayers”Capability (v1): players.list
Retrieves a list of all currently connected players.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "getPlayers", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "gameId": "12345", "name": "PlayerName1", "steamId": "76561198123456789", "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": null, "ip": "192.168.1.1", "ping": 50 }, { "gameId": "67890", "name": "PlayerName2", "steamId": null, "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": "minecraft:550e8400-e29b-41d4-a716-446655440000", "ip": "192.168.1.2", "ping": 75 }, { "gameId": "54321", "name": "PlayerName3", "steamId": null, "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": "battlenet:PlayerName-1234", "ip": "192.168.1.3", "ping": 42 } ], "requestId": "request-uuid"}getPlayerLocation
Section titled “getPlayerLocation”Capability (v1): players.location
Retrieves the current 3D position of a specific player. The response includes optional dimension information for games that support multiple dimensions/worlds.
A game that declares events.player-positions is not polled for this action during player sync, see Pushed Positions.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "getPlayerLocation", "args": "{\"gameId\": \"12345\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" }, "requestId": "request-uuid"}If the player is not found, return null:
{ "type": "response", "payload": null, "requestId": "request-uuid"}getPlayerInventory
Section titled “getPlayerInventory”Capability (v1): players.inventory
Retrieves the items in a specific player’s inventory. Note that quality is a string, not all games will have a number for quality.
A game that declares events.inventory-changed is asked for this only once an hour per player, as a reconciliation snapshot, see Pushed inventory changes.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "getPlayerInventory", "args": "{\"gameId\": \"12345\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "code": "weapon_baseball_bat", "name": "Baseball Bat", "amount": 1, "quality": "5" }, { "code": "first_aid_bandage", "name": "First Aid Bandage", "amount": 5, "quality": "high" } ], "requestId": "request-uuid"}getPlayerProgression
Section titled “getPlayerProgression”Capability (v1): players.progression (version 1 only)
Returns a player’s Progression: a list of game-defined Progression Tracks, such as a character level or a single skill. This action is not available on version 0. See the capability table in Generic Game Protocol v1.
Takaro polls this action on every player sync and detects level changes itself, so your connector only reports the current state.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "getPlayerProgression", "args": "{\"gameId\": \"12345\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "key": "character", "name": "Level", "level": 13, "experience": 48210, "progress": 0.42 }, { "key": "woodcutting", "name": "Woodcutting", "level": 23, "progress": 0.7 }, { "key": "mining", "level": 4 } ], "requestId": "request-uuid"}If the game does not know the player, return null:
{ "type": "response", "payload": null, "requestId": "request-uuid"}Track fields
Section titled “Track fields”| Field | Required | Description |
|---|---|---|
key |
Required | Identifies the track. Chosen by the game, except character, which is reserved for the one primary level. Matches ^[a-z][a-zA-Z0-9]*(\.[a-z][a-zA-Z0-9-]*)*$ and is at most 128 characters. |
name |
Optional | Display name of the track, at most 128 characters. |
level |
Required | Whole number. It may decrease between readings. |
experience |
Optional | Finite number, in the game’s own units. |
progress |
Optional | Fraction toward the next level, from 0 to 1 inclusive. |
- Answer
nullwhen the game does not know the player, and[]for a known player with no tracks. The two are distinct. Never use an error for an unknown player. characteris reserved for the one primary level. Other keys are yours to choose, so name them after the game’s real skills or perks. A game may reportcharacterand skill tracks together.- Levels are whole numbers and may go down. Report a fractional native level as
levelplusprogress: Valheim’s 23.7 becomes"level": 23, "progress": 0.7. experienceis in the game’s own units and is only comparable within one track of one game. Omit it when the game has no reliable counter.- Answer at most 200 tracks, with no duplicate keys. A payload that is not an array, more than 200 tracks, a duplicate key or a single invalid track fails the whole reading. Takaro then sends you the usual
errorframe, with one of these messages:getPlayerProgression must answer with null or an array of tracksgetPlayerProgression answered <n> tracks, more than the 200 allowedgetPlayerProgression answered the track <key> more than once
- A game without an advancement system does not declare
players.progression. Do not invent a level.
How Takaro uses it
Section titled “How Takaro uses it”- Takaro calls
getPlayerProgressionfor each online player on every player sync, after inventory and location. Servers whose manifest lacksplayers.progressionare never asked. - Each reading is compared with the last Progression Takaro stored for that player on that game server. The stored value survives disconnects and restarts.
- The first reading of a track, including a player’s first reading ever, is a silent baseline: Takaro stores it and emits no event.
- A track missing from a reading is unknown, not level 0. Takaro keeps the stored value.
- Each level change, up or down, emits one
player-level-changedevent carrying the full jump. - Games do not push level-ups. Takaro discovers changes only by polling.
giveItem
Section titled “giveItem”Capability (v1): items.give
Gives an item to a specific player.
The item code (baseball_bat in this case) is the code used in the listItems function.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "giveItem", "args": "{\"player\": {\"gameId\": \"12345\"}, \"item\": \"baseball_bat\", \"amount\": 1, \"quality\": \"5\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}listItems
Section titled “listItems”Capability (v1): items.list
Retrieves a list of all available items in the game.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "listItems", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "code": "baseball_bat", "name": "Baseball Bat", "description": "A wooden baseball bat" }, { "code": "first_aid_bandage", "name": "First Aid Bandage", "description": "Used to stop bleeding" } ], "requestId": "request-uuid"}listEntities
Section titled “listEntities”Capability (v1): entities.list
Retrieves a list of all available entities in the game. This includes both NPCs and monsters. Vanilla and modded entities should be included.
The metadata field is optional and can be used to store additional (game-specific) information about the entity.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "listEntities", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "code": "pig", "name": "Pig", "description": "Some tasty bacon", "type": "friendly", "metadata": { "health": 10 } }, { "code": "skeleton", "name": "Skeleton", "description": "A spooky skeleton", "type": "hostile", "metadata": { "health": 50, "damage": 10 } } ], "requestId": "request-uuid"}listLocations
Section titled “listLocations”Capability (v1): locations.list (version 1 only)
List all locations in the game. Locations are game-defined structures or areas. Some examples:
- Minecraft villages, nether fortresses, end cities, …
- 7 Days to Die POIs (Points of Interest)
- Rust monuments
Locations must be either rectangular or circular, not both.
The metadata field is optional and can be used to store additional information about the location.
The category field is optional. It is a free-form string the game chooses, such as trader, spawn or village. Takaro defines no fixed list.
- An empty string counts as no category.
- A value that is not a string fails response validation: Takaro sends a
type: "error"frame and the call fails. - Takaro stores the category with the Location. A change of category alone updates the stored Location in place.
- Admins can filter Locations by category on the map. Locations without a category form their own group.
- API users filter with
POST /location/searchandfilters.category. - Grouping uses the exact string, so use one stable spelling per category.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "listLocations", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" }, "radius": 50, "name": "village", "code": "village_1", "category": "village", "metadata": {} }, { "position": { "x": 200.0, "y": 100.0, "z": 50.0, "dimension": "nether" }, "sizeX": 100, "sizeY": 50, "sizeZ": 100, "name": "forest", "code": "forest_38", "category": "biome", "metadata": {} } ], "requestId": "request-uuid"}executeConsoleCommand
Section titled “executeConsoleCommand”Capability (v1): console.execute
Executes a console command on the game server.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "executeConsoleCommand", "args": "{\"command\": \"say Hi\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": { "success": true, "rawResult": "Message sent: Hi", "errorMessage": null }, "requestId": "request-uuid"}sendMessage
Section titled “sendMessage”Capability (v1): chat.send
Sends a message to one or more players.
If the recipient field is not provided, the message should be a global message.
If the recipient field is provided, the message should be sent to the specified player (DM/whisper).
Request
Section titled “Request”{ "type": "request", "payload": { "action": "sendMessage", "args": "{\"message\": \"Welcome to the server!\", \"opts\": {\"recipient\": {\"gameId\": \"12345\"}}}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}teleportPlayer
Section titled “teleportPlayer”Capability (v1): players.teleport
Teleports a player to a specific location. The coordinates are passed as x, y, and z values.
The dimension parameter is optional and allows teleportation across different game dimensions/worlds (e.g., overworld, nether, end in Minecraft).
Request
Section titled “Request”{ "type": "request", "payload": { "action": "teleportPlayer", "args": "{\"player\": {\"gameId\": \"12345\"}, \"x\": 123.45, \"y\": 67.89, \"z\": 10.11, \"dimension\": \"nether\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}Note: The dimension parameter is optional. If not provided, the player will be teleported within their current dimension. Games that don’t support dimensions can safely ignore this parameter.
testReachability
Section titled “testReachability”Capability (v1): always sent, not a capability
Tests if the game server is reachable and properly configured. Think of this as a ping/pong test.
If something is misconfigured, the response can contain a reason field with a description of the issue.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "testReachability", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": { "connectable": true, "reason": null }, "requestId": "request-uuid"}kickPlayer
Section titled “kickPlayer”Capability (v1): moderation.kick
Kicks a player from the server.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "kickPlayer", "args": "{\"player\": {\"gameId\": \"12345\"}, \"reason\": \"Violated server rules\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}banPlayer
Section titled “banPlayer”Capability (v1): moderation.ban
Bans a player from the server.
The expiresAt field is optional. If not provided, the ban will be permanent.
expiresAt is a ISO 8601 formatted date string.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "banPlayer", "args": "{\"player\": {\"gameId\": \"12345\"}, \"reason\": \"Cheating\", \"expiresAt\": \"2031-12-31T23:59:59Z\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}unbanPlayer
Section titled “unbanPlayer”Capability (v1): moderation.unban
Removes a ban for a specific player.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "unbanPlayer", "args": "{\"gameId\": \"12345\"}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}listBans
Section titled “listBans”Capability (v1): moderation.listBans
Retrieves a list of all currently banned players.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "listBans", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": [ { "player": { "gameId": "12345", "name": "BannedPlayer1" }, "reason": "Cheating", "expiresAt": "2031-12-31T23:59:59Z" }, { "player": { "gameId": "67890", "name": "BannedPlayer2" }, "reason": "Being rude", "expiresAt": "2031-12-31T23:59:59Z" } ], "requestId": "request-uuid"}shutdown
Section titled “shutdown”Capability (v1): server.shutdown
Initiates a graceful shutdown sequence for the game server.
Request
Section titled “Request”{ "type": "request", "payload": { "action": "shutdown", "args": "{}" }, "requestId": "request-uuid"}Response
Section titled “Response”{ "type": "response", "payload": null, "requestId": "request-uuid"}Takaro Game Events
Section titled “Takaro Game Events”These are the events that Takaro expects to receive from game servers. These events allow Takaro to react to changes in real-time.
Event Structure
Section titled “Event Structure”All events should be sent over the websocket connection as a JSON message with the following structure:
{ "type": "gameEvent", "payload": { "type": "<event type>", "data": { /* event specific data */ } }}On version 1, payload also carries streamId and seq, see Event delivery.
Position on player events
Section titled “Position on player events”player-connected, player-disconnected, chat-message, player-death and entity-killed accept an optional position. log does not. It is valid on version 0 and version 1.
"position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" }positionis where the player was when the event happened.- For
player-death: where the death happened. - For
entity-killed: the killer’s Position. - For
chat-message: the speaker’s Position. It is only used when there is aplayer.
- For
- With a Position, Takaro stores it with the event, updates the player’s current Position, and records it in Tracking without asking the game.
- Without one, Takaro asks
getPlayerLocationas a side effect, as before. The exception is a server that declaresevents.player-positions: it is not asked.
Capability (v1): events.log (descriptive, see Capability names)
Event Type: log
Sent when a new log line is generated by the game server.
{ "type": "gameEvent", "payload": { "type": "log", "data": { "msg": "Server started on port 26900" } }}player-connected
Section titled “player-connected”Capability (v1): events.player-connected (descriptive, see Capability names)
Event Type: player-connected
Sent when a player connects to the game server.
The player object must include the required gameId and name fields. Other fields like steamId, epicOnlineServicesId, xboxLiveId, platformId, ip, and ping are optional.
Include the appropriate platform identifier based on your game’s authentication system. Use platformId for custom platforms following the platform:id format.
position is optional, see Position on player events.
{ "type": "gameEvent", "payload": { "type": "player-connected", "data": { "player": { "gameId": "12345", "name": "SteamPlayer", "steamId": "76561198123456789", "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": null, "ip": "192.168.1.1", "ping": 50 }, "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } }}Example with platformId for a custom platform:
{ "type": "gameEvent", "payload": { "type": "player-connected", "data": { "player": { "gameId": "67890", "name": "MinecraftPlayer", "steamId": null, "epicOnlineServicesId": null, "xboxLiveId": null, "platformId": "minecraft:550e8400-e29b-41d4-a716-446655440000", "ip": "192.168.1.2", "ping": 75 } } }}player-disconnected
Section titled “player-disconnected”Capability (v1): events.player-disconnected (descriptive, see Capability names)
Event Type: player-disconnected
Sent when a player disconnects from the game server.
position is optional, see Position on player events.
{ "type": "gameEvent", "payload": { "type": "player-disconnected", "data": { "player": { "gameId": "12345" }, "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } }}chat-message
Section titled “chat-message”Capability (v1): events.chat-message (descriptive, see Capability names)
Event Type: chat-message
Sent when a player sends a chat message.
The channel field must be one of:
globalteamfriendswhisper
The player field is optional, as some chat messages might be system messages without an associated player; chat without a player is stored and fires chat-message hooks like any other chat (it is not handled as a command).
position is optional, see Position on player events.
{ "type": "gameEvent", "payload": { "type": "chat-message", "data": { "player": { "gameId": "12345", "name": "PlayerName" }, "channel": "global", "msg": "Hello everyone!", "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } }}player-death
Section titled “player-death”Capability (v1): events.player-death (descriptive, see Capability names)
Event Type: player-death
Sent when a player dies in the game.
The attacker field is optional and should only be included if the player was killed by another player.
position is optional, see Position on player events.
{ "type": "gameEvent", "payload": { "type": "player-death", "data": { "player": { "gameId": "12345", "name": "PlayerName" }, "attacker": { "gameId": "67890", "name": "AttackerName" }, "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } }}entity-killed
Section titled “entity-killed”Capability (v1): events.entity-killed (descriptive, see Capability names)
Event Type: entity-killed
Sent when a player kills an entity in the game.
position is optional, see Position on player events.
{ "type": "gameEvent", "payload": { "type": "entity-killed", "data": { "player": { "gameId": "12345", "name": "PlayerName" }, "entity": "zombie", "weapon": "baseball_bat", "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } }}player-positions
Section titled “player-positions”Capability (v1): events.player-positions (version 1 only, required)
Event Type: player-positions
Sent once per declared interval. It holds the Position of every online player.
Takaro rejects a batch that arrives sooner than the declared intervalSeconds. It is not stored as an event and does not run Hooks.
See Pushed Positions for the full rules.
{ "type": "gameEvent", "payload": { "type": "player-positions", "data": { "positions": [ { "gameId": "12345", "position": { "x": 123.45, "y": 67.89, "z": 10.11, "dimension": "overworld" } } ] }, "streamId": "4f0e9a1c-6c2b-4d3a-9f8e-7b6a5c4d3e2f", "seq": 57 }}inventory-changed
Section titled “inventory-changed”Capability (v1): events.inventory-changed (version 1 only, required)
Event Type: inventory-changed
Sent once per changed item line. quantity is signed: positive means gained, negative means lost. cause is one of pickup, drop, craft, loot, trade, death or other.
The optional counterpart names a container or another player.
See Pushed inventory changes for the full rules.
{ "type": "gameEvent", "payload": { "type": "inventory-changed", "data": { "player": { "gameId": "12345", "name": "Alice" }, "itemCode": "first_aid_bandage", "quantity": 5, "cause": "pickup", "position": { "x": 118.5, "y": 64.0, "z": 10.0 } }, "streamId": "4f0e9a1c-6c2b-4d3a-9f8e-7b6a5c4d3e2f", "seq": 61 }}