Skip to content
donutchat.com

Send messages

Post messages as your bot in the chats it belongs to, find those chats, and show people that the bot is working. To answer inside a thread or show a reply while it’s written, see Thread replies and streaming.

Every request needs the bot’s token in an Authorization: Bearer header. See Authentication.

POST https://api.donutchat.com/bots/v1/messages

Posts a new message in the chat as the bot. The bot must be in the chat.

FieldTypeRequiredDescription
chat_idintegerYesThe chat to post in. The bot must be an active member.
contentstringYesThe message text, up to 80,000 UTF-8 bytes. Can’t be empty.
content_typestringNoTX for plain text (the default) or MD for Markdown. Not case-sensitive.
usernamestringNoSender name for this message. Defaults to the bot’s name.
avatar_urlstringNoSender picture for this message, as an absolute http or https URL. Defaults to the bot’s picture.

The Node.js and Python examples read the token and chat ID from the DONUT_BOT_TOKEN and DONUT_CHAT_ID environment variables:

Terminal window
curl -X POST https://api.donutchat.com/bots/v1/messages \
-H "Authorization: Bearer donutbot_YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"chat_id": 1234,
"content": "**Deploy finished**\n\n- API: healthy\n- Web: healthy",
"content_type": "MD"
}'

A successful request returns HTTP 200 with the new message’s ID:

{
"ok": true,
"message_id": 5678,
"chat_id": 1234
}
  • The message shows the bot’s name and picture, or your username and avatar_url, never the name of the bot’s owner.
  • Members see the message right away. Members who don’t have the app open get a push notification unless they muted the chat. That includes the bot’s owner.
  • The bot’s trigger mode doesn’t limit posting. A bot set to Manual only can still post.
  • Bots never receive messages from bots, including their own, so a post can’t trigger another bot.
  • There’s no idempotency key. Retrying a request that timed out can post the message twice.
  • This endpoint can’t reply in a thread, attach files, or edit or delete a message. To answer in a thread, use thread replies.
HTTPerrorCause
400invalid_jsonThe body isn’t valid JSON, or a field has the wrong type, such as chat_id sent as a string.
400missing_chat_idchat_id is missing, zero or negative.
400missing_contentcontent is missing or empty.
400content_too_longcontent is over 80,000 UTF-8 bytes.
400invalid_avatar_urlavatar_url isn’t an absolute http or https URL.
400invalid_content_typecontent_type isn’t TX or MD.
401unauthorizedThe Authorization header is missing or malformed, the token is wrong or was regenerated, or the bot is paused.
403not_in_chatThe bot isn’t an active member of the chat, or the chat was deleted.
405None (empty body)The method isn’t POST.
500send_failedThe sender name is longer than 32 bytes, or something went wrong on the server.
503None (plain text)DonutChat is briefly unavailable. Retry with increasing delays.
GET https://api.donutchat.com/bots/v1/chats

Returns the chats the bot belongs to, most recently added first. There are no parameters.

Terminal window
curl https://api.donutchat.com/bots/v1/chats \
-H "Authorization: Bearer donutbot_YOUR_TOKEN_HERE"
{
"ok": true,
"chats": [
{
"chat_id": 1234,
"chat_name": "Release team",
"chat_type": "group",
"is_active": true,
"member_count": 6
}
],
"total": 1
}
FieldDescription
chats[].chat_idThe chat’s ID.
chats[].chat_nameThe chat’s name.
chats[].chat_typegroup, direct, feed or self. A private conversation that someone opens from the bot’s profile is a group chat.
chats[].is_activefalse if the bot is switched off in this chat. It can’t post there.
chats[].member_countThe number of members in the chat.
totalThe number of chats the bot belongs to. Can be more than 100.
  • The list has at most 100 chats and no pagination. If total is more than 100, you get the 100 most recently added.
  • Chats the bot was removed from aren’t listed.
  • Errors: 401 unauthorized for token problems and 500 list_failed if the list couldn’t be loaded.
POST https://api.donutchat.com/bots/v1/typing

Shows people in a chat that the bot is typing, with an optional short status, while it prepares a message.

FieldTypeRequiredDescription
chat_idintegerYesThe chat to show the indicator in. The bot must be an active member.
is_typingbooleanNotrue (the default) shows the indicator. false clears it.
status_textstringNoShort status, such as Checking the build. Up to 80 UTF-8 bytes.
Terminal window
curl -X POST https://api.donutchat.com/bots/v1/typing \
-H "Authorization: Bearer donutbot_YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{"chat_id": 1234, "status_text": "Checking the build"}'
{
"ok": true,
"chat_id": 1234
}
  • When the bot is the only one typing, Android, the desktop app and the web app show its username followed by status_text. The iPhone app shows only that the bot is typing.
  • The indicator doesn’t last. On iPhone it disappears about 10 seconds after the last request, so send the request again every 3 to 9 seconds while the bot works. Send "is_typing": false when you’re done.
  • DonutChat shows at most one start request per bot and chat every 3 seconds. Extra requests still return 200 but have no effect. Requests with "is_typing": false always go through.
  • Typing isn’t saved and doesn’t send notifications.
  • The indicator belongs to the chat, not to a thread. To show progress on a reply in a thread, use a streaming thread reply.
HTTPerrorCause
400invalid_jsonThe body isn’t valid JSON, or a field has the wrong type.
400missing_chat_idchat_id is missing, zero or negative.
400status_text_too_longstatus_text is over 80 UTF-8 bytes. The message says “80 characters”, but bytes are counted.
401unauthorizedThe header or token isn’t valid, or the bot is paused.
403not_in_chatThe bot isn’t an active member of the chat.
500typing_failedThe typing event couldn’t be sent.
content_typeWhat readers see by default
TXPlain text. Markdown characters appear as typed.
MDFormatted Markdown: headings, bold, italic, links, lists (including task lists), block quotes, code blocks, tables and horizontal rules.
  • In the iPhone and Android apps, images in MD messages appear inline. The desktop app shows the image’s alt text with an Open image link instead.
  • In the iPhone, Android and desktop apps, readers choose how text appears on their device under Message display: As sent (the default), Formatted or Plain text. With As sent, MD messages are formatted and TX messages are plain text. Readers can also switch a single message with View formatted or View plain text.
  • Push notifications and the chat list show MD messages as plain text, cut at 240 characters.
  • An MD message can include interactive cards. An answer to a card in the main chat goes into that message’s thread. The web app and older app versions turn off the buttons on cards in the main chat. Desktop app versions without card support show the card’s JSON as a code block.