# Poll WebSocket Messages ## Overview Poll messages manage the lifecycle of viewer polls over the upstream WebSocket connection. They are session-scoped — you must be subscribed to the relevant session to send or receive them. All messages use the standard envelope: ```json { "type": "", "data": { ... } } ``` --- ## Message Flow ``` poll.start ──► (poll is open, viewers are voting) │ poll.ending ──► (countdown active) │ ┌───────────┴───────────┐ │ │ voting.ended poll.ending.cancelled (poll is closed) (countdown aborted, poll stays open) ``` --- ## Client → Server ### poll.start Triggers poll generation for the active session. ```json { "type": "poll.start", "sessionId": 3 } ``` | Field | Type | Required | Description | |-------------|--------|----------|-----------------------------------------------------------------------------| | `type` | string | yes | `"poll.start"` | | `sessionId` | number | no | Included for protocol consistency. The server uses its internally tracked session ID. | Any existing active poll is deactivated and replaced. ### poll.leading Sent by the client to report the current leading option. Typically sent whenever the lead changes. ```json { "type": "poll.leading", "sessionId": 3, "gameId": 17, "label": "Quiplash 3", "votes": 12 } ``` | Field | Type | Required | Description | |-------------|--------|----------|---------------------------------------| | `type` | string | yes | `"poll.leading"` | | `sessionId` | number | yes | Active session ID | | `gameId` | number | yes | Game ID of the leading option (0 for "Other") | | `label` | string | yes | Display label of the leading option | | `votes` | number | yes | Current vote count for the leader | --- ## Server → Client ### poll.ending Signals that voting will close after a countdown. Sent when the server initiates poll closure. ```json { "type": "poll.ending", "data": { "sessionId": 3, "endsAt": "2026-05-13T02:20:30.123456789Z", "delaySeconds": 30 } } ``` | Field | Type | Description | |----------------|--------|--------------------------------------------------| | `sessionId` | number | Active session ID | | `endsAt` | string | RFC 3339 timestamp when voting closes | | `delaySeconds` | number | Seconds remaining until voting closes | ### poll.ending.cancelled The previously announced countdown has been cancelled. Voting remains open. ```json { "type": "poll.ending.cancelled", "data": { "sessionId": 3 } } ``` | Field | Type | Description | |-------------|--------|-------------------| | `sessionId` | number | Active session ID | ### voting.ended Voting has closed. The active poll is finalized. ```json { "type": "voting.ended" } ``` No `data` payload. The server does not include results — consumers should query their own tallies or rely on the preceding `poll.leading` updates for the final state. --- ## Lifecycle Notes - A `poll.start` always replaces any existing active poll. - `poll.ending` may be followed by either `voting.ended` (normal close) or `poll.ending.cancelled` (countdown aborted). - After `voting.ended`, no further vote-related messages are sent until the next `poll.start`. - `game.started` implicitly deactivates any active poll — no explicit poll message is sent.