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

# Chat SDK Adapter

> Build a bot that reads and responds to Velt comment threads using the Chat SDK and @veltdev/chat-sdk-adapter.

[Chat SDK](https://chat-sdk.dev) lets you build cross-platform bots whose logic
stays platform-agnostic. The
[`@veltdev/chat-sdk-adapter`](https://www.npmjs.com/package/@veltdev/chat-sdk-adapter)
connects a Chat SDK bot to **Velt comment threads**, so the same bot can run on
Velt, Slack, Discord, and every other Chat SDK adapter.

When a user @-mentions your bot or reacts in a comment thread, Velt sends a
webhook to your app and the bot responds by replying in the thread, following the
conversation, and reacting to events.

> [!TIP]
>
> **Try it live:** open the [tiptap comments demo](https://sample-apps-tiptap-comments-demo.vercel.app),
> leave a comment, and @-mention **Velt Bot**, and it streams an AI reply back into the
> thread. Source: the [`nextjs-velt-ai-bot`](https://github.com/velt-js/velt-chat-sdk-adapter/tree/main/examples/nextjs-velt-ai-bot) sample app.

## How it maps

| Chat SDK | Velt |
| - | - |
| Thread | Comment annotation inside a document |
| Message | Comment |
| Channel | Document |
| `onNewMention` | A comment that @-mentions the bot |
| `onReaction` | A reaction added to / removed from a comment |
| `thread.post()` | A reply added to the comment thread |

## Quickstart

**1. Install the adapter and Chat SDK**

```bash theme={null}
npm install @veltdev/chat-sdk-adapter chat @chat-adapter/state-memory
```

**2. Add your environment variables**

Create a `.env.local` file with your Velt API key, the bot's auth token, and
the webhook secret. You'll get the webhook secret in the final step.

```env .env.local theme={null}
VELT_API_KEY="your-velt-api-key"
VELT_AUTH_TOKEN=""
VELT_WEBHOOK_SECRET="whsec_..."
VELT_ORGANIZATION_ID="your-organization-id"
```

`VELT_AUTH_TOKEN` is optional; if omitted, the adapter generates a bot token
from your API key, scoped to `VELT_ORGANIZATION_ID`.

**3. Create a user database**

The `resolveUsers` function converts Velt user ids into display names.

```tsx app/database.ts theme={null}
export const BOT_USER_ID = "velt-bot";
export const BOT_USER_NAME = "Velt Bot";

const USERS = [
  { userId: "user-1", name: "Charlie Layne" },
  { userId: "user-2", name: "Mislav Abha" },
  { userId: BOT_USER_ID, name: BOT_USER_NAME },
];

export function getUser(userId: string) {
  const user = USERS.find((u) => u.userId === userId);
  return user ? { name: user.name } : undefined;
}

export function resolveUsers({ userIds }: { userIds: string[] }) {
  return userIds.map((id) => getUser(id));
}
```

**4. Create the bot instance**

Create a Chat instance with the Velt adapter and register handlers for
mentions and reactions.

```tsx app/bot.ts theme={null}
import { Chat } from "chat";
import { createMemoryState } from "@chat-adapter/state-memory";
import { createVeltAdapter, type VeltAdapter } from "@veltdev/chat-sdk-adapter";
import { BOT_USER_ID, BOT_USER_NAME, resolveUsers } from "./database";

let chatSingleton: Chat<{ velt: VeltAdapter }> | null = null;

export function getChat() {
  if (chatSingleton) return chatSingleton;

  const chat = new Chat<{ velt: VeltAdapter }>({
    userName: BOT_USER_NAME,
    adapters: {
      velt: createVeltAdapter({
        botUserId: BOT_USER_ID,
        botUserName: BOT_USER_NAME,
        organizationId: process.env.VELT_ORGANIZATION_ID,
        resolveUsers,
      }),
    },
    state: createMemoryState(),
  });

  // Reply when a user @-mentions the bot.
  chat.onNewMention(async (thread, message) => {
    await thread.subscribe();
    await thread.post(`Hi ${message.author.fullName}! How can I help?`);
  });

  // React to reactions (read-only on the managed backend).
  chat.onReaction(async (event) => {
    console.log(
      `${event.user.fullName} ${event.added ? "added" : "removed"} ${event.emoji}`,
    );
  });

  chatSingleton = chat;
  return chat;
}
```

> [!NOTE]
>
> The bot is created lazily so importing the module doesn't require
> credentials at build time. Credentials are read on the first webhook
> request.

**5. Create the webhook endpoint**

The bot processes incoming comments and reactions through this route. It must
run on the Node.js runtime because signature verification needs the raw body
and Node's `crypto`.

```tsx app/api/webhooks/velt/route.ts theme={null}
import { after } from "next/server";
import { getChat } from "../../../bot";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

export async function POST(request: Request) {
  return getChat().webhooks.velt(request, { waitUntil: (p) => after(() => p) });
}
```

On Vercel, use `waitUntil` from `@vercel/functions` instead of `after`.

**6. Set up the Velt webhook**

1. Expose your endpoint publicly (e.g. with a tunnel during development).
2. In the Velt Console → **Configurations → Webhook Service**, set the
   endpoint URL and enable these events:
   * `comment.add`
   * `comment_annotation.add`
   * `comment.reaction_add`
   * `comment.reaction_delete`
3. Copy your **webhook secret** (`whsec_...`) into `VELT_WEBHOOK_SECRET`.

You can also configure the webhook via
[`POST /v2/workspace/webhookconfig/update`](https://velt.dev/docs/api-reference/rest-apis/v2/workspace/webhookconfig-update).

Now when users @-mention your bot or react to messages in comment threads,
your bot responds automatically.

## Webhook versions

The adapter supports both Velt webhook systems:

* **Advanced (v2):** verified with Svix-style HMAC-SHA256 using the `whsec_...`
  secret. This is the default.
* **Basic (v1):** verified against the `Authorization: Basic <token>` header.
  Set `webhookVersion: "v1"` and pass that token as `webhookSecret`.

## Reactions

Reading reactions (`onReaction`) works on all Velt plans.

> [!WARNING]
>
> **Writing** reactions (`addReaction` / `removeReaction`) is not supported on
> the managed Velt backend, because there is no managed REST endpoint to add a
> reaction as a user, so these methods throw a clear error. To enable reaction writes,
> pass a `selfHostingConfig.reactionsService` (a self-hosted reactions service
> backed by your own database) and the adapter delegates to it.

## What to read next

* [Live demo: tiptap comments](https://sample-apps-tiptap-comments-demo.vercel.app) (@-mention **Velt Bot**)
* Sample apps: [AI streaming bot](https://github.com/velt-js/velt-chat-sdk-adapter/tree/main/examples/nextjs-velt-ai-bot) · [greeting bot](https://github.com/velt-js/velt-chat-sdk-adapter/tree/main/examples/nextjs-velt-bot)
* [Chat SDK documentation](https://chat-sdk.dev)
* [`@veltdev/chat-sdk-adapter` on npm](https://www.npmjs.com/package/@veltdev/chat-sdk-adapter)
* [Velt Webhooks](https://velt.dev/docs/webhooks/advanced.md)
* [Velt REST API: Comments](https://velt.dev/docs/api-reference/rest-apis/v2/comments-feature/comments/add-comments.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.