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

@semboja/wa

v0.1.0

Published

Node.js SDK for Semboja-WA (unofficial WhatsApp API)

Readme

@semboja/wa

Node.js SDK for Semboja-WA - an unofficial WhatsApp API gateway using the Baileys library.

Installation

npm install @semboja/wa
# or
yarn add @semboja/wa
# or
pnpm add @semboja/wa

Requirements

  • Node.js >= 20.0.0

Quick Start

import { SembojaWaClient } from '@semboja/wa';

const client = new SembojaWaClient({
  token: 'your_api_token',
  defaultDeviceId: 'my-device', // Optional: default device for all operations
});

// Send a text message
await client.messages.sendText({
  to: '6281234567890',
  text: 'Hello from Semboja!',
});

Features

  • Zero runtime dependencies - Uses native Node.js fetch API
  • Full TypeScript support - Comprehensive type definitions
  • All message types - Text, image, document, audio, video, sticker, list, buttons
  • Device management - Create, list, delete devices with QR code pairing
  • Webhook configuration - Manage webhook endpoints for real-time notifications
  • Batch messaging - Send messages to multiple recipients
  • Automatic retries - Built-in retry logic with exponential backoff
  • Quota tracking - Monitor API usage and limits

Usage

Client Configuration

import { SembojaWaClient } from '@semboja/wa';

// Simple initialization with just token
const client = new SembojaWaClient('your_api_token');

// Full configuration
const client = new SembojaWaClient({
  token: 'your_api_token',
  baseUrl: 'https://uwa.semboja.tech', // Default
  timeout: 30000, // 30 seconds (default)
  retries: 3, // Number of retries (default)
  defaultDeviceId: 'my-device', // Optional
});

Device Management

// List all devices
const devices = await client.devices.list();

// Create a new device
const device = await client.devices.create({ device_id: 'my-device' });

// Get device details
const device = await client.devices.get('my-device');

// Get QR code for pairing
const qr = await client.devices.getQrCode('my-device');
console.log(qr.qrCode); // Data URL for QR image
console.log(qr.rawQr);  // Raw QR string

// Check if device is connected
const isConnected = await client.devices.isConnected('my-device');

// Reconnect a disconnected device
await client.devices.reconnect('my-device');

// Delete a device
await client.devices.delete('my-device');

Sending Messages

Text Messages

await client.messages.sendText({
  deviceId: 'my-device', // Optional if defaultDeviceId is set
  to: '6281234567890',
  text: 'Hello, World!',
});

// Reply to a message
await client.messages.sendText({
  to: '6281234567890',
  text: 'This is a reply',
  // replyTo: 'message-id', // If supported
});

// Send to a group
await client.messages.sendText({
  to: '[email protected]',
  text: 'Hello group!',
  isGroupMessage: true,
});

// Schedule a message
await client.messages.sendText({
  to: '6281234567890',
  text: 'Scheduled message',
  sendAt: '2026-03-01T10:00:00Z',
});

Image Messages

await client.messages.sendImage({
  to: '6281234567890',
  imageUrl: 'https://example.com/image.jpg',
  caption: 'Check this out!', // Optional
});

Document Messages

await client.messages.sendDocument({
  to: '6281234567890',
  documentUrl: 'https://example.com/invoice.pdf',
  filename: 'Invoice-001.pdf',
  caption: 'Your invoice', // Optional
});

Audio Messages

await client.messages.sendAudio({
  to: '6281234567890',
  audioUrl: 'https://example.com/audio.mp3',
});

Video Messages

await client.messages.sendVideo({
  to: '6281234567890',
  videoUrl: 'https://example.com/video.mp4',
  caption: 'Watch this!', // Optional
});

Interactive List Messages

await client.messages.sendList({
  to: '6281234567890',
  title: 'Choose an option',
  body: 'Please select from the list below',
  buttonText: 'View Options',
  sections: [
    {
      title: 'Section 1',
      rows: [
        { rowId: '1', title: 'Option 1', description: 'First option' },
        { rowId: '2', title: 'Option 2', description: 'Second option' },
      ],
    },
  ],
  footer: 'Powered by Semboja', // Optional
});

