WebSockets
Real-time WebSocket connections for live event streaming and inbound sources.
hookstream provides three WebSocket endpoints for real-time communication. All connections use Cloudflare Durable Objects with the Hibernatable WebSocket API — efficient, stateful connections that survive idle periods without cost.
WebSocket upgrades cannot use custom request headers in browsers, so API keys are passed via the token query parameter instead of X-API-Key. Browser clients signed in to the dashboard use session cookies automatically.
Dashboard Stream
GET /v1/ws
Upgrade to authenticated WebSocket for real-time organization-wide event streaming. After connecting, you receive real-time events for your organization across all sources and destinations. Messages are JSON with a channel field for filtering (e.g., events, deliveries, issues).
Authentication: API key via token query param, or session cookie.
Query Parameters
API key for authentication. Browser clients with an active session cookie can omit this.
js// Uses session cookie automatically const ws = new WebSocket("wss://hookstream.io/v1/ws"); ws.addEventListener("message", (event) => { const msg = JSON.parse(event.data); console.log(msg.channel, msg.data); });
jsimport WebSocket from "ws"; const ws = new WebSocket( `wss://hookstream.io/v1/ws?token=${process.env.HOOKSTREAM_API_KEY}` ); ws.on("message", (raw) => { const msg = JSON.parse(raw.toString()); console.log(msg.channel, msg.data); });
bashhookstream listen
See hookstream listen for filtering and formatting options.
json{ "type": "event", "channel": "events", "data": { "id": "evt_d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9", "source_id": "src_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", "method": "POST", "status": "delivered", "received_at": "2026-03-01T14:30:00Z" } }
Test Session Stream
GET /v1/ws/test/:source_id
Upgrade to unauthenticated WebSocket for a test session's real-time event feed. Used by the browser-based test inspector.
Authentication: None. Validates the source is an ephemeral test session.
jsconst sessionId = "a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8"; const ws = new WebSocket(`wss://hookstream.io/v1/ws/test/${sessionId}`); ws.addEventListener("message", (event) => { const msg = JSON.parse(event.data); if (msg.type === "event") { console.log("New webhook:", msg.data); } });
json{ "type": "event", "channel": "test", "data": { "id": "evt_001", "method": "POST", "body": { "test": true }, "received_at": "2026-03-01T12:05:00Z" } }
Inbound WebSocket Source
GET /v1/ws/source/:source_id
Upgrade to authenticated WebSocket for inbound event ingestion. Instead of receiving HTTP webhooks, you can send events over a persistent WebSocket connection. Each message sent on this connection is ingested as an event and routed through the normal delivery pipeline. Useful for high-throughput or bidirectional scenarios.
Authentication: API key via token query param.
Query Parameters
API key for authentication.
jsimport WebSocket from "ws"; const ws = new WebSocket( `wss://hookstream.io/v1/ws/source/src_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6?token=${process.env.HOOKSTREAM_API_KEY}` ); ws.on("open", () => { ws.send(JSON.stringify({ type: "order.created", data: { id: "ord_123", amount: 4999 }, })); }); ws.on("message", (raw) => { const ack = JSON.parse(raw.toString()); console.log("Event ID:", ack.event_id); });
json{ "type": "order.created", "data": { "id": "ord_123", "amount": 4999 } }
json{ "type": "ack", "event_id": "evt_d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9" }
Message format
All WebSocket messages are JSON objects with a type field indicating the message kind.
Server → client:
| Type | Meaning |
|---|---|
event | New event received at a source. |
delivery | Delivery attempt completed. |
issue | Issue created or updated. |
sync | Database collection record synced. |
ping | Heartbeat — respond with pong. |
Client → server:
| Type | Meaning |
|---|---|
subscribe | Subscribe to a specific channel. |
pong | Heartbeat response. |