Skip to content
Open Markdown

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.

PartFieldTypeNotes
HeaderIdempotency-Keystring, 8-128 charsRequired. Fresh per user action.
BodyappSlugstring, 1-100Required. Game slug, [a-z0-9_-].
BodyruntimeAppIdstringOptional launch variant. Must be an enabled variant of the game; omitted means the default (or first) one.
Bodycreate_lobbybooleanDefault false: solo session. true opts in to a lobby.
BodypreferencesobjectOptional; 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 success

Response 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
  }
}
  • playUrl and token are what the player client uses to connect to the stream. Treat token as a secret.
  • display is the plan tier's display profile (advisory).
  • stream reports 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 forward yuv444 or audioChannels. 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 width or height derives the other from the tier's aspect ratio.
  • fps is capped at the tier's fps.
  • hdr inherits the tier setting when omitted; an explicit preference is enabled only when the tier permits it. yuv444 defaults to false and also requires tier support, but is not forwarded by the current adapter.
  • audioChannels inputs 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.
  • bitrateKbps defaults 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 ​

StatuserrorMeaning / action
400(validation shape)Invalid body or Idempotency-Key.
402insufficient_creditsAccount has no credits.
403forbiddenAccount inactive.
403bannedAccount banned.
403plan_requiredNo plan that allows streaming.
404app_not_foundNo enabled runtime app for the game or runtimeAppId.
409concurrent_limitPlan's concurrent session limit reached; stop one first.
409idempotency_key_conflictKey collision; use a new key.
409idempotency_key_usedThat key's earlier attempt already failed or ended; use a new key.
503unavailableRuntime could not create the session; retry.
503panic_modeMaintenance; 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.

Built for developers. Ready for agents.