curl --request GET \
--url https://api.simpl.gg/v1/lobbies/{lobby_id}/events \
--header 'api-key: <api-key>' \
--header 'x-player-id: <x-player-id>'import requests
url = "https://api.simpl.gg/v1/lobbies/{lobby_id}/events"
headers = {
"x-player-id": "<x-player-id>",
"api-key": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'x-player-id': '<x-player-id>', 'api-key': '<api-key>'}
};
fetch('https://api.simpl.gg/v1/lobbies/{lobby_id}/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.simpl.gg/v1/lobbies/{lobby_id}/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"api-key: <api-key>",
"x-player-id: <x-player-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.simpl.gg/v1/lobbies/{lobby_id}/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-player-id", "<x-player-id>")
req.Header.Add("api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.simpl.gg/v1/lobbies/{lobby_id}/events")
.header("x-player-id", "<x-player-id>")
.header("api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.simpl.gg/v1/lobbies/{lobby_id}/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-player-id"] = '<x-player-id>'
request["api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"player_id": "player_2",
"is_host": false,
"state": {
"mmr": 1480
},
"joined_at": "2026-09-21T14:00:05Z"
}Stream lobby events (SSE)
Opens a Server-Sent Events stream for this lobby. Every message carries a
named event: and a JSON data: payload, so clients dispatch on the
event name instead of sniffing the body.
Events
| event | payload | when |
|---|---|---|
lobby_updated | full lobby object | any lobby state change |
queue_stats | { players_searching, lobbies_in_queue, avg_wait_seconds } | every 10 seconds while in_queue |
server_ready | { instance_id, match_id, network_ports[] } | the game server is running and reachable |
lobby_deleted | { lobby_id, reason } | the lobby was destroyed; the stream closes after this |
player_joined | the player object | a player joined |
player_left | { player_id, reason } | a player left, was kicked, or dropped |
host_changed | { previous_host_player_id, new_host_player_id } | host transferred |
Wire format
event: player_joined
data: {"player_id":"player_2","is_host":false,"state":{"mmr":1480},"joined_at":"2026-09-21T14:00:05Z"}
event: queue_stats
data: {"players_searching":42,"lobbies_in_queue":8,"avg_wait_seconds":12.3}
event: server_ready
data: {"instance_id":"abc123","match_id":"xyz789","network_ports":[{"name":"game_udp","protocol":"udp","internal_port":7777,"external_port":30412,"host":"37.16.24.10","tls_enabled":false}]}
event: lobby_deleted
data: {"lobby_id":"lobby_456","reason":"host_left"}
A comment line (: keepalive) is sent periodically so idle connections
survive proxies. Reconnect with the standard Last-Event-ID header to
resume; on a gap, fetch GET /v1/lobbies/{lobby_id} and replace local
state rather than patching it.
curl --request GET \
--url https://api.simpl.gg/v1/lobbies/{lobby_id}/events \
--header 'api-key: <api-key>' \
--header 'x-player-id: <x-player-id>'import requests
url = "https://api.simpl.gg/v1/lobbies/{lobby_id}/events"
headers = {
"x-player-id": "<x-player-id>",
"api-key": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'x-player-id': '<x-player-id>', 'api-key': '<api-key>'}
};
fetch('https://api.simpl.gg/v1/lobbies/{lobby_id}/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.simpl.gg/v1/lobbies/{lobby_id}/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"api-key: <api-key>",
"x-player-id: <x-player-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.simpl.gg/v1/lobbies/{lobby_id}/events"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-player-id", "<x-player-id>")
req.Header.Add("api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.simpl.gg/v1/lobbies/{lobby_id}/events")
.header("x-player-id", "<x-player-id>")
.header("api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.simpl.gg/v1/lobbies/{lobby_id}/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-player-id"] = '<x-player-id>'
request["api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"player_id": "player_2",
"is_host": false,
"state": {
"mmr": 1480
},
"joined_at": "2026-09-21T14:00:05Z"
}Authorizations
Per-project client key, prefixed ck_live_. Player-facing endpoints
only, and browse never returns private lobbies. Safe to ship in a game
binary: a leak exposes one project's player surface, nothing else.
Headers
Identifies the acting player. Trusted verbatim: Simpl performs no authentication or token verification on this value. Bring your own identity system and pass whatever stable id it produces.
1 - 128"player_1"
Resume the stream after this event id following a reconnect.
Path Parameters
Lobby identifier.
"lobby_456"
Response
An open event stream. It stays open until the client disconnects or the lobby is deleted.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
- Option 6
- Option 7
The data: payload of a single event. Which schema applies is
determined by the event: name on the same message.
"lobby_456"
"ranked_2v2"
Lobby lifecycle:
waiting → in_queue → matched → in_game → waiting (rematch-ready)
↓
→ waiting (timeout/cancel/no opponents)
waiting → starting → in_game (host started directly)
→ waiting (server create failed)
waiting, in_queue, matched, starting, in_game "player_1"
Private lobbies never appear in GET /v1/lobbies for client keys, and
are joinable by invite code only.
1 <= x <= 1004
x >= 02
Show child attributes
Show child attributes
"Austin's lobby"
Datacenter region a server runs in. 16 regions are supported.
| code | location |
|---|---|
ams | Amsterdam, Netherlands |
arn | Stockholm, Sweden |
bom | Mumbai, India |
cdg | Paris, France |
dfw | Dallas, Texas (US) |
ewr | Secaucus, NJ (US) |
fra | Frankfurt, Germany |
iad | Ashburn, Virginia (US) |
lax | Los Angeles, California (US) |
lhr | London, United Kingdom |
nrt | Tokyo, Japan |
ord | Chicago, Illinois (US) |
sin | Singapore, Singapore |
sjc | San Jose, California (US) |
syd | Sydney, Australia |
yyz | Toronto, Canada |
Every region is available to every project. Capacity is Simpl's problem, not yours: pick the region closest to your players.
ams, arn, bom, cdg, dfw, ewr, fra, iad, lax, lhr, nrt, ord, sin, sjc, syd, yyz "iad"
Generated per the queue's invite_code_config. Null when the queue has
invite codes disabled.
"SIMPL-K7Q2F1"
Free-form, game-specific lobby settings: map, mode, difficulty, whatever
the game needs. Host-writable via
PATCH /v1/lobbies/{lobby_id}/settings.
{
"map": "forest",
"mode": "ctf",
"difficulty": "hard"
}
Connection details for the game server backing this lobby. Present once the
server is running. Connection-relevant fields only. Call
GET /v1/servers/{instance_id} with a server key for the full object.
Show child attributes
Show child attributes
"xyz789"