# Start a game session

`POST /v1/me/sessions`

URL: https://docs.spacerun.co/docs/platform/reference/game-sessions/createGameSession

- **Operation ID:** `createGameSession`
- **Tags:** Game sessions
- **Base URL:** `http://localhost:8787`

Starts a cloud-gaming session for the caller. The plan tier is the ceiling for resolved stream settings. An open link reuses the runtime idempotency key; failed or ended links return `idempotency_key_used`. Returned `stream` values are resolved locally: the current adapter does not forward `yuv444` or `audioChannels`, and actual support depends on the streaming backend.

**Workflow:** [Integration guide](https://docs.spacerun.co/docs/platform/guides/session-lifecycle).

**Authentication:** Platform user Bearer JWT. Acts only on the caller's own data.

**Idempotency:** Send a fresh 8-128 character key per user action; retries of the same action reuse it.

## Authentication

- **Auth:** Platform user Bearer JWT (`Authorization: Bearer <access_token>`).

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `idempotency-key` | header | `string` | yes | Min length: 8. Max length: 128 |

## Request body

Required: yes.

Content type: `application/json`

Schema: `object`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `appSlug` | `string` | yes | Min length: 1. Max length: 100. Pattern: `^[a-z0-9][a-z0-9_-]*$` |
| `runtimeAppId` | `string` | no | Min length: 1. Max length: 200 |
| `create_lobby` | `boolean` | no | Default: `false` |
| `preferences` | `object` | no | - |
| `preferences.width` | `integer` | no | Min: 320. Max: 7680 |
| `preferences.height` | `integer` | no | Min: 240. Max: 4320 |
| `preferences.fps` | `integer` | no | Min: 1. Max: 360 |
| `preferences.bitrateKbps` | `integer` | no | Min: 1000. Max: 150000 |
| `preferences.hdr` | `boolean` | no | - |
| `preferences.yuv444` | `boolean` | no | - |
| `preferences.audioChannels` | `integer` | no | Min: 1. Max: 8 |

**Example**

```json
{
  "appSlug": "example-game",
  "create_lobby": false,
  "preferences": {
    "width": 1280,
    "height": 720,
    "fps": 30
  }
}
```

## Responses

### 201

Session created; stream fields report locally resolved settings.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `sessionId` | `string` | yes | - |
| `playUrl` | `string` | yes | - |
| `token` | `string` | yes | - |
| `display` | `object` | yes | - |
| `display.width` | `integer` | yes | - |
| `display.height` | `integer` | yes | - |
| `display.fps` | `integer` | yes | - |
| `display.hdr` | `boolean` | no | - |
| `stream` | `object` | yes | - |
| `stream.width` | `integer` | yes | - |
| `stream.height` | `integer` | yes | - |
| `stream.fps` | `integer` | yes | - |
| `stream.bitrateKbps` | `integer` | yes | - |
| `stream.hdr` | `boolean` | yes | - |
| `stream.yuv444` | `boolean` | yes | - |
| `stream.audioChannels` | `integer` | yes | - |

**Example**

```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": 1280,
    "height": 720,
    "fps": 30,
    "bitrateKbps": 3000,
    "hdr": false,
    "yuv444": false,
    "audioChannels": 2
  }
}
```

## Errors

### 400

Request validation failed.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ValidationErrorBody)`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `success` | `boolean` | yes | One of: `false` |
| `error` | `object` | yes | - |
| `error.name` | `string` | yes | One of: `"ZodError"` |
| `error.issues` | `object[]` | yes | - |
| `error.issues[].code` | `string` | yes | - |
| `error.issues[].path` | `(string \| number)[]` | yes | - |
| `error.issues[].message` | `string` | yes | - |

**Request validation**

```json
{
  "success": false,
  "error": {
    "name": "ZodError",
    "issues": [
      {
        "code": "custom",
        "path": [
          "field"
        ],
        "message": "Invalid value"
      }
    ]
  }
}
```

### 401

Missing, malformed, expired or wrong-audience Bearer token (`missing_token`, `invalid_token`, `invalid_audience`).

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `error` | `string` | yes | Stable machine-readable error code, e.g. `forbidden`, `not_found`. |
| `details` | `any` | no | Optional structured context. For 403 it is `{ perm }`. |

**Error response**

```json
{
  "error": "missing_token"
}
```

### 402

`insufficient_credits`: the account has no credits.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`, fields as described above.

**Error response**

```json
{
  "error": "insufficient_credits"
}
```

### 403

`forbidden` (inactive account), `banned`, or `plan_required`.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`, fields as described above.

**Error response**

```json
{
  "error": "forbidden"
}
```

### 404

`app_not_found`: no enabled runtime app for the game or `runtimeAppId`.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`, fields as described above.

**Error response**

```json
{
  "error": "app_not_found"
}
```

### 409

`concurrent_limit`, `idempotency_key_conflict` or `idempotency_key_used`.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`, fields as described above.

**Error response**

```json
{
  "error": "concurrent_limit"
}
```

### 500

Unexpected server error (`internal`). No details are returned.

- Header `x-request-id`: Request identifier; quote it when reporting an error.
Content type: `application/json`

Schema: `object (ErrorBody)`, fields as described above.

**Error response**

```json
{
  "error": "internal"
}
```

### 503

`unavailable`: the runtime could not create the session; retry. Maintenance can refuse this write before authentication (degraded blocks session start and checkout; lockdown blocks other public/user writes).

- Header `x-request-id`: Request identifier; quote it when reporting an error.
- Header `Retry-After`: Maintenance retry delay in seconds; present for panic_mode. Example: `30`.
Content type: `application/json`

Schema: `object (ErrorBody) | object (MaintenanceErrorBody)`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `(variant 1).error` | `string` | yes | Stable machine-readable error code, e.g. `forbidden`, `not_found`. |
| `(variant 1).details` | `any` | no | Optional structured context. For 403 it is `{ perm }`. |
| `(variant 2).error` | `string` | yes | One of: `"panic_mode"` |
| `(variant 2).level` | `string` | yes | One of: `"degraded"`, `"lockdown"` |
| `(variant 2).reason` | `string \| null` | yes | - |

**Error response**

```json
{
  "error": "unavailable"
}
```

**Dependency unavailable**

```json
{
  "error": "unavailable"
}
```

**Maintenance lockdown**

```json
{
  "error": "panic_mode",
  "level": "lockdown",
  "reason": "Scheduled maintenance"
}
```

## Examples

### curl

```bash
curl -X POST 'http://localhost:8787/v1/me/sessions' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H 'idempotency-key: 7d0f3c52-9a1e-4b6f-8c2d-5e4a3b2c1d0e' \
  -H 'Content-Type: application/json' \
  --data '{"appSlug":"example-game","create_lobby":false,"preferences":{"width":1280,"height":720,"fps":30}}'
```

### TypeScript

```ts
const accessToken = process.env.ACCESS_TOKEN; // user JWT from your sign-in flow

const response = await fetch("http://localhost:8787/v1/me/sessions", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${accessToken}`,
    "idempotency-key": "7d0f3c52-9a1e-4b6f-8c2d-5e4a3b2c1d0e",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "appSlug": "example-game",
    "create_lobby": false,
    "preferences": {
      "width": 1280,
      "height": 720,
      "fps": 30
    }
  }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
const data = response.status === 204 || response.status === 205
  ? undefined
  : response.headers.get("content-type")?.includes("json")
    ? await response.json()
    : await response.text();
```
