Sessions
A session is one live, full-duplex conversation seat. Mint it here, then connect your client directly to the returned edge — see the data plane for the WebSocket protocol.
Create a session
POST /api/v1/sessionsRequired scope: sessions:write (secret key) or session:connect
(publishable key — stock personas only, origin-checked).
Request body — pick one of persona / avatar_ref:
{ "persona": "mei" }{ "avatar_ref": "019...", "voice_ref": "019..." }| Field | Required | Description |
|---|---|---|
persona | One-of | Stock persona key from the public gallery (mei, david, …). Works without a workspace. |
avatar_ref | One-of | Custom avatar version id (see Avatars). Secret, workspace-bound keys only. |
voice_ref | No | Voice version id override. Secret keys only. |
workspace_id | Conditional | Only when the key is not workspace-bound (and only for avatar_ref/voice_ref mints). |
domain_allowlist | No | Origins permitted to connect with the minted token. Publishable keys: overridden by the key’s registered origins. |
Response 201 — seat granted:
{ "status": "ready", "session_id": "019...", "connect_url": "https://box-1.casola.ai", "session_token": "eyJhbGciOiJFZERTQ...", "seat_token": "…", "expires_at": 1719000060}| Field | Description |
|---|---|
connect_url | The assigned edge’s https base URL. Derive WebSocket URLs by swapping https → wss and appending /mse / /mic_stream. |
session_token | Short-lived (≈60 s) EdDSA JWT the edge verifies offline. Browsers pass it as ?token=; servers/native as Authorization: Bearer. |
seat_token | Opaque seat handle (internal; the platform uses it for heartbeat/release plumbing). |
expires_at | Unix seconds when session_token expires. Connect before this; the live session then runs up to the server-set cap (default ≈300 s). |
Response 202 — fleet at capacity, you’re queued:
{ "status": "queued", "ticket": "…", "ahead": 3, "queue_ws": "/api/v1/sessions/queue?ticket=…" }Open queue_ws as a WebSocket for live position events; when promoted, POST
/api/v1/sessions again to claim your seat.
Queue WebSocket
GET /api/v1/sessions/queue?ticket={ticket} (WebSocket upgrade)No API key needed — the ticket is the credential.
Get a session
GET /api/v1/sessions/{sessionId}Required scope: sessions:read
Returns the session record including its current status (pending, active,
or ended).
{ "id": "019...", "workspace_id": "019...", "api_token_id": "019...", "avatar_ref": "019...", "voice_ref": null, "status": "pending", "box_host": "box-1.casola.ai", "created_at": 1719000000}Heartbeat & release
POST /api/v1/sessions/{sessionId}/heartbeat scope: sessions:writePOST /api/v1/sessions/{sessionId}/release scope: sessions:writeLive media traffic is itself the liveness signal — heartbeat only matters for
a seat you are holding while not yet connected. release frees the seat early
on a clean client exit (promotes the queue head immediately instead of waiting
for the idle reaper).