Vercel Chat SDK
Build agents on iMessage and SMS with Vercel's Chat SDK, powered by Linq.
Chat SDK is Vercel’s framework for building chat agents. Write your bot’s logic once and run it across platforms through adapters. The Linq adapter is the iMessage and SMS channel — your agent sends and receives texts, media, and tapback reactions over Apple Messages and SMS, using the same handlers you’d write for any other platform.
The adapter is built and maintained by Linq and lives at github.com/linq-team/linq-chat-sdk.
Install
Section titled “Install”npm install @linqapp/chat-sdk-adapter chatchat is Vercel’s Chat SDK core; @linqapp/chat-sdk-adapter is the Linq channel.
Quickstart
Section titled “Quickstart”import { createLinqAdapter } from "@linqapp/chat-sdk-adapter";import { Chat } from "chat";
const chat = new Chat({ userName: "mybot", adapters: { linq: createLinqAdapter({ apiKey: process.env.LINQ_API_KEY!, signingSecret: process.env.LINQ_WEBHOOK_SECRET!, }), },});
chat.onDirectMessage(async (thread, message) => { await thread.subscribe(); await thread.post(`you said: ${message.text}`);});
chat.onReaction(["thumbs_up"], async (event) => { await event.thread.post("appreciate the tapback 🫡");});Then route Linq webhooks to the adapter from any fetch-style handler:
// e.g. a Next.js / Nitro / Hono POST routeexport default async (request: Request) => chat.webhooks.linq(request);Configuration
Section titled “Configuration”| Option | Required | Description |
|---|---|---|
apiKey | yes | Your Linq API key. |
signingSecret | yes | The signing secret from your webhook subscription. Inbound requests are verified with HMAC-SHA256 over {timestamp}.{body} with replay protection. |
baseURL | no | Override the API base URL. |
Receiving messages
Section titled “Receiving messages”The adapter is webhook-driven. Create a webhook subscription pointing at your route and subscribe to at least:
message.receivedreaction.addedreaction.removed
See webhook events for the full payload reference. Any event type the adapter doesn’t handle is acknowledged with a 200 and ignored.
What’s supported
Section titled “What’s supported”The adapter maps Linq onto the Chat SDK’s thread/message/reaction model, so standard APIs (thread.post, thread.subscribe, onDirectMessage, onNewMessage, onReaction) work unchanged.
- Text — inbound and outbound, in DMs and group chats.
- Media — inbound images, audio, and files arrive as attachments; outbound
attachments/filesare sent as media parts (public HTTPS URLs by reference, or pre-uploaded for larger/raw files). - Reactions — iMessage tapbacks map to Chat SDK emoji both ways (see below).
- Typing indicators — supported in DMs (Linq rejects typing in groups).
- Edits — outbound message text can be edited.
Streaming is buffered (recipients see one final message). Stickers, message deletion, and modals have no iMessage equivalent and are not supported.
Reactions
Section titled “Reactions”Standard tapbacks map to normalized Chat SDK emoji in both directions:
| Linq tapback | Chat SDK emoji |
|---|---|
like | thumbs_up |
dislike | thumbs_down |
love | heart |
laugh | laugh |
emphasize | exclamation |
question | question |
Custom emoji reactions pass through the default resolver (e.g. 👍 → thumbs_up); anything unmapped falls back to the raw emoji. See reactions for how Linq models tapbacks.
Thread IDs
Section titled “Thread IDs”Thread IDs are stable and always take the form linq:{chatId}, so a conversation maps to the same Chat SDK thread whether it first arrives via webhook or API.
Example app
Section titled “Example app”The repo includes a full example — a server running one AI bot across Linq, Telegram, and WhatsApp from a single set of handlers.