baileys-webhooks
v0.1.0
Published
Drop-in webhook dispatcher for Baileys WhatsApp bots with HMAC signing, retries, and timeout handling
Maintainers
Readme
baileys-webhooks
Drop-in webhook dispatcher for Baileys WhatsApp bots. HMAC-signed, retried, timeout-bounded. Free your bot logic from boilerplate.
Why
Every Baileys deployment reinvents webhook forwarding — dispatching messages.upsert, connection.update, groups.update, and other events to HTTP endpoints. Most implementations lack retry logic, signature verification, or timeout handling.
baileys-webhooks solves this with a clean, production-ready dispatcher that wraps your Baileys socket and handles the heavy lifting.
Features
- HMAC-SHA256 signed payloads — receivers verify authenticity
- Exponential backoff retry — configurable attempts, delays, and factors
- Timeout-bounded requests — uses AbortController to prevent hanging
- Event filtering — wildcard
*or specific event arrays per endpoint - Multiple endpoints — dispatch to N receivers in parallel
- Fire-and-forget async — doesn't block Baileys event loop
- TypeScript strict mode — full type safety
Install
npm install baileys-webhooksRequires @whiskeysockets/baileys as a peer dependency (v6.0.0+).
Quick Start
import makeWASocket from '@whiskeysockets/baileys'
import { wrapWithWebhooks } from 'baileys-webhooks'
const sock = makeWASocket({ /* your config */ })
const dispatcher = wrapWithWebhooks(sock, {
endpoints: [
{
url: 'https://api.example.com/wa-events',
secret: 'your-webhook-secret',
events: ['messages.upsert', 'groups.update']
},
{
url: 'https://other.example.com/all',
secret: 'another-secret',
events: '*' // All supported events
}
],
retry: { maxAttempts: 3, backoffMs: 500, factor: 2 },
timeout: 10_000,
filter: (event, payload) => true, // Optional pre-dispatch filter
onError: (err, ctx) => {
console.error(`Webhook failed: ${ctx.endpoint.url}`, err)
}
})
// Dispatcher is now active and forwarding eventsEndpoint Configuration
Each endpoint supports:
{
url: string // HTTP endpoint URL
secret: string // HMAC signing secret
events: string[] | '*' // Event filter (wildcard or specific events)
retry?: { // Optional per-endpoint retry override
maxAttempts: number
backoffMs: number
factor: number
}
}Supported Events
messages.upsertmessages.updateconnection.updategroups.updategroups.upsertgroup-participants.updatepresence.updatechats.updatecontacts.updatemessage-receipt.updatecreds.update
Use events: '*' to receive all events.
Webhook Payload
Each POST request contains:
{
"event": "messages.upsert",
"data": { /* Baileys event data */ },
"timestamp": 1672531200000,
"instanceId": "optional-instance-id"
}Headers:
Content-Type: application/jsonX-Baileys-Signature: <hmac-sha256-hex>
Signature Verification
Node.js (Express)
import { verifySignature } from 'baileys-webhooks'
app.post('/webhook', (req, res) => {
const signature = req.headers['x-baileys-signature']
const body = JSON.stringify(req.body)
if (!verifySignature('your-secret', body, signature)) {
return res.status(401).send('Invalid signature')
}
// Process webhook
console.log('Event:', req.body.event)
res.sendStatus(200)
})Python (Flask)
import hmac
import hashlib
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Baileys-Signature')
body = request.get_data()
secret = b'your-secret'
expected = hmac.new(secret, body, hashlib.sha256).hexdigest()
if signature != expected:
return 'Invalid signature', 401
data = request.json
print(f"Event: {data['event']}")
return '', 200Composes with baileys-antiban
Combine with rate limiting and anti-ban protection:
import { wrapWithAntiban } from 'baileys-antiban'
import { wrapWithWebhooks } from 'baileys-webhooks'
const sock = makeWASocket({ /* ... */ })
wrapWithAntiban(sock, { /* rate limit config */ })
const dispatcher = wrapWithWebhooks(sock, { /* webhook config */ })API
wrapWithWebhooks(sock, config)
Wraps a Baileys socket with webhook dispatching.
Returns: WebhookDispatcher
dispatcher.addEndpoint(config)
Dynamically add a new endpoint.
dispatcher.removeEndpoint(url)
Remove an endpoint by URL.
dispatcher.stop()
Detach all listeners and stop dispatching.
Roadmap
- v0.2: BullMQ adapter for Redis-backed queueing (production-grade)
- Receipt mode: Only mark delivered if receiver returns 200
- Batch mode: Aggregate events and POST in batches
- Dead-letter queue: Persist failed webhooks for manual replay
License
MIT © Kobus Wentzel
Contributing
PRs welcome! This library aims to stay small, focused, and dependency-light.
