Docs/Events
Webhooks
Outbound webhook event types, HTTP headers, payload schemas, and signature verification.
Specification
Socketo delivers outbound HTTP POST webhook requests to your backend endpoints when channel occupancy changes or client events occur, adhering to the Pusher Channels Webhook specification.
Supported Webhook Events
| Event | Trigger Condition | Payload Properties |
|---|---|---|
channel_occupied | First subscriber subscribes to channel | channel |
channel_vacated | Last remaining subscriber leaves channel | channel |
member_added | User joins a presence channel | channel, user_id |
member_removed | User vacates a presence channel | channel, user_id |
client_event | Client triggers a client-* event | channel, event, data, socket_id, user_id |
Request Headers
Every outbound webhook delivery includes the following headers:
| Header | Description |
|---|---|
Content-Type | Set to application/json. |
X-Pusher-Key | Public application key (app.id). |
X-Pusher-Signature | Hex-encoded HMAC-SHA256 hash of the raw HTTP request body signed with app_secret. |
Payload Schema
json
{
"time_ms": 1710000000000,
"events": [
{
"name": "channel_occupied",
"channel": "chat-room"
}
]
}Signature Verification
Compare the incoming X-Pusher-Signature header against an HMAC-SHA256 calculation of the raw, unmodified request body:
Node.js Example
ts
import crypto from 'node:crypto'
export function verifyWebhookSignature(
rawBody: string,
signatureHeader: string,
appSecret: string,
): boolean {
const expected = crypto
.createHmac('sha256', appSecret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected),
)
}Official SDK Verification
Official Pusher server SDKs verify webhooks directly:
ts
import Pusher from 'pusher'
const webhook = pusher.webhook({
headers: Object.fromEntries(request.headers),
rawBody: await request.text(),
})
if (!webhook.isValid()) {
return new Response('Invalid signature', { status: 401 })
}
for (const event of webhook.getEvents()) {
console.log(`Event: ${event.name} on ${event.channel}`)
}