EventSub
Webhook helpers and a WebSocket client for Twitch EventSub, with signature verification and session keepalive.
Choose webhook helpers or the WebSocket client depending on your delivery transport. Both approaches keep sessions healthy and verify Twitch signatures.
Webhook handler
import { handleEventSubWebhook } from "velho";
import { z } from "zod";
const cheerSchema = z.object({
broadcaster_user_id: z.string(),
is_anonymous: z.boolean(),
bits: z.number(),
});
export async function twitchWebhookHandler(req, res) {
const body = await getRawBody(req);
const result = await handleEventSubWebhook(
{
headers: req.headers,
body,
},
{
secret: process.env.TWITCH_EVENTSUB_SECRET!,
eventSchema: cheerSchema,
onNotification: async ({ subscription, event }) => {
console.log(subscription.type, event.bits);
},
onRevocation: ({ subscription }) => {
console.warn("Revoked:", subscription);
},
}
);
res.writeHead(result.status, result.headers);
res.end(result.body);
}- Framework agnostic: provide raw headers and request body.
- Signature verification uses HMAC-SHA256 with constant-time comparison.
- Automatic response to
webhook_callback_verificationchallenges.
WebSocket client
import { EventSubWebSocketClient } from "velho";
const wsClient = new EventSubWebSocketClient({ autoReconnect: true });
await wsClient.connect();
wsClient.on("connected", (session) => {
console.log("Session ID", session.id);
});
wsClient.on("notification", ({ subscription, event }) => {
console.log(subscription.type, event);
});- Keeps sessions alive and honors Twitch reconnect instructions.
- Resets keepalive timers to detect silent disconnects.
- Pair with the Helix client to create subscriptions using the active session ID.