npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

whatshub-client

v1.2.0

Published

Official Node.js client library for WhatsHub - Universal WhatsApp Gateway API with SSE and Webhook support

Readme

whatshub-client

Official Node.js client library for WhatsHub - Universal WhatsApp Gateway API

npm version License: MIT

Features

Easy to use - Simple, intuitive API ✅ TypeScript support - Full type definitions included ✅ Two delivery modes - SSE (persistent servers) or Webhooks (Firebase Functions, serverless) ✅ Real-time messages - Built-in SSE (Server-Sent Events) handling ✅ Webhook support - Perfect for Firebase Functions, AWS Lambda, serverless ✅ Auto-reconnect - Automatic event stream reconnection ✅ Event-driven - EventEmitter-based for reactive programming ✅ Media support - Send images, videos, audio, documents ✅ Auto image optimization - Images over 1MB automatically compressed ✅ Group messaging - Get and message WhatsApp groups ✅ Promise-based - Modern async/await API ✅ HMAC security - Built-in webhook signature verification

Installation

npm install whatshub-client

Quick Start

const WhatsHubClient = require('@phiresky/whatshub-client');

// Create client
const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: 'wh_live_your_api_key_here',
  sessionId: 'my-company-support'
});

// Create session and connect
await client.createSession();

// Listen for QR code
client.on('qr', (qrCode) => {
  console.log('Scan this QR code with WhatsApp:', qrCode);
});

// Listen for connection
client.on('ready', (data) => {
  console.log('WhatsApp connected!', data.phoneNumber);
});

// Listen for messages
client.on('message', (message) => {
  console.log('New message from:', message.chatId);
  console.log('Text:', message.text);
});

// Connect to real-time stream
client.connectSSE();

// Send a message
await client.sendMessage('+27763724011', 'Hello from WhatsHub!');

Configuration

Client Options

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',  // Required
  apiKey: 'wh_live_xxxxx',                               // Required
  sessionId: 'my-session',                               // Optional
  autoConnect: false,                                     // Optional
  debug: false,                                           // Optional
  webhookUrl: 'https://your-app.com/webhook',           // Optional (for Firebase Functions)
  webhookSecret: 'your-secret-123'                       // Optional (for webhook verification)
});

| Option | Type | Required | Description | |--------|------|----------|-------------| | hubUrl | string | ✅ Yes | WhatsHub server URL | | apiKey | string | ✅ Yes | Your WhatsHub API key | | sessionId | string | ❌ No | Session ID (auto-generated if not provided) | | autoConnect | boolean | ❌ No | Auto-connect SSE on init (default: false) | | debug | boolean | ❌ No | Enable debug logging (default: false) | | webhookUrl | string | ❌ No | Webhook URL for message delivery (Firebase Functions, serverless) | | webhookSecret | string | ❌ No | Secret for HMAC signature verification |

API Reference

Sessions

createSession(options)

Create a new WhatsApp session

await client.createSession({
  sessionId: 'my-session',           // Optional
  syncContacts: ['+27763724011'],    // Optional
  syncHistory: false                 // Optional (default: false)
});

Returns: Promise<{sessionId: string}>

getQRCode(sessionId)

Get QR code for WhatsApp authentication

const { qrCode } = await client.getQRCode();
// qrCode is a data URL: "data:image/png;base64,..."

Returns: Promise<{qrCode: string}>

getStatus(sessionId)

Get session connection status

const status = await client.getStatus();
console.log(status.connected);      // true/false
console.log(status.phoneNumber);    // "+27815665778"

Returns: Promise<SessionStatus>

getUserStatus()

Get overall user status (all sessions)

const status = await client.getUserStatus();
console.log(status.hasActiveConnection);  // true/false
console.log(status.connectedSessions);    // 2
console.log(status.sessions);             // [...]

Returns: Promise<UserStatus>

deleteSession(sessionId)

Delete session (logout from WhatsApp)

await client.deleteSession();

Returns: Promise<void>

Messaging

sendMessage(to, message, sessionId)

Send a text message

const result = await client.sendMessage('+27763724011', 'Hello!');
console.log(result.messageId);

Parameters:

  • to (string): Phone number (+27763724011) or group ID
  • message (string): Text message content
  • sessionId (string, optional): Session ID

Returns: Promise<{success: boolean, messageId: string}>

