Appearance
Session lifecycle
A session is one running game instance streamed to the user. The Platform API checks eligibility, applies the plan tier, creates the session in the Runtime service and returns what the client needs to connect. Both calls need a user access token and act on the caller's own sessions.
Start: POST /v1/me/sessions
Operation: createGameSession.
| Part | Field | Type | Notes |
|---|---|---|---|
| Header | Idempotency-Key | string, 8-128 chars | Required. Fresh per user action. |
| Body | appSlug | string, 1-100 | Required. Game slug, [a-z0-9_-]. |
| Body | runtimeAppId | string | Optional launch variant. Must be an enabled variant of the game; omitted means the default (or first) one. |
| Body | create_lobby | boolean | Default false: solo session. true opts in to a lobby. |
| Body | preferences | object | Optional; every field optional. |
preferences fields: width (320-7680), height (240-4320), fps (1-360), bitrateKbps (1000-150000), hdr, yuv444, audioChannels (1-8).
curl
bash
curl -X POST https://api.example.com/v1/me/sessions \
-H 'Authorization: Bearer <ACCESS_TOKEN>' \
-H 'Idempotency-Key: 6f1c2b7e-example-key' \
-H 'Content-Type: application/json' \
-d '{
"appSlug": "example-game",
"create_lobby": false,
"preferences": { "width": 2560, "height": 1440, "fps": 120, "hdr": true, "audioChannels": 6 }
}'TypeScript
ts
const res = await fetch("https://api.example.com/v1/me/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
appSlug: "example-game",
preferences: { width: 2560, height: 1440, fps: 120 },
}),
});
const session = await res.json(); // 201 on successResponse 201 (for a tier capped at 1920x1080/60 fps, HDR disabled, with locally resolved 6-channel audio):
json
{
"sessionId": "sess_example",
"playUrl": "https://play.example.com/s/sess_example",
"token": "<MEMBER_TOKEN>",
"display": { "width": 1920, "height": 1080, "fps": 60, "hdr": false },
"stream": {
"width": 1920, "height": 1080, "fps": 60,
"bitrateKbps": 12500, "hdr": false, "yuv444": false, "audioChannels": 6
}
}playUrlandtokenare what the player client uses to connect to the stream. Treattokenas a secret.displayis the plan tier's display profile (advisory).streamreports locally resolved settings after tier clamping. It is not a measurement of the running stream. The current adapter forwards resolution, fps, bitrate and conditional HDR; it does not forwardyuv444oraudioChannels. The streaming backend may have additional capability limits.
Tier clamping
The plan tier is a ceiling. Preferences above it are degraded, never rejected:
- Resolution keeps your aspect ratio and shrinks to fit the tier's resolution (dimensions rounded to even numbers). Sending only
widthorheightderives the other from the tier's aspect ratio. fpsis capped at the tier's fps.hdrinherits the tier setting when omitted; an explicit preference is enabled only when the tier permits it.yuv444defaults to false and also requires tier support, but is not forwarded by the current adapter.audioChannelsinputs accept 1-8. The resolver chooses 2, 6 or 8 with a stereo minimum, so requesting 1 returns 2. The default is 2; the current adapter does not forward this value.bitrateKbpsdefaults to a value computed from the mode (about 12 Mbps at 1080p60) and is capped by the tier maximum.
Read stream to see the resolved preferences; verify actual capabilities in the player/backend rather than assuming every resolved field is enforced.
Errors
| Status | error | Meaning / action |
|---|---|---|
| 400 | (validation shape) | Invalid body or Idempotency-Key. |
| 402 | insufficient_credits | Account has no credits. |
| 403 | forbidden | Account inactive. |
| 403 | banned | Account banned. |
| 403 | plan_required | No plan that allows streaming. |
| 404 | app_not_found | No enabled runtime app for the game or runtimeAppId. |
| 409 | concurrent_limit | Plan's concurrent session limit reached; stop one first. |
| 409 | idempotency_key_conflict | Key collision; use a new key. |
| 409 | idempotency_key_used | That key's earlier attempt already failed or ended; use a new key. |
| 503 | unavailable | Runtime could not create the session; retry. |
| 503 | panic_mode | Maintenance; see limits. |
Note:
On a lost response, reuse the same key for the same action. An open link reuses its runtime idempotency key. A failed or ended link returns
idempotency_key_used; start a new action with a new key. Eligibility and concurrency checks can still refuse a retry, so do not assume an identical response. Internal retries to runtime also reuse the same key. An acknowledged runtime failure marks the link failed; do not blindly retry that terminal attempt indefinitely.
Stop: POST /v1/me/sessions/stop
Operation: stopGameSessions. No body. Stops all of the caller's open sessions.
bash
curl -X POST https://api.example.com/v1/me/sessions/stop \
-H 'Authorization: Bearer <ACCESS_TOKEN>'json
{ "stopped": true }It is idempotent: with nothing open it returns { "stopped": false }. A 503 unavailable means the runtime could not stop it; retry. Stop remains available during maintenance lockdown.
Login sessions are separate
GET /v1/me/sessions lists authentication sessions. Its DELETE operation revokes login access; it does not stop a running game. See Profile and security and use the game stop POST above when releasing a streaming session.