Velt
Bots that read, reply, mention, and start threads in Velt's anchored comments across editors, canvases, PDFs, and video, mapping Velt organizations, documents, comment annotations, and comments to the Chat SDK Channel/Thread/Message model.
Install
pnpm add @veltdev/chat-sdk-adapterQuick start
import { Chat } from "chat";
import { createMemoryState } from "@chat-adapter/state-memory";
import { createVeltAdapter, type VeltAdapter } from "@veltdev/chat-sdk-adapter";
const bot = new Chat<{ velt: VeltAdapter }>({
userName: "Velt Bot",
adapters: {
velt: createVeltAdapter({
apiKey: process.env.VELT_API_KEY,
webhookSecret: process.env.VELT_WEBHOOK_SECRET,
botUserId: "velt-bot",
botUserName: "Velt Bot",
}),
},
state: createMemoryState(),
});
bot.onNewMention(async (thread, message) => {
await thread.post(`Hi ${message.author.fullName}! How can I help?`);
});The adapter maps Velt documents to Chat SDK channels, comment annotations to Chat SDK threads, and individual comments to messages, so the rest of the Chat SDK API (subscriptions, handlers, posts, reactions) works exactly the same as with any other adapter.
Configuration
Prop
Type
Platform setup
- Create a Velt account and copy your API key.
- Add a bot user to your organization (
POST /v2/users/addwithuserId: "velt-bot") so it can post and appears in the @-mention list. - Configure webhooks (Velt Console → Configurations → Webhook Service, or
POST /v2/workspace/webhookconfig/update) and subscribe to:comment.addcomment_annotation.addcomment.reaction_addcomment.reaction_delete
- Copy the signing secret (
whsec_...for Advanced/v2 webhooks) intowebhookSecret.
Point your Velt webhook URL at the route that forwards requests to bot.webhooks.velt (see Webhook events).
Webhook events
| Event | Role |
|---|---|
comment.add | Drives Chat SDK message processing |
comment_annotation.add | First comment of a new thread |
comment.reaction_add | Drives reaction handlers |
comment.reaction_delete | Drives reaction handlers |
import { after } from "next/server";
import { bot } from "@/lib/bot";
export const runtime = "nodejs"; // raw body + crypto; not edge
export async function POST(request: Request) {
return bot.webhooks.velt(request, {
waitUntil: (task) => after(() => task),
});
}Velt has two webhook systems and the adapter verifies both: Advanced (v2) with Svix-style HMAC-SHA256 (whsec_..., default) and Basic (v1) with an Authorization: Basic <token> header (set webhookVersion: "v1"). Invalid requests return 401. Passing waitUntil lets work continue after the response is sent in serverless environments like Vercel.
ID encoding
- Thread ID:
velt:{organizationId}:{documentId}:{annotationId} - Channel ID:
velt:{organizationId}:{documentId}
encodeThreadId
adapter.encodeThreadId(data: {
organizationId: string;
documentId: string;
annotationId: string;
}): string;const encoded = adapter.encodeThreadId({
organizationId: "my-org",
documentId: "doc-1",
annotationId: "NHR5sMWU7YmTv2HJ1nVC",
});
// "velt:my-org:doc-1:NHR5sMWU7YmTv2HJ1nVC"decodeThreadId
adapter.decodeThreadId(threadId: string): {
organizationId: string;
documentId: string;
annotationId: string;
};Each segment is URL-encoded, so ids may safely contain :. Throws if the format is invalid.
Message format
Velt Comments are stored as commentHtml, so the adapter converts between Velt HTML and the Chat SDK's mdast AST (VeltFormatConverter). Inbound {{userId}} mention tokens are normalized to readable @Name. Each parsed Message.raw also carries lightweight document context (documentName, documentUrl, anchoredText) so bots can ground replies.
Supported: paragraphs with bold, italic, code, strikethrough, links, and @mentions.
Flattened to plain text / paragraphs: headings, lists, code blocks, tables, and card payloads (rendered as fallback text). Interactivity is not preserved.
Reactions
Reading reactions (onReaction) works on all Velt plans.
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 PermissionError. To enable reaction writes, provide selfHostingConfig.reactionsService (a self-hosted reactions service backed by your own database).
Examples
- Live demo: open the Velt tiptap comments demo, leave a comment, and @-mention Velt Bot to see a streaming AI reply (runs the AI bot below).
- Velt Chat SDK Bot: a Next.js bot that replies to @-mentions in Velt comment threads.
- Velt Chat SDK AI Bot: the same stack with a streaming Claude reply flow.
- Full walkthrough: Get started with a Chat SDK bot using Velt.
Feature support
Messaging
| Feature | Supported |
|---|---|
| Post message | |
| Edit message | |
| Delete message | |
| File uploads | By reference |
| Streaming | |
| Scheduled messages |
Rich content
| Feature | Supported |
|---|---|
| Card format | Flattened to text |
| Buttons | |
| Link buttons | |
| Select menus | |
| Tables | Flattened to text |
| Fields | |
| Images in cards | |
| Modals |
Conversations
| Feature | Supported |
|---|---|
| Slash commands | |
| Mentions | Users |
| Add reactions | Bot writes: self-hosted |
| Remove reactions | Bot writes: self-hosted |
| Typing indicator | |
| DMs | |
| Ephemeral messages | |
| User lookup | resolveUsers |
| Parent subject | |
| Native client | |
| Custom API endpoint |
Message history
| Feature | Supported |
|---|---|
| Fetch messages | |
| Fetch single message | |
| Fetch thread info | |
| Fetch channel messages | |
| List threads | |
| Fetch channel info | |
| Post channel message |