> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://agentphone.to/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://agentphone.to/docs/_mcp/server.

# Vercel

> Add SMS, MMS, iMessage, and voice to Vercel's Chat SDK with the AgentPhone adapter

Chat SDK by Vercel is the open-source toolkit for building chat interfaces — it powers conversational UIs across Slack, Teams, Discord, WhatsApp, Telegram, and more. AgentPhone is an official vendor adapter, bringing **SMS, MMS, iMessage, and voice** to the Chat SDK ecosystem through one interface.

## Four channels, one adapter

| Channel  | Send | Receive     | Media | Reactions |
| -------- | ---- | ----------- | ----- | --------- |
| SMS      | Yes  | Yes         | —     | —         |
| MMS      | Yes  | Yes         | Yes   | —         |
| iMessage | Yes  | Yes         | Yes   | Yes       |
| Voice    | —    | Transcripts | —     | —         |

Inbound SMS, MMS, and iMessage arrive as standard Chat SDK message events. Voice calls land as messages containing the full transcript and summary when the call ends — your bot logic handles everything through the same handler pipeline.

## Get started

```bash
npm install @agentphone/chat-sdk-adapter chat @chat-adapter/state-memory
```

```typescript
import { Chat } from "chat";
import { createMemoryState } from "@chat-adapter/state-memory";
import { createAgentPhoneAdapter } from "@agentphone/chat-sdk-adapter";

for (const name of ["AGENTPHONE_API_KEY", "AGENTPHONE_AGENT_ID", "AGENTPHONE_WEBHOOK_SECRET"]) {
  if (!process.env[name]) throw new Error(`Set ${name}`);
}
const agentphone = createAgentPhoneAdapter({
  apiKey: process.env.AGENTPHONE_API_KEY!,
  agentId: process.env.AGENTPHONE_AGENT_ID!,
  webhookSecret: process.env.AGENTPHONE_WEBHOOK_SECRET!,
});

export const chat = new Chat({
  userName: "my-bot",
  adapters: { agentphone },
  state: createMemoryState(),
});

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

Save the setup as `lib/chat.ts`. Set `AGENTPHONE_API_KEY`, `AGENTPHONE_AGENT_ID`, and `AGENTPHONE_WEBHOOK_SECRET` on the server. Signature verification only runs when a webhook secret is configured; fail deployment if any required variable is missing.

For a Next.js App Router endpoint, save this as `app/api/webhook/route.ts`:

```typescript
import { chat } from "../../../lib/chat";
export async function POST(request: Request) {
  return chat.webhooks.agentphone(request);
}
```

Point your AgentPhone [webhook](/docs/documentation/guides/webhooks) at that route. Save the secret returned by registration. This example uses in-memory Chat SDK state for local development; use a supported durable state adapter for multi-instance or serverless deployments. Handle subscribed messages as well as new mentions:

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

## iMessage reactions

The AgentPhone adapter supports iMessage tapbacks — send and receive `love`, `like`, `dislike`, `laugh`, `emphasize`, and `question`:

```typescript
await chat.getAdapter("agentphone").addReaction(threadId, messageId, "love");
```

Inbound reactions fire the standard `onReaction` handler — no special handling required.

## Voice call transcripts

When a call ends, the transcript arrives as a Chat SDK message with the full text, a summary, and call metadata:

```typescript
chat.onNewMention(async (thread, message) => {
  const raw = message.raw;
  if (raw && typeof raw === "object" && "callId" in raw) {
    console.log("Completed call:", raw.callId);
    if ("summary" in raw && typeof raw.summary === "string") console.log(raw.summary);
    if ("durationSeconds" in raw && typeof raw.durationSeconds === "number") {
      console.log("Duration (seconds):", raw.durationSeconds);
    }
    if ("transcript" in raw && Array.isArray(raw.transcript)) {
      for (const turn of raw.transcript) {
        if (turn && typeof turn === "object" && typeof turn.content === "string") {
          console.log(turn.content);
        }
      }
    }
  }
});
```

This adapter processes completed-call notifications; it does not supply live voice turn responses. Use [hosted voice or a voice webhook](/docs/documentation/guides/calls#voice-modes) for the conversation itself. A follow-up SMS is a separate send and needs outbound SMS readiness.

## Links

* npm: [`@agentphone/chat-sdk-adapter`](https://www.npmjs.com/package/@agentphone/chat-sdk-adapter)
* [GitHub repo](https://github.com/AgentPhone-AI/chat-sdk-adapter)