Interactive Button Messages

await client.messages.sendButtons({
  to: '6281234567890',
  body: 'Choose an action',
  buttons: [
    { id: 'yes', text: 'Yes' },
    { id: 'no', text: 'No' },
    { id: 'maybe', text: 'Maybe' },
  ],
  footer: 'Reply with a button', // Optional
});

Managing Messages

// Get message by ID
const message = await client.messages.get('kwid-123');

// List outgoing messages
const messages = await client.messages.list({
  deviceId: 'my-device',
  status: 'success', // 'pending' | 'success' | 'fail'
  limit: 20,
});

// List incoming messages
const incoming = await client.messages.listIncoming({
  deviceId: 'my-device',
  limit: 20,
});

Batch Messages

// Send batch messages
const batch = await client.batch.create({
  deviceId: 'my-device',
  messages: [
    { phone_number: '6281234567890', message: 'Hello 1', message_type: 'text' },
    { phone_number: '6289876543210', message: 'Hello 2', message_type: 'text' },
  ],
});

// Get batch status
const status = await client.batch.get(batch.id);
console.log(`Sent: ${status.sent_count}, Failed: ${status.failed_count}`);

Groups

// List groups for a device
const groups = await client.groups.list('my-device');

// Get group details
const group = await client.groups.get('[email protected]', 'my-device');
console.log(group.subject); // Group name
console.log(group.participants); // Group members

Webhooks

// List webhooks
const webhooks = await client.webhooks.list();

// Create a webhook
const webhook = await client.webhooks.create({
  url: 'https://yourapp.com/webhook',
  events: ['send_message_response', 'incoming_message', 'device_status'],
});

// Delete a webhook
await client.webhooks.delete(webhook.id);

// List webhook delivery logs
const logs = await client.webhooks.listResponses();

Quotas

// Get current quota
const quota = await client.quotas.get();
console.log(`Messages: ${quota.outgoing_messages.used}/${quota.outgoing_messages.limit}`);
console.log(`Devices: ${quota.devices.used}/${quota.devices.limit}`);
console.log(`Plan: ${quota.plan}`);

// Check if there's remaining quota
const hasQuota = await client.quotas.hasOutgoingQuota();
const hasDeviceQuota = await client.quotas.hasDeviceQuota();

Error Handling

import {
  SembojaWaClient,
  AuthenticationError,
  DeviceNotConnectedError,
  QuotaExceededError,
  ValidationError,
  RateLimitError,
  NotFoundError,
  ServerError,
  NetworkError,
  TimeoutError,
} from '@semboja/wa';

try {
  await client.messages.sendText({
    to: '6281234567890',
    text: 'Hello!',
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API token');
  } else if (error instanceof DeviceNotConnectedError) {
    console.error(`Device ${error.deviceId} is not connected`);
    // Attempt to reconnect or show QR code
    const qr = await client.devices.getQrCode(error.deviceId);
  } else if (error instanceof QuotaExceededError) {
    console.error('Message quota exceeded');
  } else if (error instanceof ValidationError) {
    console.error('Invalid request:', error.message);
  } else if (error instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof NotFoundError) {
    console.error('Resource not found');
  } else if (error instanceof ServerError) {
    console.error('Server error, please retry');
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
  } else if (error instanceof TimeoutError) {
    console.error('Request timed out');
  }
}

Phone Number Format

Phone numbers should include the country code without the + prefix:

// All these formats work
await client.messages.sendText({ to: '6281234567890', text: 'Hello' });
await client.messages.sendText({ to: '+6281234567890', text: 'Hello' }); // + will be removed
await client.messages.sendText({ to: '+62 812-3456-7890', text: 'Hello' }); // Spaces/dashes removed

Important Notes

This SDK connects to an unofficial WhatsApp API gateway. Using unofficial WhatsApp APIs may violate WhatsApp's Terms of Service and could result in your phone number being banned. Use at your own risk.

For official WhatsApp Business API integration, consider using @semboja/connect instead.

License

MIT