sendMedia(to, media, caption, sessionId)

Send media message (image, video, audio, document)

// From URL
await client.sendMedia('+27763724011', {
  url: 'https://example.com/image.jpg',
  mimetype: 'image/jpeg',
  filename: 'photo.jpg'
}, 'Check this out!');

// From Base64
await client.sendMedia('+27763724011', {
  base64: 'iVBORw0KGgoAAAANS...',
  mimetype: 'image/png',
  filename: 'screenshot.png'
}, 'Screenshot attached');

Parameters:

  • to (string): Phone number or group ID
  • media (object): Media object with url or base64, mimetype, filename
  • caption (string, optional): Media caption
  • sessionId (string, optional): Session ID

Returns: Promise<{success: boolean, messageId: string}>

getMessages(options, sessionId)

Get message history

const messages = await client.getMessages({
  contact: '+27763724011',  // Optional: filter by contact
  from: '2025-11-01',       // Optional: start date
  to: '2025-11-03',         // Optional: end date
  limit: 100                // Optional: max messages (default: 100)
});

Returns: Promise<Message[]>

Groups

getGroups(sessionId)

Get list of WhatsApp groups

const groups = await client.getGroups();

groups.forEach(group => {
  console.log(group.id);          // "[email protected]"
  console.log(group.subject);     // "Family Group"
  console.log(group.participants); // 15
});

Returns: Promise<WhatsAppGroup[]>

Real-Time Events (SSE)

connectSSE(sessionId)

Connect to Server-Sent Events stream for real-time updates

client.connectSSE();

disconnectSSE()

Disconnect from SSE stream

client.disconnectSSE();

Events

The client extends EventEmitter and emits the following events:

Connection Events

qr

QR code available for scanning

client.on('qr', (qrCode, data) => {
  console.log('QR Code:', qrCode);  // data URL
});

ready / connected

WhatsApp connected and authenticated

client.on('ready', (data) => {
  console.log('Connected!', data.phoneNumber);
});

disconnected

WhatsApp disconnected

client.on('disconnected', (data) => {
  console.log('Disconnected:', data.reason);
  console.log('Will reconnect:', data.shouldReconnect);
});

conflict

Multiple devices connected (action required)

client.on('conflict', (data) => {
  console.error('Conflict detected:', data.reason);
  // Log out of other WhatsApp Web/Desktop sessions
});

Message Events

message

New incoming message

client.on('message', (message) => {
  console.log('From:', message.chatId);
  console.log('Text:', message.text);
  console.log('Has media:', message.hasMedia);

  // Auto-reply example
  if (message.text.toLowerCase().includes('help')) {
    client.sendMessage(message.chatId, 'How can I help you?');
  }
});

message-sent

Message successfully sent

client.on('message-sent', (data) => {
  console.log('Message sent to:', data.to);
  console.log('Message ID:', data.messageId);
});

Other Events

heartbeat

Keep-alive ping (every 30 seconds)

client.on('heartbeat', (data) => {
  console.log('Heartbeat:', data.timestamp);
});

error

Error occurred

client.on('error', (error) => {
  console.error('Error:', error);
});

Complete Examples

Example 1: Basic Bot

const WhatsHubClient = require('@phiresky/whatshub-client');

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: 'support-bot',
  debug: true
});

async function main() {
  // Create session
  await client.createSession();

  // Handle QR code
  client.on('qr', (qrCode) => {
    console.log('Please scan this QR code with WhatsApp');
    // Display QR code or save to file
  });

  // Handle connection
  client.on('ready', async (data) => {
    console.log('✅ WhatsApp connected!', data.phoneNumber);

    // Send startup notification
    await client.sendMessage('+27763724011', 'Bot is now online! 🤖');
  });

  // Handle incoming messages
  client.on('message', async (message) => {
    // Ignore messages from self
    if (message.fromMe) return;

    console.log(`Message from ${message.chatId}: ${message.text}`);

    // Simple command handling
    if (message.text === '/help') {
      await client.sendMessage(message.chatId,
        'Available commands:\n/help - Show this message\n/status - Check bot status');
    }
    else if (message.text === '/status') {
      const status = await client.getUserStatus();
      await client.sendMessage(message.chatId,
        `Bot Status:\nConnected: ${status.hasActiveConnection}\nSessions: ${status.totalSessions}`);
    }
    else {
      await client.sendMessage(message.chatId,
        'Thanks for your message! Type /help for available commands.');
    }
  });

  // Handle disconnection
  client.on('disconnected', (data) => {
    console.log('Disconnected:', data.reason);
    if (data.shouldReconnect) {
      console.log('Will attempt to reconnect...');
    }
  });

  // Connect to real-time stream
  client.connectSSE();
}

