Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions apps/docs/content/docs/adapters/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Overview
description: Platform-specific adapters for Slack, Teams, Google Chat, Discord, Telegram, GitHub, and Linear.
description: Platform-specific adapters for Slack, Teams, Google Chat, Discord, Telegram, Twilio, GitHub, and Linear.
type: overview
prerequisites:
- /docs/getting-started
Expand All @@ -12,50 +12,50 @@ Adapters handle webhook verification, message parsing, and API calls for each pl

### Messaging

| Feature | [Slack](/docs/adapters/slack) | [Teams](/docs/adapters/teams) | [Google Chat](/docs/adapters/gchat) | [Discord](/docs/adapters/discord) | [Telegram](/docs/adapters/telegram) | [GitHub](/docs/adapters/github) | [Linear](/docs/adapters/linear) |
|---------|-------|-------|-------------|---------|---------|--------|--------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| File uploads | ✅ | ✅ | ❌ | ✅ | ⚠️ Single file | ❌ | ❌ |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ❌ |
| Feature | [Slack](/docs/adapters/slack) | [Teams](/docs/adapters/teams) | [Google Chat](/docs/adapters/gchat) | [Discord](/docs/adapters/discord) | [Telegram](/docs/adapters/telegram) | [Twilio](/docs/adapters/twilio) | [GitHub](/docs/adapters/github) | [Linear](/docs/adapters/linear) |
|---------|-------|-------|-------------|---------|---------|--------|--------|--------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| File uploads | ✅ | ✅ | ❌ | ✅ | ⚠️ Single file | ❌ | ❌ | ❌ |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ❌ | ❌ |

### Rich content

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | GFM Markdown | Markdown |
| Buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard callbacks | ❌ | ❌ |
| Link buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard URLs | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Tables | ✅ Block Kit | ✅ GFM | ⚠️ ASCII | ✅ GFM | ⚠️ ASCII | ✅ GFM | ✅ GFM |
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Images in cards | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | Twilio | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|--------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | Markdown + inline keyboard buttons | Text fallback | GFM Markdown | Markdown |
| Buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard callbacks | ❌ | ❌ | ❌ |
| Link buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard URLs | ❌ | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Tables | ✅ Block Kit | ✅ GFM | ⚠️ ASCII | ✅ GFM | ⚠️ ASCII | ⚠️ Text | ✅ GFM | ✅ GFM |
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ⚠️ Text | ✅ | ✅ |
| Images in cards | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

### Conversations

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|
| Slash commands | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ |
| Typing indicator | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ |
| DMs | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | Twilio | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|--------|
| Slash commands | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ⚠️ | ⚠️ |
| Typing indicator | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| DMs | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ |

### Message history

| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|
| Fetch messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ✅ |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ⚠️ Cached | ❌ | ❌ |
| Fetch thread info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fetch channel messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ❌ |
| List threads | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| Fetch channel info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Post channel message | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | Discord | Telegram | Twilio | GitHub | Linear |
|---------|-------|-------|-------------|---------|----------|--------|--------|--------|
| Fetch messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ✅ | ✅ | ✅ |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ⚠️ Cached | ✅ | ❌ | ❌ |
| Fetch thread info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fetch channel messages | ✅ | ✅ | ✅ | ✅ | ⚠️ Cached | ❌ | ✅ | ❌ |
| List threads | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ |
| Fetch channel info | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| Post channel message | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |

<Callout type="info">
⚠️ indicates partial support — the feature works with limitations. See individual adapter pages for details.
Expand All @@ -70,6 +70,7 @@ Adapters handle webhook verification, message parsing, and API calls for each pl
| [Google Chat](/docs/adapters/gchat) | `@chat-adapter/gchat` |
| [Discord](/docs/adapters/discord) | `@chat-adapter/discord` |
| [Telegram](/docs/adapters/telegram) | `@chat-adapter/telegram` |
| [Twilio](/docs/adapters/twilio) | `@chat-adapter/twilio` |
| [GitHub](/docs/adapters/github) | `@chat-adapter/github` |
| [Linear](/docs/adapters/linear) | `@chat-adapter/linear` |

Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/docs/adapters/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"gchat",
"discord",
"telegram",
"twilio",
"github",
"linear"
]
Expand Down
119 changes: 119 additions & 0 deletions apps/docs/content/docs/adapters/twilio.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
title: Twilio
description: Configure the Twilio adapter for SMS and MMS messaging.
type: integration
prerequisites:
- /docs/getting-started
---

## Installation

```sh title="Terminal"
pnpm add @chat-adapter/twilio
```

## Usage

The adapter auto-detects `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, and `TWILIO_PHONE_NUMBER` from environment variables:

```typescript title="lib/bot.ts" lineNumbers
import { Chat } from "chat";
import { createTwilioAdapter } from "@chat-adapter/twilio";

const bot = new Chat({
userName: "mybot",
adapters: {
twilio: createTwilioAdapter(),
},
});

