Session Lifecycle

Every conversation with the orchestrator is scoped to a session. Sessions are created in the database before the WebSocket is established, ensuring clean ownership and preventing ID spoofing.

Creating a session

POST /api/sessions
Authorization: Bearer <access_token>
              OR
X-Api-Key: <api_key>

Response:

{
  "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "ws_url": "wss://api.example.com/ws/user-agent/3fa85f64-...?token=eyJ…"
}

The token is a short-lived JWT (5 minutes) bound to session_id. It cannot be used to connect to a different session.

Phase transitions

STARTED ──────────────────────────────────┐
   │                                      │
   │ WebSocket connect                    │ token expired /
   ▼                                      │ never connected
CONNECTED                                 │
   │                                      │
   │ CONNECT_AGENT tool call              │
   ▼                                      │
AGENT_CONNECTED                           │
   │                                      │
   │ USER_MESSAGE received                │
   ▼                                      │
WORKING ◄──────────────────────────────┐  │
   │                                   │  │
   │ action needs payment              │  │
   ▼                                   │  │
AWAITING_PAYMENT                       │  │
   │ PAYMENT_RESPONSE (approved)       │  │
   └───────────────────────────────────┘  │
                                          │
   Any phase → CANCEL_SESSION             │
   Any phase → server error              │
   Orchestrator → close_session tool      │
   ▼                                      │
CLOSED ◄──────────────────────────────────┘

Reconnection

Sessions in STARTED or CONNECTED phase can be reconnected with the same session_id and a new token (call POST /api/sessions again with the same credentials — implementation note: currently a new session_id is issued on each call).

The WebSocket endpoint rejects any session_id that is not found in the database (close code 4004). Always call POST /api/sessions first — never generate a session ID client-side.

Session expiry

Sessions in CLOSED phase are retained for 30 days for audit purposes, then purged. Active sessions are kept indefinitely until closed.