Files
cottongin 3ed3af06ba docs: add vote tracking endpoints to API documentation
Update REST endpoint docs (votes.md, sessions.md), WebSocket protocol
(websocket.md), OpenAPI spec, and voting guide with the new
GET /api/votes, GET /api/sessions/:id/votes, and vote.received event.

Made-with: Cursor
2026-03-15 19:16:23 -04:00

4.8 KiB

Votes Endpoints

Real-time popularity voting. Bots or integrations send votes during live gaming sessions. Votes are matched to the currently-playing game using timestamp intervals.

Endpoint Summary

Method Path Auth Description
GET /api/votes None Paginated vote history with filtering
POST /api/votes/live Bearer Submit a live vote (up/down)

GET /api/votes

Paginated vote history with filtering. Use query parameters to filter by session, game, username, or vote type.

Authentication

None.

Query Parameters

Parameter Type Required Default Description
session_id int No Filter by session ID
game_id int No Filter by game ID
username string No Filter by voter username
vote_type string No "up" or "down"
page int No 1 Page number
limit int No 50 Items per page (max 100)

Response

200 OK

Results are ordered by timestamp DESC. The vote_type field is returned as "up" or "down" (not raw integers).

{
  "votes": [
    {
      "id": 891,
      "session_id": 5,
      "game_id": 42,
      "game_title": "Quiplash 3",
      "pack_name": "Party Pack 7",
      "username": "viewer123",
      "vote_type": "up",
      "timestamp": "2026-03-15T20:29:55.000Z",
      "created_at": "2026-03-15T20:29:56.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 237,
    "total_pages": 5
  }
}

Error Responses

Status Body When
400 { "error": "..." } Invalid session_id, game_id, or vote_type
200 { "votes": [], "pagination": { "page": 1, "limit": 50, "total": 0, "total_pages": 0 } } No results match the filters

POST /api/votes/live

Submit a real-time up/down vote for the game currently being played. Automatically finds the active session and matches the vote to the correct game using the provided timestamp and session game intervals.

Authentication

Bearer token required. Include in header: Authorization: Bearer <token>.

Request Body

Field Type Required Description
username string Yes Identifier for the voter (used for deduplication)
vote string Yes "up" or "down"
timestamp string Yes ISO 8601 timestamp when the vote occurred
{
  "username": "viewer123",
  "vote": "up",
  "timestamp": "2026-03-15T20:30:00Z"
}

Behavior

  • Finds the active session (single session with is_active = 1).
  • Matches the vote timestamp to the game being played at that time (uses interval between consecutive played_at timestamps).
  • Updates game upvotes, downvotes, and popularity_score atomically in a transaction.
  • Deduplication: Rejects votes from the same username within a 1-second window (409 Conflict).
  • Broadcasts a vote.received WebSocket event to all clients subscribed to the active session. See WebSocket Protocol for event payload.

Response

200 OK

{
  "success": true,
  "message": "Vote recorded successfully",
  "session": { "id": 3, "games_played": 5 },
  "game": {
    "id": 42,
    "title": "Quiplash 3",
    "upvotes": 11,
    "downvotes": 2,
    "popularity_score": 9
  },
  "vote": {
    "username": "viewer123",
    "type": "up",
    "timestamp": "2026-03-15T20:30:00Z"
  }
}

Error Responses

Status Body When
400 { "error": "Missing required fields: username, vote, timestamp" } Missing required fields
400 { "error": "vote must be either \"up\" or \"down\"" } Invalid vote value
400 { "error": "Invalid timestamp format. Use ISO 8601 format (e.g., 2025-11-01T20:30:00Z)" } Invalid timestamp
404 { "error": "No active session found" } No session with is_active = 1
404 { "error": "No games have been played in the active session yet" } Active session has no games
404 { "error": "Vote timestamp does not match any game in the active session", "debug": { "voteTimestamp": "2026-03-15T20:30:00Z", "sessionGames": [{ "title": "Quiplash 3", "played_at": "..." }] } } Timestamp outside any game interval
409 { "error": "Duplicate vote detected (within 1 second of previous vote)", "message": "Please wait at least 1 second between votes", "timeSinceLastVote": 0.5 } Same username voted within 1 second
500 { "error": "..." } Server error

Example

curl -X POST "http://localhost:5000/api/votes/live" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "viewer123",
    "vote": "up",
    "timestamp": "2026-03-15T20:30:00Z"
  }'