Skip to main content
PlayFlow provides a single SSE endpoint per player that streams everything you need: lobby updates, queue stats, match notifications, and server status changes. No polling required.

The Endpoint

GET /v3/lobbies/{config}/me/events
x-player-id: {player_id}
api-key: {key}
Accept: text/event-stream
  • One connection per player is enough — all events for their current lobby flow through it
  • The connection stays open indefinitely (with keep-alive pings every 30s)
  • When the player leaves the lobby, close the connection
The SSE connection doubles as a heartbeat. As long as the stream is open, PlayFlow knows the player is alive. You don’t need a separate heartbeat endpoint unless you’re not using SSE (e.g., polling clients on legacy platforms).

Event Types

EventWhen it firesData
connectedRight after connection opensFull lobby state
lobby_updatedAny time the lobby changesFull lobby state
queue_statsEvery 10s while in_queue{ playersSearching, lobbiesInQueue, avgWaitSeconds }
lobby_deletedLobby was deleted{ id }
pingEvery 30s (keep-alive)Empty string

Event: connected

Fires immediately on connection. Gives you the full current state — no need to call GET /me first.
event: connected
data: {"id":"abc-123","status":"waiting","host":"p1","players":[...],...}

Event: lobby_updated

Fires whenever the lobby changes:
  • A player joins or leaves
  • Host kicks someone
  • A player updates their state
  • Host changes settings
  • Host starts matchmaking / game
  • Match found → status becomes in_game
  • Game server status changes (launching → running)
event: lobby_updated
data: {"id":"abc-123","status":"in_game","server":{"ip":"...","port":7770,...},...}
Key usage: When status becomes in_game and server.status becomes running, connect your game client.

Event: queue_stats

Only fires while status: in_queue. Emitted every 10 seconds.
event: queue_stats
data: {"playersSearching":42,"lobbiesInQueue":8,"avgWaitSeconds":12.3}
Use this to show live “42 searching, ~12s wait” in your matchmaking UI.

Event: lobby_deleted

Fires when the lobby is deleted (last player left, host deleted it, or cleanup timeout).
event: lobby_deleted
data: {"id":"abc-123"}
Close the connection on this event — there’s nothing left to subscribe to.

Event: ping

Keep-alive every 30 seconds. Empty data. You can ignore these in your handler — they exist only to keep the connection alive through proxies and load balancers.
event: ping
data:

Client Examples

const playerId = "player_123";
const config = "ranked";
const apiKey = "pfclient_...";

// Note: EventSource doesn't support custom headers directly.
// Pass the api-key and player-id via query params or use a polyfill.
const url = `https://api.computeflow.cloud/api/v3/lobbies/${config}/me/events`;

// Use fetch + ReadableStream for full header support:
const res = await fetch(url, {
  headers: {
    "api-key": apiKey,
    "x-player-id": playerId,
    "Accept": "text/event-stream",
  },
});

const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  buffer += decoder.decode(value, { stream: true });
  const events = buffer.split("\n\n");
  buffer = events.pop() ?? "";
  
  for (const block of events) {
    const eventMatch = block.match(/^event: (.+)$/m);
    const dataMatch = block.match(/^data: (.+)$/m);
    if (!eventMatch || !dataMatch) continue;
    
    const eventType = eventMatch[1];
    const data = JSON.parse(dataMatch[1]);
    
    switch (eventType) {
      case "connected":
      case "lobby_updated":
        console.log("Lobby:", data);
        if (data.status === "in_game" && data.server?.status === "running") {
          connectToGameServer(data.server.ports[0].host, data.server.ports[0].port);
        }
        break;
      case "queue_stats":
        updateQueueUI(data.playersSearching, data.avgWaitSeconds);
        break;
      case "lobby_deleted":
        console.log("Lobby deleted");
        return;
    }
  }
}

Handling Disconnects

SSE connections can drop due to network issues, proxy timeouts, or server restarts. Your client should:
  1. Detect disconnect — the read loop exits or the connection errors
  2. Reconnect automatically — with exponential backoff (1s, 2s, 4s, max 30s)
  3. Replay state on reconnect — the connected event sends the current full state, so you can recover cleanly
While disconnected, you won’t receive events. You might miss a match, a kick, or a server ready event. Your reconnect logic should fetch GET /me on reconnect to ensure state consistency, OR rely on the connected event’s initial state.

Polling as a Fallback

If SSE isn’t available (e.g., your platform blocks streaming), poll GET /me instead:
# Every 2-5 seconds
curl "https://api.computeflow.cloud/api/v3/lobbies/{config}/me" \
  -H "api-key: pfclient_..." \
  -H "x-player-id: {player}"
With polling, you should also enable heartbeat in your lobby config (since the SSE connection isn’t keeping the player alive) and send periodic heartbeats:
POST /v3/lobbies/{config}/me/heartbeat

The Full Matchmaking Flow with SSE

This is what a player’s event stream looks like during a matchmaking session:
# 1. Connect
event: connected
data: {"status":"waiting","players":[{"id":"p1","isHost":true}],...}

# 2. Player starts matchmaking
event: lobby_updated
data: {"status":"in_queue","matchmaking":{"mode":"5v5","queueStats":{...}}}

# 3. Queue stats stream every 10s
event: queue_stats
data: {"playersSearching":42,"avgWaitSeconds":12.3}

event: queue_stats
data: {"playersSearching":45,"avgWaitSeconds":11.8}

# 4. Match found! Server launching
event: lobby_updated
data: {"status":"in_game","matchId":"m_abc","server":{"status":"launching","ports":[...]}}

# 5. Server ready
event: lobby_updated
data: {"status":"in_game","server":{"status":"running","ports":[{"host":"1.2.3.4","port":7770}]}}
# → Client now connects to 1.2.3.4:7770

# 6. Game ends, lobby cleanup
event: lobby_deleted
data: {"id":"abc-123"}
That’s the entire competitive matchmaking experience — queue, find opponents, launch server, connect — delivered through one SSE stream.

Matchmaking

How matchmaking finds opponents and forms matches.

API Reference

Full SSE endpoint reference.