> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel Chat SDK Adapter

> Build bots in Next.js that send and receive SMS and MMS through Telnyx using the official @telnyx/chat-sdk-adapter package for Vercel's Chat SDK.

[`@telnyx/chat-sdk-adapter`](https://www.npmjs.com/package/@telnyx/chat-sdk-adapter) is the official Telnyx adapter for the [Vercel Chat SDK](https://chat-sdk.dev/) — Vercel's TypeScript framework for building chatbots that work across Slack, Microsoft Teams, Discord, Telegram, WhatsApp, email, and now SMS/MMS through Telnyx. Write bot logic once and route messages through any supported channel.

The adapter is maintained by Telnyx at [`team-telnyx/telnyx-chat-sdk-adapter`](https://github.com/team-telnyx/telnyx-chat-sdk-adapter) and listed as a **vendor-official** adapter on [chat-sdk.dev/adapters](https://chat-sdk.dev/adapters).

<Note>
  **When to use this adapter:** building an AI- or rules-driven SMS bot inside a Next.js app and wanting the same handler API you already use for other chat platforms. For general-purpose, high-volume messaging outside a Chat SDK app, use the [Telnyx Messaging API](/docs/messaging/messages/send-message/index) directly.
</Note>

## Prerequisites

* A [Telnyx account](https://portal.telnyx.com) with a messaging-enabled phone number (E.164 format)
* A [Messaging Profile](/docs/messaging/messages/messaging-profiles-overview/index) with a webhook URL configured
* Your Telnyx [v2 API key](https://portal.telnyx.com/#/app/auth/v2)
* The Ed25519 **Public Key** from the messaging profile (for webhook signature verification)
* Node.js `>=18`

***

## Install

```bash theme={null}
pnpm add @telnyx/chat-sdk-adapter chat
```

Also install a state adapter — `@chat-adapter/state-memory` for development, `@chat-adapter/state-redis` for production:

```bash theme={null}
pnpm add @chat-adapter/state-memory
```

***

## Quick start

```ts theme={null}
import { createTelnyxAdapter } from "@telnyx/chat-sdk-adapter";
import { createMemoryState } from "@chat-adapter/state-memory";
import { Chat } from "chat";

const telnyx = createTelnyxAdapter({
  messagingProfileId: "40017a7b-...", // recommended — see "Dedicated messaging profile"
  // apiKey:      "KEY..."              // or set TELNYX_API_KEY
  // phoneNumber: "+15551234567"        // or set TELNYX_FROM_NUMBER
  // publicKey:   "vFo7Hk..."           // or set TELNYX_PUBLIC_KEY
});

const chat = new Chat({
  userName: "sms-bot",
  adapters: { telnyx },
  state: createMemoryState(),
});

chat.onNewMention(async (thread, message) => {
  await thread.subscribe();
  await thread.post(`Got your text: ${message.text}`);
});

chat.onSubscribedMessage(async (thread, message) => {
  await thread.post(`Reply: ${message.text}`);
});

await chat.initialize();
```

In your webhook route handler, forward the request to `chat.webhooks.telnyx`:

```ts theme={null}
// app/api/webhooks/telnyx/route.ts (Next.js App Router)
export async function POST(request: Request) {
  return chat.webhooks.telnyx(request);
}
```

Point your messaging profile's webhook URL at `https://<your-domain>/api/webhooks/telnyx`.

***

## Configuration

### Environment variables

| Variable             | Required    | Description                                                                                                                                                       |
| -------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TELNYX_API_KEY`     | Yes         | Your v2 API key                                                                                                                                                   |
| `TELNYX_FROM_NUMBER` | Yes         | E.164 phone number the bot sends from                                                                                                                             |
| `TELNYX_PUBLIC_KEY`  | Recommended | Ed25519 public key from the messaging profile. Base64 or hex — auto-detected. If unset, webhook signatures are not verified — never run without it in production. |
| `BOT_USERNAME`       | No          | Bot display name. Defaults to `"bot"`.                                                                                                                            |

### `TelnyxAdapterConfig`

```ts theme={null}
interface TelnyxAdapterConfig {
  apiKey?: string;
  phoneNumber?: string;            // E.164
  publicKey?: string;              // base64 or hex, auto-detected
  messagingProfileId?: string;     // strongly recommended (see below)
  userName?: string;
  extraTags?: string[];            // merged into outbound `tags` array
  disableAttributionTags?: boolean;
  logger?: Logger;
}
```

***

## Recommended: Dedicated messaging profile

Create a dedicated [Messaging Profile](/docs/messaging/messages/messaging-profiles-overview/index) for each bot and pass its ID as `messagingProfileId`. We recommend prefixing the profile name with `[Chat SDK]` (for example, `[Chat SDK] support-bot-prod`) so it's easy to find in Mission Control and in usage reports.

A dedicated profile gives you:

* Per-profile usage analytics, so bot traffic is separated from the rest of your account
* Per-profile spend limits, which cap bot spend without affecting other workloads
* An isolated webhook URL and failover URL
* An isolated Ed25519 public key — the one you pass as `publicKey` belongs to the profile, not the account

***

## Webhook setup

<Steps>
  <Step title="Open your messaging profile">
    In the [Telnyx Mission Control portal](https://portal.telnyx.com/#/app/messaging), open the messaging profile you created for the bot.
  </Step>

  <Step title="Set the webhook URL">
    Under **Inbound Settings**, set the **Webhook URL** to your server's endpoint (for example, `https://bot.example.com/api/webhooks/telnyx`). Set **Webhook API version** to `2`.
  </Step>

  <Step title="Copy the Public Key">
    Under **Messaging** → **Security**, copy the **Public Key** for the profile. Pass it as `publicKey` (or set `TELNYX_PUBLIC_KEY`). Telnyx shows this key in base64; the adapter accepts it as-is.
  </Step>

  <Step title="Assign a phone number">
    Assign one or more phone numbers to the profile. The number you set as `TELNYX_FROM_NUMBER` must belong to this profile.
  </Step>
</Steps>

Incoming webhooks are validated against the `telnyx-signature-ed25519` and `telnyx-timestamp` headers. Requests with a timestamp older than 300 seconds, or with an invalid signature, are rejected with `401`.

***

## Capabilities

| Capability          | Supported | Notes                                                                                                   |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| Inbound SMS / MMS   | Yes       | via Ed25519-verified webhooks                                                                           |
| Outbound SMS        | Yes       | via `POST /v2/messages`                                                                                 |
| Outbound MMS        | Yes       | automatic upgrade when a posted message has attachments with public URLs                                |
| Rate-limit handling | Yes       | `429` responses surface as `AdapterRateLimitError` with `Retry-After`                                   |
| Structured errors   | Yes       | Telnyx error codes, titles, and details are parsed into `AuthenticationError` / `NetworkError` messages |
| Direct messages     | Yes       | a thread is one pair of phone numbers; `isDM()` returns `true`                                          |
| Typing indicators   | No        | no-op; SMS has no typing concept                                                                        |
| Reactions           | No        | SMS has no reactions                                                                                    |
| Edit / delete       | No        | SMS messages are final once sent                                                                        |
| Message history API | No        | Telnyx does not expose a thread-scoped history API — use a persistent Chat SDK state adapter            |

***

## Thread model

A thread is a pair of E.164 phone numbers. The thread ID format is `telnyx:<bot-number>:<user-number>`, for example `telnyx:+15551234567:+15559876543`. `openDM(phoneNumber)` returns the thread ID for a given recipient so you can post proactively.

***

## Attribution

Outbound messages carry two ecosystem-observability signals:

1. **`User-Agent` header** on every outbound API call: `@telnyx/chat-sdk-adapter/<version> (vercel-chat-sdk)`.
2. **`tags` on every outbound message**: `["vercel-chat-sdk", "vercel-chat-sdk:<version>"]`, merged with any user-supplied tags.

These tags appear in Telnyx webhook event payloads (`message.sent`, `message.finalized`, `message.received`) in the `data.payload.tags` field. User-supplied `extraTags` are merged after the attribution tags. Set `disableAttributionTags: true` to opt out; `extraTags` is unaffected.

```ts theme={null}
const telnyx = createTelnyxAdapter({
  extraTags: ["env:prod", "team:support"],
  // disableAttributionTags: true,
});
```

***

## Pair with the Telnyx AI SDK provider

Use this adapter alongside [`@telnyx/ai-sdk-provider`](https://github.com/team-telnyx/ai-sdk-provider) — the Telnyx provider for the [Vercel AI SDK](https://ai-sdk.dev/) — to build a full AI-powered SMS agent on Telnyx inference. The Chat SDK handles message I/O; the AI SDK handles LLM, embeddings, and speech. One account, one API key, two packages.

***

## Resources

* [`@telnyx/chat-sdk-adapter` on npm](https://www.npmjs.com/package/@telnyx/chat-sdk-adapter)
* [Source on GitHub](https://github.com/team-telnyx/telnyx-chat-sdk-adapter)
* [Vercel Chat SDK adapter directory](https://chat-sdk.dev/adapters)
* [Chat SDK docs](https://chat-sdk.dev/docs)
* [Telnyx Messaging API reference](/docs/messaging/messages/send-message/index)
* [Messaging profiles overview](/docs/messaging/messages/messaging-profiles-overview/index)