bot.onNewMention(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
```

## Webhook route

```typescript title="app/api/webhooks/twilio/route.ts" lineNumbers
import { bot } from "@/lib/bot";

export async function POST(request: Request): Promise<Response> {
return bot.webhooks.twilio(request);
}
```

Configure this URL as your Twilio webhook in the [Twilio Console](https://console.twilio.com/):

1. Go to **Phone Numbers** > **Manage** > **Active Numbers**
2. Select your phone number
3. Under **Messaging Configuration**, set the webhook URL for "A message comes in" to `https://your-domain.com/api/webhooks/twilio`
4. Set the HTTP method to **POST**

## Configuration

All options are auto-detected from environment variables when not provided.

| Option | Required | Description |
|--------|----------|-------------|
| `accountSid` | No* | Twilio Account SID. Auto-detected from `TWILIO_ACCOUNT_SID` |
| `authToken` | No* | Twilio Auth Token. Auto-detected from `TWILIO_AUTH_TOKEN` |
| `phoneNumber` | No* | Twilio phone number (E.164 format). Auto-detected from `TWILIO_PHONE_NUMBER` |
| `webhookUrl` | No | Override webhook URL for signature validation (useful behind proxies) |
| `userName` | No | Bot username (defaults to `"bot"`) |
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |

*These options are required — either via config or environment variables.

## Environment variables

```bash title=".env.local"
TWILIO_ACCOUNT_SID=AC_your_account_sid_here
TWILIO_AUTH_TOKEN=your_auth_token_here
TWILIO_PHONE_NUMBER=+15551234567
```

## Features

| Feature | Supported |
|---------|-----------|
| Post message | Yes |
| Edit message | No (SMS is immutable) |
| Delete message | Yes (via Twilio API) |
| Mentions | Yes (all inbound messages are treated as mentions) |
| Reactions | No |
| Cards | Text fallback |
| Modals | No |
| Streaming | No |
| DMs | Yes (all SMS conversations are DMs) |
| Ephemeral messages | No |
| File uploads | No (MMS media URLs only) |
| Typing indicator | No |
| Fetch messages | Yes (bidirectional) |
| Fetch single message | Yes |
| Fetch thread info | Yes |

## Thread ID format

Twilio thread IDs follow the pattern `twilio:{twilioNumber}:{recipientNumber}`:

```
twilio:+15551234567:+15559876543
```

Each unique pair of phone numbers represents a conversation thread.

## MMS media

Inbound MMS messages include media attachments (images, videos, audio, files). These are parsed automatically from Twilio's `MediaUrl` and `MediaContentType` webhook fields.

Outbound MMS is supported when your message includes media URLs via the `files` property with URL-based files. Binary file uploads are not supported — Twilio's API only accepts public media URLs.

## Notes

- SMS body is limited to 1600 characters. Messages exceeding this limit are truncated and a warning is logged.
- All SMS conversations are treated as DMs (`isDM` always returns `true`).
- There are no channels, threads-within-threads, or slash commands in SMS.
- Twilio status callback webhooks (delivery receipts) are automatically detected and acknowledged without processing.
- `editMessage` throws `NotImplementedError` — Twilio's `update()` API only supports redacting message bodies or canceling scheduled messages, not real content edits.
- `fetchMessages` returns messages from both directions (inbound and outbound), sorted chronologically.
- Webhook signature validation uses `twilio.validateRequest`. If your app is behind a reverse proxy, set the `webhookUrl` config option to the public-facing URL.
1 change: 1 addition & 0 deletions examples/nextjs-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@chat-adapter/state-memory": "workspace:*",
"@chat-adapter/state-redis": "workspace:*",
"@chat-adapter/telegram": "workspace:*",
"@chat-adapter/twilio": "workspace:*",
"@chat-adapter/teams": "workspace:*",
"ai": "^6.0.5",
"chat": "workspace:*",
Expand Down
14 changes: 14 additions & 0 deletions examples/nextjs-chat/src/lib/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
createTelegramAdapter,
type TelegramAdapter,
} from "@chat-adapter/telegram";
import { createTwilioAdapter, type TwilioAdapter } from "@chat-adapter/twilio";
import { ConsoleLogger } from "chat";
import { recorder, withRecording } from "./recorder";

Expand All @@ -28,6 +29,7 @@ export interface Adapters {
slack?: SlackAdapter;
teams?: TeamsAdapter;
telegram?: TelegramAdapter;
twilio?: TwilioAdapter;
}

// Methods to record for each adapter (outgoing API calls)
Expand Down Expand Up @@ -96,6 +98,7 @@ const TELEGRAM_METHODS = [
"openDM",
"fetchMessages",
];
const TWILIO_METHODS = ["postMessage", "fetchMessages"];

/**
* Build type-safe adapters based on available environment variables.
Expand Down Expand Up @@ -215,5 +218,16 @@ export function buildAdapters(): Adapters {
);
}

// Twilio SMS adapter (optional) - env vars: TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE_NUMBER
if (process.env.TWILIO_ACCOUNT_SID) {
adapters.twilio = withRecording(
createTwilioAdapter({
logger: logger.child("twilio"),
}),
"twilio",
TWILIO_METHODS
);
}

return adapters;
}
57 changes: 57 additions & 0 deletions packages/adapter-twilio/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@chat-adapter/twilio",
"version": "0.1.0",
"description": "Twilio SMS/MMS adapter for chat",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"test": "vitest run --coverage",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@chat-adapter/shared": "workspace:*",
"chat": "workspace:*",
"twilio": "^5.0.0"
},
"devDependencies": {
"@types/node": "^25.3.2",
"tsup": "^8.3.5",
"typescript": "^5.7.2",
"vitest": "^4.0.18"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vercel/chat.git",
"directory": "packages/adapter-twilio"
},
"homepage": "https://github.com/vercel/chat#readme",
"bugs": {
"url": "https://github.com/vercel/chat/issues"
},
"publishConfig": {
"access": "public"
},
"keywords": [
"chat",
"twilio",
"sms",
"mms",
"adapter"
],
"license": "MIT"
}
Loading