@semboja/wa
v0.1.0
Published
Node.js SDK for Semboja-WA (unofficial WhatsApp API)
Maintainers
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/waRequirements
- 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 membersWebhooks
// 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 removedImportant 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
