npm package: @memberjunction/communication-twilio
Description: Twilio provider for MemberJunction Communication framework
Latest version: 5.24.0

# @memberjunction/communication-twilio

Twilio provider for the MemberJunction Communication Framework. This provider enables messaging across multiple channels -- SMS, WhatsApp Business, and Facebook Messenger -- through the Twilio API. The channel is automatically detected based on recipient format.

## Architecture

```mermaid
graph TD
    subgraph twilio["@memberjunction/communication-twilio"]
        TP["TwilioProvider"]
        CFG["Config Module\n(Environment Variables)"]
        CRED["TwilioCredentials"]
        DETECT["Channel Detection\n(SMS / WhatsApp / Messenger)"]
    end

    subgraph tw["Twilio Service"]
        API["Twilio REST API"]
        SMS["SMS / MMS"]
        WA["WhatsApp Business"]
        FB["Facebook Messenger"]
    end

    subgraph base["@memberjunction/communication-types"]
        BCP["BaseCommunicationProvider"]
    end

    BCP --> TP
    TP --> CFG
    TP --> CRED
    TP --> DETECT
    TP --> API
    API --> SMS
    API --> WA
    API --> FB

    style twilio fill:#2d6a9f,stroke:#1a4971,color:#fff
    style tw fill:#7c5295,stroke:#563a6b,color:#fff
    style base fill:#2d8659,stroke:#1a5c3a,color:#fff
```

## Installation

```bash
npm install @memberjunction/communication-twilio
```

## Configuration

Set the following environment variables:

```env
# Required
TWILIO_ACCOUNT_SID=your-account-sid
TWILIO_AUTH_TOKEN=your-auth-token
TWILIO_PHONE_NUMBER=+1234567890

# Optional (for additional channels)
TWILIO_WHATSAPP_NUMBER=+1234567890
TWILIO_FACEBOOK_PAGE_ID=your-page-id
```

## Channel Detection

The provider automatically selects the messaging channel based on the recipient format:

```mermaid
flowchart LR
    TO["Recipient Address"] --> CHECK{"Prefix?"}
    CHECK -->|"whatsapp:+1..."| WA["WhatsApp Channel"]
    CHECK -->|"messenger:psid"| FB["Messenger Channel"]
    CHECK -->|"+1234567890"| SMS["SMS Channel"]

    style TO fill:#2d6a9f,stroke:#1a4971,color:#fff
    style WA fill:#2d8659,stroke:#1a5c3a,color:#fff
    style FB fill:#7c5295,stroke:#563a6b,color:#fff
    style SMS fill:#b8762f,stroke:#8a5722,color:#fff
```

| Recipient Format | Channel | From Number Config |
|-----------------|---------|-------------------|
| `+1234567890` | SMS | `TWILIO_PHONE_NUMBER` |
| `whatsapp:+1234567890` | WhatsApp | `TWILIO_WHATSAPP_NUMBER` |
| `messenger:user_psid` | Facebook Messenger | `TWILIO_FACEBOOK_PAGE_ID` |

## Supported Operations

| Operation | Supported | Notes |
|-----------|-----------|-------|
| `SendSingleMessage` | Yes | Auto-detects channel, supports media URLs |
| `GetMessages` | Yes | Filter by from, to, dateSent |
| `ForwardMessage` | Yes | Reconstructs message body with forward prefix |
| `ReplyToMessage` | Yes | Fetches original, sends to original sender |
| `CreateDraft` | No | Messaging services have no draft concept |
| Extended operations | No | No folder, search, or attachment operations |

## Usage

### Sending SMS

```typescript
import { CommunicationEngine } from '@memberjunction/communication-engine';
import { Message } from '@memberjunction/communication-types';

const engine = CommunicationEngine.Instance;
await engine.Config(false, contextUser);

const message = new Message();
message.To = '+1234567890';
message.Body = 'Hello from MemberJunction!';

const result = await engine.SendSingleMessage('Twilio', 'Standard SMS', message);
```

### Sending WhatsApp Message

```typescript
const message = new Message();
message.To = 'whatsapp:+1234567890';
message.Body = 'Hello via WhatsApp!';

const result = await engine.SendSingleMessage('Twilio', 'Standard SMS', message);
```

### Sending Facebook Messenger Message

```typescript
const message = new Message();
message.To = 'messenger:user_psid';
message.Body = 'Hello via Messenger!';

const result = await engine.SendSingleMessage('Twilio', 'Standard SMS', message);
```

### Sending Media (MMS / WhatsApp)

```typescript
const message = new Message();
message.To = '+1234567890';
message.Body = 'Check out this image!';
message.ContextData = {
    mediaUrls: ['https://example.com/image.jpg']
};

const result = await engine.SendSingleMessage('Twilio', 'Standard SMS', message);
```

### Retrieving Messages

```typescript
const provider = engine.GetProvider('Twilio');

const result = await provider.GetMessages({
    NumMessages: 50,
    ContextData: {
        from: '+1234567890',
        to: '+0987654321',
        dateSent: new Date('2025-01-01')
    }
});

result.Messages.forEach(msg => {
    console.log(`${msg.From} -> ${msg.To}: ${msg.Body}`);
});
```

### Per-Request Credentials

```typescript
import { TwilioCredentials } from '@memberjunction/communication-twilio';

const result = await provider.SendSingleMessage(processedMessage, {
    accountSid: 'customer-sid',
    authToken: 'customer-token',
    phoneNumber: '+1987654321'
} as TwilioCredentials);
```

### Replying to a Message

```typescript
const result = await provider.ReplyToMessage({
    MessageID: 'original-twilio-message-sid',
    Message: processedReply
});
```

### Forwarding a Message

```typescript
const result = await provider.ForwardMessage({
    MessageID: 'message-sid-to-forward',
    ToRecipients: ['+1234567890', 'whatsapp:+0987654321'],
    Message: 'FYI - forwarding this message'
});
```

## TwilioCredentials

```typescript
interface TwilioCredentials extends ProviderCredentialsBase {
    accountSid?: string;
    authToken?: string;
    phoneNumber?: string;
    whatsappNumber?: string;
    facebookPageId?: string;
    disableEnvironmentFallback?: boolean;
}
```

## Client Caching

The provider caches Twilio client instances for performance. Environment credential clients are shared across all calls; per-request credential clients are cached by `accountSid`.

## Important Notes

- SMS/messaging channels use **plain text only** -- HTML content is not supported
- Message threading is simulated using Twilio Message SIDs (Twilio has no native thread concept)
- Forwarding reconstructs the message content with a "Forwarded message" prefix
- Media attachments are supported through the `mediaUrls` context data property
- All operations are asynchronous via the Twilio REST API

## Dependencies

| Package | Purpose |
|---------|---------|
| `@memberjunction/communication-types` | Base provider class and type definitions |
| `@memberjunction/core` | Logging utilities (LogError, LogStatus) |
| `@memberjunction/global` | RegisterClass decorator |
| `twilio` | Official Twilio SDK |
| `dotenv` | Environment variable loading |
| `env-var` | Environment variable validation |

## Development

```bash
npm run build    # Compile TypeScript
npm run clean    # Remove dist directory
```