curl --request POST \
--url https://api.simpl.gg/v1/lobbies/join \
--header 'Content-Type: application/json' \
--header 'api-key: <api-key>' \
--header 'x-player-id: <x-player-id>' \
--data '
{
"invite_code": "SIMPL-K7Q2F1",
"state": {
"mmr": 1500
}
}
'import requests
url = "https://api.simpl.gg/v1/lobbies/join"
payload = {
"invite_code": "SIMPL-K7Q2F1",
"state": { "mmr": 1500 }
}
headers = {
"x-player-id": "<x-player-id>",
"api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-player-id': '<x-player-id>',
'api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({invite_code: 'SIMPL-K7Q2F1', state: {mmr: 1500}})
};
fetch('https://api.simpl.gg/v1/lobbies/join', 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/join",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'invite_code' => 'SIMPL-K7Q2F1',
'state' => [
'mmr' => 1500
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.simpl.gg/v1/lobbies/join"
payload := strings.NewReader("{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-player-id", "<x-player-id>")
req.Header.Add("api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.simpl.gg/v1/lobbies/join")
.header("x-player-id", "<x-player-id>")
.header("api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.simpl.gg/v1/lobbies/join")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-player-id"] = '<x-player-id>'
request["api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}"
response = http.request(request)
puts response.read_body{
"lobby_id": "lobby_456",
"queue_id": "ranked_2v2",
"status": "waiting",
"host_player_id": "player_1",
"is_private": true,
"max_players": 4,
"current_players": 2,
"players": [
{
"player_id": "player_1",
"is_host": true,
"joined_at": "2026-09-21T14:00:00Z",
"state": {
"mmr": 1500,
"team": "team_1",
"regions": [
"iad",
"dfw"
]
}
}
],
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "Austin's lobby",
"region": "iad",
"invite_code": "SIMPL-K7Q2F1",
"settings": {
"map": "forest",
"mode": "ctf",
"difficulty": "hard"
},
"server": {
"instance_id": "abc123",
"region": "iad",
"status": "launching",
"match_id": "xyz789",
"network_ports": [
{
"name": "game_udp",
"protocol": "udp",
"internal_port": 7777,
"external_port": 30412,
"host": "37.16.24.10",
"tls_enabled": false
}
]
},
"match_id": "xyz789"
}Join a lobby by invite code
Joins whichever lobby carries this invite code, public or private. The only way into a private lobby.
curl --request POST \
--url https://api.simpl.gg/v1/lobbies/join \
--header 'Content-Type: application/json' \
--header 'api-key: <api-key>' \
--header 'x-player-id: <x-player-id>' \
--data '
{
"invite_code": "SIMPL-K7Q2F1",
"state": {
"mmr": 1500
}
}
'import requests
url = "https://api.simpl.gg/v1/lobbies/join"
payload = {
"invite_code": "SIMPL-K7Q2F1",
"state": { "mmr": 1500 }
}
headers = {
"x-player-id": "<x-player-id>",
"api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-player-id': '<x-player-id>',
'api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({invite_code: 'SIMPL-K7Q2F1', state: {mmr: 1500}})
};
fetch('https://api.simpl.gg/v1/lobbies/join', 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/join",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'invite_code' => 'SIMPL-K7Q2F1',
'state' => [
'mmr' => 1500
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.simpl.gg/v1/lobbies/join"
payload := strings.NewReader("{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-player-id", "<x-player-id>")
req.Header.Add("api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.simpl.gg/v1/lobbies/join")
.header("x-player-id", "<x-player-id>")
.header("api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.simpl.gg/v1/lobbies/join")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-player-id"] = '<x-player-id>'
request["api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"invite_code\": \"SIMPL-K7Q2F1\",\n \"state\": {\n \"mmr\": 1500\n }\n}"
response = http.request(request)
puts response.read_body{
"lobby_id": "lobby_456",
"queue_id": "ranked_2v2",
"status": "waiting",
"host_player_id": "player_1",
"is_private": true,
"max_players": 4,
"current_players": 2,
"players": [
{
"player_id": "player_1",
"is_host": true,
"joined_at": "2026-09-21T14:00:00Z",
"state": {
"mmr": 1500,
"team": "team_1",
"regions": [
"iad",
"dfw"
]
}
}
],
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"name": "Austin's lobby",
"region": "iad",
"invite_code": "SIMPL-K7Q2F1",
"settings": {
"map": "forest",
"mode": "ctf",
"difficulty": "hard"
},
"server": {
"instance_id": "abc123",
"region": "iad",
"status": "launching",
"match_id": "xyz789",
"network_ports": [
{
"name": "game_udp",
"protocol": "udp",
"internal_port": 7777,
"external_port": 30412,
"host": "37.16.24.10",
"tls_enabled": false
}
]
},
"match_id": "xyz789"
}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"
Body
Response
Joined. The full lobby, including the new player.
"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"