main().catch(console.error);

Example 2: Send Bulk Messages

const WhatsHubClient = require('@phiresky/whatshub-client');

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: 'bulk-sender'
});

async function sendBulkMessages() {
  // Wait for connection
  await client.createSession();

  // Get status to ensure connected
  const status = await client.getStatus();
  if (!status.connected) {
    console.log('Not connected. Please scan QR code first.');
    return;
  }

  const contacts = [
    '+27763724011',
    '+27815665778',
    // ... more contacts
  ];

  const message = 'Hello! This is a bulk message from our system.';

  for (const contact of contacts) {
    try {
      await client.sendMessage(contact, message);
      console.log(`✅ Sent to ${contact}`);

      // Rate limiting: ~40-60 messages/minute
      await new Promise(resolve => setTimeout(resolve, 1500));
    } catch (error) {
      console.error(`❌ Failed to send to ${contact}:`, error.message);
    }
  }

  console.log('Bulk send complete!');
}

sendBulkMessages().catch(console.error);

Example 3: Send Media

const WhatsHubClient = require('@phiresky/whatshub-client');
const fs = require('fs');

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: 'media-sender'
});

async function sendImage() {
  // From URL
  await client.sendMedia('+27763724011', {
    url: 'https://example.com/promo.jpg',
    mimetype: 'image/jpeg',
    filename: 'promo.jpg'
  }, '🎉 Special offer just for you!');

  // From local file (base64)
  const imageBuffer = fs.readFileSync('./image.png');
  const base64Image = imageBuffer.toString('base64');

  await client.sendMedia('+27763724011', {
    base64: base64Image,
    mimetype: 'image/png',
    filename: 'image.png'
  }, 'Check out this screenshot!');
}

sendImage().catch(console.error);

Example 4: Group Messaging

const WhatsHubClient = require('@phiresky/whatshub-client');

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: 'group-bot'
});

async function sendToGroup() {
  // Get all groups
  const groups = await client.getGroups();

  console.log(`Found ${groups.length} groups`);

  // Find specific group
  const targetGroup = groups.find(g =>
    g.subject.toLowerCase().includes('team')
  );

  if (targetGroup) {
    await client.sendMessage(targetGroup.id,
      '📢 Team announcement: Meeting at 3 PM today!');
    console.log(`Message sent to group: ${targetGroup.subject}`);
  }
}

sendToGroup().catch(console.error);

Webhook Integration (Firebase Functions, Serverless)

For stateless environments like Firebase Functions or AWS Lambda, use webhook mode:

Setup with Webhooks

const functions = require('firebase-functions');
const WhatsHubClient = require('whatshub-client');

// Webhook endpoint - receives messages from WhatsHub
exports.whatsappWebhook = functions.https.onRequest(async (req, res) => {
  if (req.method !== 'POST') {
    return res.status(405).send('Method Not Allowed');
  }

  // 1. Verify HMAC signature (CRITICAL!)
  const signature = req.headers['x-whatshub-signature'];
  const secret = functions.config().whatsapp.webhook_secret;

  try {
    const isValid = WhatsHubClient.verifyWebhookSignature(
      req.body,
      signature,
      secret
    );

    if (!isValid) {
      return res.status(401).send('Unauthorized');
    }
  } catch (error) {
    return res.status(400).send('Invalid signature');
  }

  // 2. Parse message
  const message = WhatsHubClient.parseWebhookPayload(req.body);

  console.log('Received:', message.text);

  // 3. Process message (your logic here)
  // ...

  // 4. Respond quickly (5s timeout)
  res.status(200).send('OK');
});

// Setup function - call once to create session
exports.setupWhatsApp = functions.https.onRequest(async (req, res) => {
  const client = new WhatsHubClient({
    hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
    apiKey: functions.config().whatsapp.api_key
  });

  const webhookUrl = `https://us-central1-${process.env.GCLOUD_PROJECT}.cloudfunctions.net/whatsappWebhook`;

  await client.createSession({
    sessionId: 'my-session',
    webhookUrl: webhookUrl,
    webhookSecret: functions.config().whatsapp.webhook_secret
  });

  const { qrCode } = await client.getQRCode('my-session');

  res.json({ message: 'Scan QR code', qrCode });
});

