Files
jackboxpartypack-gamepicker/docs/api/guides/webhooks-and-events.md
cottongin 8ba32e128c docs: comprehensive API documentation from source code
Replace existing docs with fresh documentation built entirely from source
code analysis. OpenAPI 3.1 spec as source of truth, plus human-readable
Markdown with curl examples, response samples, and workflow guides.

- OpenAPI 3.1 spec covering all 42 endpoints (validated against source)
- 7 endpoint reference docs (auth, games, sessions, picker, stats, votes, webhooks)
- WebSocket protocol documentation (auth, subscriptions, 4 event types)
- 4 guide documents (getting started, session lifecycle, voting, webhooks)
- API README with overview, auth docs, and quick reference table
- Old docs archived to docs/archive/

Made-with: Cursor
2026-03-15 16:44:53 -04:00

217 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Webhooks and Events
A narrative guide to the Jackbox Game Picker event notification system: webhooks (HTTP callbacks) and WebSocket (persistent real-time connections). Both deliver event data about session and game activity.
---
## 1. Two Notification Systems
The API offers two complementary ways to receive event notifications:
| System | Model | Best for |
|--------|-------|----------|
| **Webhooks** | HTTP POST callbacks to your URL | Server-to-server, external integrations |
| **WebSocket** | Persistent bidirectional connection | Real-time UIs, dashboards, live tools |
Both systems emit the same kinds of events (e.g. `game.added`) but differ in how they deliver them.
---
## 2. When to Use Which
### Use Webhooks when:
- **Server-to-server** — Discord bots, Slack, logging pipelines, external APIs
- **Stateless** — Your endpoint receives a POST, processes it, and returns. No long-lived connection
- **Behind firewalls** — Your server can receive HTTP but may not hold open WebSocket connections
- **Async delivery** — Youre fine with HTTP round-trip latency and want delivery logged and auditable
### Use WebSocket when:
- **Real-time UI** — Dashboards, admin panels, live session viewers
- **Instant updates** — You need push-style notifications with minimal latency
- **Persistent connection** — Your app keeps a live connection and subscribes to specific sessions
- **Best-effort is fine** — WebSocket is push-only; theres no built-in delivery log for events
---
## 3. Webhook Setup
Webhooks are registered via the REST API. See [Webhooks endpoints](../endpoints/webhooks.md) for full CRUD details.
### Create a Webhook
`POST /api/webhooks` with:
- `name` — Display name (e.g. `"Discord Bot"`)
- `url` — Callback URL (must be a valid HTTP/HTTPS URL)
- `secret` — Shared secret for signing payloads (HMAC-SHA256)
- `events` — Array of event types that trigger this webhook (e.g. `["game.added"]`)
**Example:**
```bash
curl -X POST "http://localhost:5000/api/webhooks" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Discord Bot",
"url": "https://my-server.com/webhooks/jackbox",
"secret": "mysecret123",
"events": ["game.added"]
}'
```
The `events` array defines which events fire this webhook. Currently, the codebase triggers webhooks for **`game.added`** when a game is added to a session. The `triggerWebhook` function in `backend/utils/webhooks.js` is invoked from `sessions.js` on that event.
### Update, Enable/Disable, Delete
- **Update:** `PATCH /api/webhooks/{id}` — Change `name`, `url`, `secret`, `events`, or `enabled`
- **Disable:** `PATCH /api/webhooks/{id}` with `"enabled": false` — Stops delivery without deleting config
- **Delete:** `DELETE /api/webhooks/{id}` — Removes webhook and its logs
---
## 4. Webhook Delivery
### How it works
When an event occurs (e.g. a game is added), the server:
1. Finds all enabled webhooks subscribed to that event
2. Sends an async HTTP POST to each webhook URL
3. Logs each delivery attempt in `webhook_logs` (status, error, payload)
### Payload format
Each POST body is JSON:
```json
{
"event": "game.added",
"timestamp": "2026-03-15T20:30:00.000Z",
"data": {
"session": { "id": 3, "is_active": true, "games_played": 2 },
"game": {
"id": 42,
"title": "Quiplash 3",
"pack_name": "Jackbox Party Pack 7",
"min_players": 3,
"max_players": 8,
"manually_added": false
}
}
}
```
Headers include:
- `Content-Type: application/json`
- `X-Webhook-Event: game.added`
- `X-Webhook-Signature: sha256=<hmac>` — Use your `secret` to verify the payload
### View delivery logs
`GET /api/webhooks/{id}/logs` returns recent delivery attempts (status, error message, payload).
### Test a webhook
`POST /api/webhooks/test/{id}` sends a dummy `game.added` event to the webhook URL. Delivery runs asynchronously; check logs for status.
---
## 5. WebSocket Events
The WebSocket server runs at `/api/sessions/live` on the same host and port as the HTTP API. See [WebSocket protocol](../websocket.md) for connection, authentication, and subscription details.
### Event types and audience
| Event | Broadcast to | Triggered by |
|-------|--------------|--------------|
| `session.started` | All authenticated clients | `POST /api/sessions` |
| `game.added` | Session subscribers | `POST /api/sessions/{id}/games` |
| `session.ended` | Session subscribers | `POST /api/sessions/{id}/close` |
| `player-count.updated` | Session subscribers | `PATCH /api/sessions/{sessionId}/games/{sessionGameId}/player-count` |
`session.started` goes to every authenticated client. The others go only to clients that have subscribed to the relevant session via `{ "type": "subscribe", "sessionId": 3 }`.
### Envelope format
All events use this envelope:
```json
{
"type": "<event-type>",
"timestamp": "2026-03-15T20:30:00.000Z",
"data": { ... }
}
```
`data` contains event-specific fields (session, game, player count, etc.) as described in [WebSocket protocol](../websocket.md).
---
## 6. Comparison
| Feature | Webhooks | WebSocket |
|---------|----------|-----------|
| **Connection** | Stateless HTTP | Persistent |
| **Auth** | Secret in config | JWT per connection |
| **Events** | `game.added` | `session.started`, `game.added`, `session.ended`, `player-count.updated` |
| **Latency** | Higher (HTTP round trip) | Lower (push) |
| **Reliability** | Logged, auditable | Best-effort |
---
## 7. Example: Discord Bot
Use a webhook to post game additions to a Discord channel. Youll need:
1. A webhook created in the Game Picker API pointing to your server
2. A small server that receives the webhook and forwards to Discords Incoming Webhook
**Webhook receiver (Node.js):**
```javascript
const crypto = require('crypto');
app.post('/webhooks/jackbox', express.json(), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
// Verify HMAC-SHA256 using your webhook secret
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}
if (req.body.event === 'game.added') {
const { session, game } = req.body.data;
const discordPayload = {
content: `🎮 **${game.title}** added to session #${session.id} (${game.min_players}-${game.max_players} players)`
};
fetch(process.env.DISCORD_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(discordPayload)
}).catch(err => console.error('Discord post failed:', err));
}
res.status(200).send('OK');
});
```
Register the Game Picker webhook with your servers URL (e.g. `https://my-bot.example.com/webhooks/jackbox`), set `events` to `["game.added"]`, and use the same `secret` in your servers `WEBHOOK_SECRET`.
---
## Cross-references
- **[Webhooks endpoints](../endpoints/webhooks.md)** — Full CRUD, request/response schemas, errors
- **[WebSocket protocol](../websocket.md)** — Connection, auth, subscriptions, event payloads