Entropia Central broadcasts live activity over SignalR. Three feeds are public and open to anyone: globals, trade messages and PvP actions. Connect to a hub, listen for its event, and the server pushes records as they are recorded.

These feeds are read only. The hubs push data to you and there is nothing to send back beyond the subscription calls described below.

Available hubs

All hubs live under https://api.entropiacentral.com.

Hub Path Event you listen for What it carries
Globals /hubs/globals ReceiveGlobal Globals, HOFs and ATHs as they are recorded
Trade messages /hubs/trademessages ReceiveTradeMessage Messages from the in-game trade channels
PvP actions /hubs/pvpactions ReceivePvpAction PvP kills

Connecting

Build a connection, register your handler, then start it. Register handlers before calling start() so you do not miss records that arrive during the handshake.

ts
import { HubConnectionBuilder } from '@microsoft/signalr';

const connection = new HubConnectionBuilder()
  .withUrl('https://api.entropiacentral.com/hubs/globals')
  .withAutomaticReconnect()
  .build();

connection.on('ReceiveGlobal', (global) => {
  console.log(global.avatarName, global.globalValue, global.type);
});

await connection.start();

Payload properties are camelCased on the wire, so the C# property AvatarName arrives as avatarName.

Globals and trade messages start streaming immediately

Connecting to the globals hub or the trade messages hub is enough. The server adds you to that hub's broadcast group as part of the connection, so records begin arriving as soon as start() resolves.

PvP actions require an explicit join

The PvP hub is the exception. Connecting alone delivers nothing. Call JoinPvpActions after starting:

ts
const connection = new HubConnectionBuilder()
  .withUrl('https://api.entropiacentral.com/hubs/pvpactions')
  .withAutomaticReconnect()
  .build();

connection.on('ReceivePvpAction', (action) => {
  console.log(action.attacker, 'killed', action.defender);
});

await connection.start();
await connection.invoke('JoinPvpActions');

Call LeavePvpActions to stop receiving them without dropping the connection. Re-invoke JoinPvpActions after a reconnect, because group membership does not survive one.

Narrowing what you receive

Each hub accepts subscription calls that add you to a narrower group.

Globals

Call Argument Effect
SubscribeToGlobalType type string, for example hof Globals of that type only
UnsubscribeFromGlobalType type string Stops the above
SubscribeToEvent numeric event id Globals scored towards that community event
UnsubscribeFromEvent numeric event id Stops the above

Trade messages

Call Argument Effect
SubscribeToChannel channel name, for example trade Messages on that channel only
UnsubscribeFromChannel channel name Stops the above

PvP actions

Call Argument Effect
JoinPvpActions none All PvP actions
JoinAttacker avatar name Actions where that avatar is the attacker
JoinDefender avatar name Actions where that avatar is the defender
LeavePvpActions, LeaveAttacker, LeaveDefender matching argument Stops the above

Avatar and channel names are matched case insensitively.

Subscribing causes duplicate deliveries

This is the one behaviour that surprises people. A narrower subscription does not replace the broad feed, it adds a second delivery path, and the server broadcasts to every matching group.

On the globals hub you are already in the broadcast group from the moment you connect. If you then call SubscribeToGlobalType('hof'), a HOF is sent to the broad group and to the type group, so your ReceiveGlobal handler fires twice for the same record. Trade message channels and PvP attacker and defender groups behave the same way.

Two ways to deal with it:

  • Use the broad feed and filter client side, which is the simplest option and what the Entropia Central site itself does.
  • Or subscribe narrowly and deduplicate. Globals carry strippedMessage, which is the value the server itself hashes for deduplication, and trade messages carry a stable id.

Subscribing to a specific attacker and defender who appear in the same kill will deliver that action three times: once for the broad group and once for each name group.

Payloads

ReceiveGlobal

Property Type Notes
avatarName string Avatar that recorded the global
globalValue number Value in PED
type string Global category, for example hunting or mining
dateTime string UTC timestamp, always set by the server
isHof, isAth, isTeam boolean Classification flags
fullMessage string Original in-game message
strippedMessage string Message without timestamp or channel prefix, used for deduplication
creatureName, depositName, instanceName, craftedItemName, landareaName, rareItemName, discoveredItemName, tieredItemName string Populated according to type, empty otherwise
tieredItemTier number Tier reached, for tiering globals
pvpSpree number Kill count, for PvP globals
detailRoute string or null Wiki path for the subject, for example /wiki/creatures/some-slug

The name fields are always present and are empty strings when they do not apply, rather than being omitted.

ReceiveTradeMessage

Property Type Notes
id number Stable identifier, useful for deduplication
channel string Originating in-game channel
author string Avatar that posted
content string Message text
dateTime string UTC timestamp, most recent posting when reposts were collapsed
repeatCount number 1 for a single posting, higher when identical reposts were collapsed
firstPostedAt string or null First posting time, set only when reposts were collapsed

ReceivePvpAction

Property Type Notes
attacker string Avatar that got the kill
defender string Avatar that was killed
weapon string Weapon used
dateTime string UTC timestamp

Reconnects

Use withAutomaticReconnect(). Two things to keep in mind when a connection drops and comes back:

Nothing is replayed. Records broadcast while you were disconnected are gone. If you need an unbroken series, re-fetch the current state from the REST endpoints on reconnect and treat the socket as live updates only.

Group membership is not restored. Automatic group joins are re-applied by the server, so globals and trade messages resume on their own. Anything you joined by calling a method, including every PvP subscription, has to be re-invoked:

ts
connection.onreconnected(async () => {
  await connection.invoke('JoinPvpActions');
});