Skip to content

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.

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 "{}".

  • On version 0, report a failure with a top-level error on the response, or a type: "error" frame with the request’s requestId (message in payload.message). Takaro treats both as a failure with code game_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.

Capability (v1): players.get

Retrieves information about a specific player.

{
"type": "request",
"payload": {
"action": "getPlayer",
"args": "{\"gameId\": \"12345\"}"
},
"requestId": "request-uuid"
}
{
"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"
}

Capability (v1): players.list

Retrieves a list of all currently connected players.

{
"type": "request",
"payload": {
"action": "getPlayers",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"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"
}

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.

{
"type": "request",
"payload": {
"action": "getPlayerLocation",
"args": "{\"gameId\": \"12345\"}"
},
"requestId": "request-uuid"
}
{
"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"
}

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.

{
"type": "request",
"payload": {
"action": "getPlayerInventory",
"args": "{\"gameId\": \"12345\"}"
},
"requestId": "request-uuid"
}
{
"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"
}

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.

{
"type": "request",
"payload": {
"action": "getPlayerProgression",
"args": "{\"gameId\": \"12345\"}"
},
"requestId": "request-uuid"
}
{
"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"
}
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 null when 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.
  • character is 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 report character and skill tracks together.
  • Levels are whole numbers and may go down. Report a fractional native level as level plus progress: Valheim’s 23.7 becomes "level": 23, "progress": 0.7.
  • experience is 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 error frame, with one of these messages:
    • getPlayerProgression must answer with null or an array of tracks
    • getPlayerProgression answered <n> tracks, more than the 200 allowed
    • getPlayerProgression answered the track <key> more than once
  • A game without an advancement system does not declare players.progression. Do not invent a level.
  • Takaro calls getPlayerProgression for each online player on every player sync, after inventory and location. Servers whose manifest lacks players.progression are 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-changed event carrying the full jump.
  • Games do not push level-ups. Takaro discovers changes only by polling.

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.

{
"type": "request",
"payload": {
"action": "giveItem",
"args": "{\"player\": {\"gameId\": \"12345\"}, \"item\": \"baseball_bat\", \"amount\": 1, \"quality\": \"5\"}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

Capability (v1): items.list

Retrieves a list of all available items in the game.

{
"type": "request",
"payload": {
"action": "listItems",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"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"
}

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.

{
"type": "request",
"payload": {
"action": "listEntities",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"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"
}

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/search and filters.category.
  • Grouping uses the exact string, so use one stable spelling per category.
{
"type": "request",
"payload": {
"action": "listLocations",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"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"
}

Capability (v1): console.execute

Executes a console command on the game server.

{
"type": "request",
"payload": {
"action": "executeConsoleCommand",
"args": "{\"command\": \"say Hi\"}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": {
"success": true,
"rawResult": "Message sent: Hi",
"errorMessage": null
},
"requestId": "request-uuid"
}

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).

{
"type": "request",
"payload": {
"action": "sendMessage",
"args": "{\"message\": \"Welcome to the server!\", \"opts\": {\"recipient\": {\"gameId\": \"12345\"}}}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

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).

{
"type": "request",
"payload": {
"action": "teleportPlayer",
"args": "{\"player\": {\"gameId\": \"12345\"}, \"x\": 123.45, \"y\": 67.89, \"z\": 10.11, \"dimension\": \"nether\"}"
},
"requestId": "request-uuid"
}
{
"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.

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.

{
"type": "request",
"payload": {
"action": "testReachability",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": {
"connectable": true,
"reason": null
},
"requestId": "request-uuid"
}

Capability (v1): moderation.kick

Kicks a player from the server.

{
"type": "request",
"payload": {
"action": "kickPlayer",
"args": "{\"player\": {\"gameId\": \"12345\"}, \"reason\": \"Violated server rules\"}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

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.

{
"type": "request",
"payload": {
"action": "banPlayer",
"args": "{\"player\": {\"gameId\": \"12345\"}, \"reason\": \"Cheating\", \"expiresAt\": \"2031-12-31T23:59:59Z\"}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

Capability (v1): moderation.unban

Removes a ban for a specific player.

{
"type": "request",
"payload": {
"action": "unbanPlayer",
"args": "{\"gameId\": \"12345\"}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

Capability (v1): moderation.listBans

Retrieves a list of all currently banned players.

{
"type": "request",
"payload": {
"action": "listBans",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"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"
}

Capability (v1): server.shutdown

Initiates a graceful shutdown sequence for the game server.

{
"type": "request",
"payload": {
"action": "shutdown",
"args": "{}"
},
"requestId": "request-uuid"
}
{
"type": "response",
"payload": null,
"requestId": "request-uuid"
}

These are the events that Takaro expects to receive from game servers. These events allow Takaro to react to changes in real-time.

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.

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" }
  • position is 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 a player.
  • 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 getPlayerLocation as a side effect, as before. The exception is a server that declares events.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"
}
}
}

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
}
}
}
}

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"
}
}
}
}

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:

  • global
  • team
  • friends
  • whisper

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"
}
}
}
}

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"
}
}
}
}

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"
}
}
}
}

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
}
}

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
}
}