Deploy to Firebase

# Set config
firebase functions:config:set \
  whatsapp.api_key="wh_live_your_key" \
  whatsapp.webhook_secret="your-secret"

# Deploy
firebase deploy --only functions

# Setup (one-time)
curl https://us-central1-your-project.cloudfunctions.net/setupWhatsApp

Static Utility Methods

The client provides static methods for webhook handling:

WhatsHubClient.verifyWebhookSignature(body, signature, secret)

Verifies HMAC-SHA256 signature from WhatsHub webhooks:

const isValid = WhatsHubClient.verifyWebhookSignature(
  req.body,                            // Request body (object or string)
  req.headers['x-whatshub-signature'], // Signature header
  process.env.WEBHOOK_SECRET           // Your secret
);

if (!isValid) {
  throw new Error('Invalid signature');
}

WhatsHubClient.parseWebhookPayload(body)

Parses and validates webhook payload:

const message = WhatsHubClient.parseWebhookPayload(req.body);

console.log(message.chatId);    // "[email protected]"
console.log(message.text);      // "Hello!"
console.log(message.timestamp); // ISO date

TypeScript Usage

import WhatsHubClient, {
  WhatsHubClientOptions,
  MessageEvent
} from '@phiresky/whatshub-client';

const options: WhatsHubClientOptions = {
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY!,
  sessionId: 'my-session',
  debug: true
};

const client = new WhatsHubClient(options);

client.on('message', (message: MessageEvent) => {
  console.log('Message:', message.text);
});

await client.createSession();
client.connectSSE();

Error Handling

const client = new WhatsHubClient({
  hubUrl: 'https://uat.phiresky.com/api/whatsapp-hub',
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: 'my-session'
});

// Handle errors from API calls
try {
  await client.sendMessage('+27763724011', 'Hello!');
} catch (error) {
  console.error('Failed to send message:', error.message);
}

// Handle SSE errors
client.on('error', (error) => {
  console.error('SSE error:', error);

  // Implement retry logic
  setTimeout(() => {
    console.log('Reconnecting...');
    client.connectSSE();
  }, 5000);
});

// Handle conflicts
client.on('conflict', (data) => {
  console.error('Multiple devices connected!');
  console.error('Please log out of other WhatsApp Web/Desktop sessions');
  // Notify admin or take corrective action
});

Best Practices

1. Use Environment Variables

const client = new WhatsHubClient({
  hubUrl: process.env.WHATSHUB_URL,
  apiKey: process.env.WHATSHUB_API_KEY,
  sessionId: process.env.WHATSHUB_SESSION_ID
});

2. Respect Rate Limits

// WhatsApp rate limit: ~40-60 messages/minute
async function sendWithRateLimit(contacts, message) {
  for (const contact of contacts) {
    await client.sendMessage(contact, message);
    await new Promise(resolve => setTimeout(resolve, 1500)); // 1.5s delay
  }
}

3. Handle Disconnections

client.on('disconnected', (data) => {
  if (data.shouldReconnect) {
    // Implement exponential backoff
    setTimeout(() => client.connectSSE(), 5000);
  } else {
    // Permanent disconnect - take action
    console.error('Permanent disconnect - manual intervention required');
  }
});

4. Clean Up

process.on('SIGINT', () => {
  console.log('Shutting down...');
  client.destroy();
  process.exit(0);
});

Troubleshooting

QR Code Not Appearing

// Ensure session is created first
await client.createSession();

// Then get QR code
const { qrCode } = await client.getQRCode();

Messages Not Being Received

// Make sure SSE is connected
client.connectSSE();

// Check connection status
const status = await client.getStatus();
console.log('Connected:', status.connected);

Session Keeps Disconnecting

// Check for conflicts
client.on('conflict', (data) => {
  console.error('Multiple devices connected!');
  // Log out of other WhatsApp Web/Desktop sessions
});

API Documentation

For complete API documentation, see:

Support

License

MIT © Phiresky

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

Changelog

See CHANGELOG.md for release history.


Made with ❤️ by Phiresky