npm package: @semboja/wa
Description: Node.js SDK for Semboja-WA (unofficial WhatsApp API)
Author: Semboja Tech
Latest version: 0.1.0

# @semboja/wa

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

## Installation

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

## Requirements

- Node.js >= 20.0.0

## Quick Start

```typescript
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

```typescript
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

```typescript
// 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

```typescript
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: '120363123456789@g.us',
  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

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

#### Document Messages

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

#### Audio Messages

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

#### Video Messages

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

#### Interactive List Messages

```typescript
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

```typescript
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

```typescript
// 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

```typescript
// 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

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

// Get group details
const group = await client.groups.get('120363123456789@g.us', 'my-device');
console.log(group.subject); // Group name
console.log(group.participants); // Group members
```

### Webhooks

```typescript
// 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

```typescript
// 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

```typescript
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:

```typescript
// 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](https://www.npmjs.com/package/@semboja/connect) instead.

## License

MIT