npm package: @semboja/connect
Description: Official Node.js SDK for Semboja WhatsApp API Bridge
Author: Semboja Tech
Latest version: 0.7.1

# @semboja/connect

Official Node.js SDK for [Semboja WhatsApp API Bridge](https://connect.semboja.tech).

[![npm version](https://img.shields.io/npm/v/@semboja/connect.svg?style=flat-square)](https://www.npmjs.com/package/@semboja/connect)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)

## Installation

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

## Quick Start

```typescript
import { SembojaClient } from '@semboja/connect';

const client = new SembojaClient('sk_live_your_api_key');

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

console.log('Message ID:', result.data.messages[0].id);
```

## Features

- **Type-safe** - Full TypeScript support with comprehensive types
- **Simple API** - Intuitive methods for all WhatsApp operations
- **Error handling** - Typed errors for easy error handling
- **Webhook verification** - Built-in signature verification
- **Retry logic** - Automatic retries with exponential backoff
- **Test mode** - Safe testing with `sk_test_*` keys

## Usage

### Initialize Client

```typescript
import { SembojaClient } from '@semboja/connect';

// Simple initialization
const client = new SembojaClient('sk_live_your_api_key');

// With options
const client = new SembojaClient({
  apiKey: process.env.SEMBOJA_API_KEY!,
  timeout: 60000,  // 60 seconds
  retries: 5,
});
```

### Send Messages

```typescript
// Text message
await client.messages.sendText({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  text: 'Hello, World!',
  previewUrl: true, // Enable URL preview
});

// Reply to a message
await client.messages.sendText({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  text: 'Thanks for your message!',
  replyTo: 'wamid.xxx', // Message ID to reply to
});

// Template message
await client.messages.sendTemplate({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  template: {
    name: 'order_confirmation',
    language: { code: 'id' },
    components: [
      {
        type: 'body',
        parameters: [
          { type: 'text', text: 'John' },
          { type: 'text', text: 'ORD-12345' },
        ],
      },
    ],
  },
});

// Image message
await client.messages.sendImage({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  image: {
    link: 'https://example.com/image.jpg',
    caption: 'Check this out!',
  },
});

// Document message
await client.messages.sendDocument({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  document: {
    link: 'https://example.com/invoice.pdf',
    filename: 'invoice.pdf',
    caption: 'Your invoice',
  },
});

// Reaction
await client.messages.sendReaction({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  reaction: {
    messageId: 'wamid.xxx',
    emoji: '👍',
  },
});

// Interactive buttons
await client.messages.sendInteractive({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  interactive: {
    type: 'button',
    body: { text: 'Choose an option:' },
    action: {
      buttons: [
        { type: 'reply', reply: { id: 'yes', title: 'Yes' } },
        { type: 'reply', reply: { id: 'no', title: 'No' } },
      ],
    },
  },
});

// Sticker message
await client.messages.sendSticker({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  sticker: {
    link: 'https://example.com/sticker.webp',
  },
});

// Location message
await client.messages.sendLocation({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  location: {
    latitude: -6.2088,
    longitude: 106.8456,
    name: 'Monas',
    address: 'Gambir, Central Jakarta, Indonesia',
  },
});

// Contact card
await client.messages.sendContacts({
  phoneNumberId: '123456789',
  to: '+6281234567890',
  contacts: [
    {
      name: {
        formatted_name: 'John Doe',
        first_name: 'John',
        last_name: 'Doe',
      },
      phones: [
        { phone: '+6281234567890', type: 'CELL' },
      ],
      emails: [
        { email: 'john@example.com', type: 'WORK' },
      ],
    },
  ],
});

// Mark message as read
await client.messages.markAsRead({
  phoneNumberId: '123456789',
  messageId: 'wamid.xxx',
});
```

### Templates

```typescript
// List all templates
const templates = await client.templates.list();

// Filter by status
const approved = await client.templates.list({ status: 'APPROVED' });
```

### Phone Numbers

```typescript
const phoneNumbers = await client.phoneNumbers.list();

for (const phone of phoneNumbers.data) {
  console.log(`${phone.verified_name}: ${phone.display_phone_number}`);
}
```

### Usage Statistics

```typescript
const usage = await client.usage.get();

console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);
console.log(`Messages sent: ${usage.data.messages.sent}`);
console.log(`Messages received: ${usage.data.messages.received}`);
console.log(`API calls: ${usage.data.api_calls}`);
```

### Test Mode

Use `sk_test_*` API keys to test without sending real messages:

```typescript
const client = new SembojaClient('sk_test_your_test_key');

// Check if in test mode
console.log('Test mode:', client.isTestMode); // true

// Trigger a test webhook
await client.test.triggerWebhook({
  phoneNumberId: '123456789',
  type: 'text',
  from: '+6281234567890',
  text: 'Test incoming message',
});
```

### Webhook Verification

```typescript
import { verifyWebhookSignature } from '@semboja/connect';

// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const isValid = verifyWebhookSignature({
    payload: req.body,
    signature: req.headers['x-semboja-signature'] as string,
    timestamp: req.headers['x-semboja-timestamp'] as string,
    secret: process.env.WEBHOOK_SECRET!,
  });

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

  const event = JSON.parse(req.body.toString());
  console.log('Received event:', event);

  res.status(200).send('OK');
});
```

### Error Handling

```typescript
import { 
  SembojaClient, 
  AuthenticationError, 
  RateLimitError,
  ValidationError,
} from '@semboja/connect';

const client = new SembojaClient('sk_live_your_api_key');

try {
  await client.messages.sendText({
    phoneNumberId: '123456789',
    to: '+6281234567890',
    text: 'Hello!',
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof RateLimitError) {
    console.error('Rate limited, retry after:', error.resetAt);
  } else if (error instanceof ValidationError) {
    console.error('Invalid request:', error.message);
  } else {
    throw error;
  }
}
```

## API Reference

### SembojaClient

| Property | Type | Description |
|----------|------|-------------|
| `messages` | `Messages` | Messages API |
| `templates` | `Templates` | Templates API |
| `phoneNumbers` | `PhoneNumbers` | Phone Numbers API |
| `usage` | `Usage` | Usage API |
| `test` | `Test` | Test API (test mode only) |
| `isTestMode` | `boolean` | Whether using test API key |

### Messages API

| Method | Description |
|--------|-------------|
| `sendText(options)` | Send a text message |
| `sendTemplate(options)` | Send a template message |
| `sendImage(options)` | Send an image |
| `sendVideo(options)` | Send a video |
| `sendAudio(options)` | Send an audio file |
| `sendDocument(options)` | Send a document |
| `sendSticker(options)` | Send a sticker (WebP) |
| `sendLocation(options)` | Send a location |
| `sendContacts(options)` | Send contact cards |
| `sendReaction(options)` | Send a reaction |
| `sendInteractive(options)` | Send interactive message |
| `markAsRead(options)` | Mark a message as read |

### Error Classes

| Class | Status Code | Description |
|-------|-------------|-------------|
| `SembojaError` | varies | Base error class |
| `AuthenticationError` | 401 | Invalid API key |
| `RateLimitError` | 429 | Rate limit exceeded |
| `ValidationError` | 400 | Invalid request |
| `NotFoundError` | 404 | Resource not found |
| `ServerError` | 500 | Server error |
| `NetworkError` | - | Network/connection error |

## Requirements

- Node.js 20.0.0 or higher

## Links

- [API Documentation](https://connect.semboja.tech/docs)
- [Console](https://console.semboja.tech)
- [Semboja](https://semboja.tech)

## License

MIT - [Semboja Tech](https://semboja.tech)