> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.getdial.ai/integrations/agent-clients/vercel-chat-sdk/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server. # Vercel Chat SDK > Add Dial as a channel to any bot built on Vercel's Chat SDK — the same handler answers SMS, MMS, iMessage, and inbound voice through one adapter. [**Vercel Chat SDK**](https://chat-sdk.dev) is a TypeScript framework for building multi-channel bots: one bot handler responds to messages across Slack, Teams, Discord, and other channels through adapters. The `@getdial/chat-sdk-adapter` package plugs **Dial** into that adapter surface so the same bot handler also answers phone traffic — SMS, MMS, iMessage, and inbound voice-call transcripts — with replies sent back over the phone through Dial. Written and maintained by Dial. Published on npm as [`@getdial/chat-sdk-adapter`](https://www.npmjs.com/package/@getdial/chat-sdk-adapter). Source at [`GetDial-AI/chat-sdk-adapter`](https://github.com/GetDial-AI/chat-sdk-adapter). ## Install ```bash npm install @getdial/chat-sdk-adapter chat ``` `chat` is Vercel's Chat SDK; both packages are required. Node 18+. ## Usage ```typescript import { Chat } from "chat"; import { createMemoryState } from "@chat-adapter/state-memory"; import { createDialAdapter } from "@getdial/chat-sdk-adapter"; const bot = new Chat({ userName: "mybot", adapters: { dial: createDialAdapter(), // reads DIAL_* env vars; explicit config wins }, state: createMemoryState(), // swap for Redis/Postgres in production }); bot.onNewMention(async (thread, message) => { await thread.post(`heard you: ${message.text}`); }); // Bind the webhook endpoint on whichever HTTP framework you use: app.post("/webhook/dial", (req) => bot.webhooks.dial(req)); ``` The `bot.webhooks.dial(request)` call routes the inbound HTTP request through the adapter's signature verification, envelope parsing, and Chat SDK's per-thread state — your handler runs identically to a Slack or Teams mention. ## Configuration `createDialAdapter(config?)` reads the environment when a field is omitted. Explicit config values win. | Field | Env var | Required | What it is | | --------------- | --------------------- | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `apiKey` | `DIAL_API_KEY` | ✅ | Dial API key (`sk_live_…`). Mint it from the [dashboard](https://getdial.ai/dashboard). | | `fromNumberId` | `DIAL_FROM_NUMBER_ID` | ✅ | Dial's ID of the phone number the bot sends **from**. Copy it from the [Phone Numbers page](https://getdial.ai/dashboard/numbers), or `dial number list --json`. | | `webhookSecret` | `DIAL_WEBHOOK_SECRET` | prod | HMAC-SHA256 signing secret Dial issued when the webhook subscription was created. Required in production; when set, incoming requests are verified against `X-Dial-Signature` and rejected `401` on mismatch. | | `apiBaseUrl` | `DIAL_API_URL` | | Override the Dial API host. Defaults to `https://api.getdial.ai`. | | `botName` | `BOT_USERNAME` | | Display name Chat SDK uses for the bot. Defaults to `"bot"`. | | `logger` | — | | Chat SDK `Logger` instance. Defaults to `ConsoleLogger("info").child("dial")`. | ## Webhook setup Point a Dial webhook subscription at the endpoint you handed to `bot.webhooks.dial`. Create the subscription from the [Webhooks page](https://getdial.ai/dashboard/webhooks) or over the API: ```bash curl -X POST https://api.getdial.ai/api/v1/webhooks \ -H "Authorization: Bearer $DIAL_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "targetUrl": "https://your-bot.example.com/webhook/dial", "eventTypes": ["*"] }' ``` The `whsec_…` secret returned at creation goes in `DIAL_WEBHOOK_SECRET`. See the [Webhooks reference](/documentation/platform/webhooks) for retries, signature format, and event types. ## What the adapter carries | Direction | Channel | Text | Media | | --------- | -------------------- | ----------------- | -------------------------------- | | Inbound | SMS | ✅ | — | | Inbound | MMS | ✅ | ✅ (image / video / audio / file) | | Inbound | iMessage | ✅ | ✅ | | Inbound | Voice call | ✅ (as transcript) | — | | Outbound | SMS / MMS / iMessage | ✅ | ✅ (via attachment URLs) | Voice calls surface to the bot as their transcript, delivered via the `call.transcribed` event. Very short calls that never generate a transcript don't fire an `onNewMention`. ## Threads A Chat SDK thread here is a **pair of phone numbers** — your Dial-owned number and the peer's — encoded as: ``` dial:{yourDialNumber}:{peerNumber} ``` Every distinct pair is a distinct thread. Chat SDK's per-thread state (conversation history, subscriptions, locks) is scoped per-pair, so multiple concurrent conversations don't leak into each other. ## Design notes * **Outbound sends and transcript fetches** go through the official [`@getdial/sdk`](https://www.npmjs.com/package/@getdial/sdk) Node SDK — no hand-rolled HTTP. * **Signature verification** uses Node's built-in `crypto.createHmac` + `timingSafeEqual`, matching the exact primitive Dial's server signs with. * **ESM-only, TypeScript-first.** The adapter ships `dist/index.js` + `dist/index.d.ts` — no source, no tests, no `node_modules`. * Peer-depends on `chat ^4.20.0` — install `chat` alongside this adapter. ## Learn more * Chat SDK docs: [chat-sdk.dev](https://chat-sdk.dev) * Adapter source + issues: [`GetDial-AI/chat-sdk-adapter`](https://github.com/GetDial-AI/chat-sdk-adapter) * Node SDK the adapter wraps: [`@getdial/sdk`](/documentation/sdks/node) * Related Dial concepts: [Webhooks](/documentation/platform/webhooks), [Events overview](/api-reference/events/overview) > Add Dial as a channel to any bot built on Vercel's Chat SDK — the same handler answers SMS, MMS, iMessage, and inbound voice through one adapter.