Files
jackboxpartypack-gamepicker/docs/archive/API_QUICK_REFERENCE.md
cottongin 0d0d20161b docs: update remaining docs with vote tracking API changes
Update README.md, docs/api/README.md, session-lifecycle guide,
webhooks-and-events guide, and archive docs (BOT_INTEGRATION,
API_QUICK_REFERENCE) with new endpoints and vote.received event.

Made-with: Cursor
2026-03-15 19:21:35 -04:00

515 lines
9.0 KiB
Markdown

# API Quick Reference
Quick reference for Live Voting, WebSocket, and Webhook endpoints.
## Base URL
```
http://localhost:5000/api
```
## Authentication
All endpoints require JWT authentication:
```
Authorization: Bearer YOUR_JWT_TOKEN
```
Get token via:
```bash
POST /api/auth/login
Body: { "key": "YOUR_ADMIN_KEY" }
```
---
## WebSocket Events
### Connect to WebSocket
```
ws://localhost:5000/api/sessions/live
```
**Message Protocol**:
```json
// Authenticate
{ "type": "auth", "token": "YOUR_JWT_TOKEN" }
// Subscribe to session
{ "type": "subscribe", "sessionId": 123 }
// Unsubscribe
{ "type": "unsubscribe", "sessionId": 123 }
// Heartbeat
{ "type": "ping" }
```
**Server Events**:
```json
// Auth success
{ "type": "auth_success", "message": "..." }
// Subscribed
{ "type": "subscribed", "sessionId": 123 }
// Session started
{
"type": "session.started",
"timestamp": "2025-11-01T...",
"data": {
"session": { "id": 123, "is_active": 1, "created_at": "...", "notes": "..." }
}
}
// Game added
{
"type": "game.added",
"timestamp": "2025-11-01T...",
"data": {
"session": { "id": 123, "is_active": true, "games_played": 5 },
"game": { "id": 45, "title": "Fibbage 4", ... }
}
}
// Session ended
{
"type": "session.ended",
"timestamp": "2025-11-01T...",
"data": {
"session": { "id": 123, "is_active": 0, "games_played": 5 }
}
}
// Vote received (live votes only, not chat-import)
{
"type": "vote.received",
"timestamp": "2025-11-01T...",
"data": {
"sessionId": 123,
"game": { "id": 42, "title": "Quiplash 3", "pack_name": "Party Pack 7" },
"vote": { "username": "viewer123", "type": "up", "timestamp": "2025-11-01T20:30:00Z" },
"totals": { "upvotes": 14, "downvotes": 3, "popularity_score": 11 }
}
}
// Pong
{ "type": "pong" }
```
---
## Votes
### Get Vote History
```http
GET /api/votes?session_id=5&game_id=42&username=viewer123&vote_type=up&page=1&limit=50
```
**Response (200)**:
```json
{
"votes": [
{
"id": 891,
"session_id": 5,
"game_id": 42,
"game_title": "Quiplash 3",
"pack_name": "Party Pack 7",
"username": "viewer123",
"vote_type": "up",
"timestamp": "2025-11-01T20:30:00.000Z",
"created_at": "2025-11-01T20:30:01.000Z"
}
],
"pagination": { "page": 1, "limit": 50, "total": 237, "total_pages": 5 }
}
```
All query parameters are optional. No authentication required.
### Submit Live Vote
```http
POST /api/votes/live
```
**Request Body**:
```json
{
"username": "string",
"vote": "up" | "down",
"timestamp": "2025-11-01T20:30:00Z"
}
```
**Success Response (200)**:
```json
{
"success": true,
"message": "Vote recorded successfully",
"session": { "id": 123, "games_played": 5 },
"game": {
"id": 45,
"title": "Fibbage 4",
"upvotes": 46,
"downvotes": 3,
"popularity_score": 43
},
"vote": {
"username": "TestUser",
"type": "up",
"timestamp": "2025-11-01T20:30:00Z"
}
}
```
**Error Responses**:
- `400` - Invalid payload
- `404` - No active session or timestamp doesn't match any game
- `409` - Duplicate vote (within 1 second)
---
## Webhooks
### List Webhooks
```http
GET /api/webhooks
```
**Response**:
```json
[
{
"id": 1,
"name": "Kosmi Bot",
"url": "http://bot-url/webhook",
"events": ["game.added"],
"enabled": true,
"created_at": "2025-11-01T20:00:00Z"
}
]
```
### Get Single Webhook
```http
GET /api/webhooks/:id
```
### Create Webhook
```http
POST /api/webhooks
```
**Request Body**:
```json
{
"name": "Kosmi Bot",
"url": "http://bot-url/webhook",
"secret": "your_shared_secret",
"events": ["game.added"]
}
```
**Response (201)**:
```json
{
"id": 1,
"name": "Kosmi Bot",
"url": "http://bot-url/webhook",
"events": ["game.added"],
"enabled": true,
"created_at": "2025-11-01T20:00:00Z",
"message": "Webhook created successfully"
}
```
### Update Webhook
```http
PATCH /api/webhooks/:id
```
**Request Body** (all fields optional):
```json
{
"name": "Updated Name",
"url": "http://new-url/webhook",
"secret": "new_secret",
"events": ["game.added"],
"enabled": false
}
```
### Delete Webhook
```http
DELETE /api/webhooks/:id
```
**Response (200)**:
```json
{
"message": "Webhook deleted successfully",
"webhookId": 1
}
```
### Test Webhook
```http
POST /api/webhooks/test/:id
```
Sends a test `game.added` event to verify webhook is working.
**Response (200)**:
```json
{
"message": "Test webhook sent",
"note": "Check webhook_logs table for delivery status"
}
```
### Get Webhook Logs
```http
GET /api/webhooks/:id/logs?limit=50
```
**Response**:
```json
[
{
"id": 1,
"webhook_id": 1,
"event_type": "game.added",
"payload": { /* full payload */ },
"response_status": 200,
"error_message": null,
"created_at": "2025-11-01T20:30:00Z"
}
]
```
---
## Webhook Payloads
### Event: `session.started`
Sent when a new session is created.
**Headers**:
- `Content-Type: application/json`
- `X-Webhook-Signature: sha256=<hmac_signature>`
- `X-Webhook-Event: session.started`
- `User-Agent: Jackbox-Game-Picker-Webhook/1.0`
**Payload**:
```json
{
"event": "session.started",
"timestamp": "2025-11-01T20:00:00Z",
"data": {
"session": {
"id": 123,
"is_active": 1,
"created_at": "2025-11-01T20:00:00Z",
"notes": "Friday Game Night"
}
}
}
```
### Event: `game.added`
Sent when a game is added to an active session.
**Headers**:
- `Content-Type: application/json`
- `X-Webhook-Signature: sha256=<hmac_signature>`
- `X-Webhook-Event: game.added`
- `User-Agent: Jackbox-Game-Picker-Webhook/1.0`
**Payload**:
```json
{
"event": "game.added",
"timestamp": "2025-11-01T20:30:00Z",
"data": {
"session": {
"id": 123,
"is_active": true,
"games_played": 5
},
"game": {
"id": 45,
"title": "Fibbage 4",
"pack_name": "The Jackbox Party Pack 9",
"min_players": 2,
"max_players": 8,
"manually_added": false
}
}
}
```
### Event: `session.ended`
Sent when a session is closed/ended.
**Headers**:
- `Content-Type: application/json`
- `X-Webhook-Signature: sha256=<hmac_signature>`
- `X-Webhook-Event: session.ended`
- `User-Agent: Jackbox-Game-Picker-Webhook/1.0`
**Payload**:
```json
{
"event": "session.ended",
"timestamp": "2025-11-01T20:30:00Z",
"data": {
"session": {
"id": 123,
"is_active": 0,
"games_played": 5
}
}
}
```
---
## cURL Examples
### Submit Vote
```bash
curl -X POST "http://localhost:5000/api/votes/live" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "TestUser",
"vote": "up",
"timestamp": "2025-11-01T20:30:00Z"
}'
```
### Create Webhook
```bash
curl -X POST "http://localhost:5000/api/webhooks" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Kosmi Bot",
"url": "http://localhost:3001/webhook/jackbox",
"secret": "test_secret_123",
"events": ["game.added"]
}'
```
### Test Webhook
```bash
curl -X POST "http://localhost:5000/api/webhooks/test/1" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
### View Webhook Logs
```bash
curl -X GET "http://localhost:5000/api/webhooks/1/logs?limit=10" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"
```
---
## Webhook Signature Verification
**Node.js Example**:
```javascript
const crypto = require('crypto');
function verifyWebhookSignature(signature, payload, secret) {
if (!signature || !signature.startsWith('sha256=')) {
return false;
}
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook endpoint:
app.post('/webhook/jackbox', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = process.env.WEBHOOK_SECRET;
if (!verifyWebhookSignature(signature, req.body, secret)) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
res.status(200).send('OK');
});
```
---
## Error Codes
| Code | Meaning |
|------|---------|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request - Invalid payload |
| 401 | Unauthorized - Invalid JWT or signature |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Duplicate vote |
| 500 | Internal Server Error |
---
## Rate Limiting
Currently no rate limiting is implemented. Consider implementing rate limiting in production:
- Per IP address
- Per JWT token
- Per webhook endpoint
---
## Best Practices
1. **Always verify webhook signatures** before processing
2. **Use HTTPS** for webhook URLs in production
3. **Store secrets securely** in environment variables
4. **Respond quickly** to webhooks (< 5 seconds)
5. **Log webhook activity** for debugging
6. **Handle retries gracefully** if implementing retry logic
7. **Validate timestamps** to prevent replay attacks
---
For detailed documentation, see [BOT_INTEGRATION.md](BOT_INTEGRATION.md)