Skip to content

Bot Send (HTTP API)

The Bot Send API lets an external service post messages into any chat the bot has been added to, using a single bearer token. Messages appear under the bot’s identity (name, avatar), not the human who created the bot.

DirectionBot → chat
AuthAuthorization: Bearer vifbot_<token>
TransportPOST over HTTPS (application/json)
Typical use caseAI agents, assistants, automations that need a persistent identity across multiple chats

Pick a bot when the sender needs a reusable identity — one token can post into any chat the bot has been added to, and messages render with the bot’s name and avatar. If you just need to post an alert into a single chat without an identity, an Incoming Webhook is simpler. If your bot also needs to receive messages and react, pair this with Bot Receive.

import { Steps } from ‘@astrojs/starlight/components’;

  1. Open the DonutChat app → BotsCreate bot.
  2. Enter a name, a unique username, and an optional description. Tap Create.
  3. DonutChat shows the bot’s token (starts with vifbot_). Copy it — the token is shown only once.
  4. Add the bot to a chat: open the chat → BotsAdd bot → pick your bot.
  5. Repeat step 4 for every chat the bot should be able to post into.

import { Aside } from ‘@astrojs/starlight/components’;

POST https://api.donutchat.com/bots/v1/messages
HeaderValue
AuthorizationBearer vifbot_<token>
Content-Typeapplication/json
{
"chat_id": 1234,
"content": "Standup starts in 5 minutes.",
"username": "Standup Bot",
"avatar_url": "https://example.com/bot-avatar.png"
}
FieldTypeRequiredNotes
chat_idint64yesID of the target chat. The bot must already be a member.
contentstringyesMessage body. Max 4000 UTF-8 bytes (multi-byte characters like CJK or emoji count as multiple bytes).
usernamestringnoPer-message override of the bot’s display name.
avatar_urlstringnoPer-message override of the bot’s avatar URL.

import { Tabs, TabItem } from ‘@astrojs/starlight/components’;

Terminal window
curl -X POST \
"https://api.donutchat.com/bots/v1/messages" \
-H "Authorization: Bearer vifbot_YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"chat_id": 1234,
"content": "Standup starts in 5 minutes."
}'
const TOKEN = process.env.VIFBOT_TOKEN;
const response = await fetch('https://api.donutchat.com/bots/v1/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
chat_id: 1234,
content: 'Standup starts in 5 minutes.',
}),
});
if (!response.ok) {
const err = await response.json();
throw new Error(`${err.error}: ${err.message}`);
}
const { message_id, chat_id } = await response.json();
console.log('Posted message', message_id, 'to chat', chat_id);

Success — HTTP 200:

{
"ok": true,
"message_id": 98765,
"chat_id": 1234
}

Error — HTTP 4xx or 5xx:

{
"ok": false,
"error": "<code>",
"message": "<human-readable>"
}
HTTP statuserror codeMeaningWhat to do
400invalid_jsonBody was not valid JSONSend a well-formed JSON body
400missing_chat_idchat_id is missing or not positiveProvide a valid int64 chat_id
400missing_contentcontent field is empty or missingProvide a non-empty content string
400content_too_longcontent exceeds 4000 bytesSplit or shorten the message
401unauthorizedToken is missing, invalid, or the bot has been disabledConfirm the Authorization header shape; re-enable the bot in the app if it was deactivated; regenerate the token if compromised
403not_in_chatBot is not a member of the target chatAdd the bot to the chat first
405method_not_allowedUsed a method other than POSTUse POST
500send_failedInternal error while delivering the messageRetry with exponential backoff
  • Message size: content is capped at 4000 UTF-8 bytes. Multi-byte characters (CJK, emoji) can hit the cap below 4000 visible characters; if you send rich content, size on Buffer.byteLength(s, 'utf8') before posting.
  • Identity override precedence: per-request username / avatar_url → bot’s configured defaults. Requests with neither field use the bot’s defaults.
  • Trigger mode does not gate manual sends. A bot configured with trigger_mode: manual or mention still accepts direct POST /bots/v1/messages calls. Trigger mode only governs auto-replies driven by Bot Receive events.
  • Token format: bot tokens start with vifbot_. Anything else is not a valid bot token.
  • Per-chat membership is required every time. Creating a bot does not auto-add it to any chat.
  • Incoming Webhooks — simplest one-way post into a specific chat, no identity.
  • Bot Receive — receive real-time chat events so your bot can react.