Skip to content
donutchat.com

Developer overview

Connect your own services to DonutChat over HTTPS and JSON. Post alerts into a chat, or build a bot that people can talk to.

  • Notifications: post build results, monitoring alerts or scheduled reports into a chat.
  • Bots: give your service its own name and picture. A bot posts in every chat it’s added to, receives what people send it, and replies in threads.
  • AI agents: stream an answer into a thread as it’s written, show progress while the agent works, and let people answer with buttons.
IntegrationDirectionWhat it doesCredential
Incoming webhookYour service to one chatPosts plain-text messages. No bot needed.Secret URL
Bot HTTP APIYour service to the bot’s chatsPosts messages and thread replies as the bot, updates a reply while it’s written, shows typing, and downloads files people share.Bot token
Event streamThe bot’s chats to your serviceSends people’s messages and thread replies, reactions, and notices when the bot is added to or removed from a chat, over a WebSocket.Bot token
Event webhooksThe bot’s chats to your serviceSends people’s messages, thread replies and reactions to your HTTPS endpoint.Signing secret
Interactive cardsInside a bot’s thread repliesShows facts and up to 4 buttons; selecting a button posts a reply that mentions the bot.Bot token

An incoming webhook is the quickest way to post into one chat. Use a bot when your service needs one identity across several chats, needs to hear from people, or answers in threads.

You set up both in the DonutChat apps. In a group, the owner and managers create incoming webhooks in Chat info on iPhone, Android or the web app; in a feed chat, only the owner can. The desktop app can’t manage webhooks. You create bots in My Bots in any app (desktop app: Settings > App > My bots).

APIURL
Bot HTTP APIhttps://api.donutchat.com/bots/v1/
Event streamwss://api.donutchat.com/bots/v1/stream
Incoming webhooksThe URL you copy from the app, such as https://donutchat.com/webhooks/v1/{webhook_id}/{token}
EndpointPurpose
POST /bots/v1/messagesPost a message in a chat
GET /bots/v1/chatsList the chats the bot belongs to
POST /bots/v1/typingShow or clear a typing indicator
POST /bots/v1/thread-repliesReply in a thread
POST /bots/v1/thread-replies/streamUpdate a reply while it’s written, then finish it
POST /bots/v1/thread-replies/activityReport progress while a reply is written
GET /bots/v1/streamReceive events over a WebSocket
GET /bots/v1/chats/{chat_id}/messages/…/attachments/{attachment_id}/contentDownload a file someone shared

The APIs can’t create bots, add them to chats or change their trigger modes; you do that in the apps. They also can’t edit or delete posted messages (a bot can only update its own thread replies), add reactions, upload files, or read chat history or member lists.

  • Send request bodies as JSON with Content-Type: application/json.
  • Bot requests need an Authorization: Bearer header with the bot’s token. See Authentication.
  • A successful request returns HTTP 200 and a JSON object with "ok": true. (File downloads return the file itself, and the event stream upgrades to a WebSocket.)
  • An error returns a JSON object with an error code for your code to check and a message for people:
{
"ok": false,
"error": "not_in_chat",
"message": "Bot is not a member of this chat"
}

A few responses aren’t JSON:

  • A request with the wrong HTTP method gets 405 with an empty body and an Allow header that names the right method.
  • A URL that doesn’t match any endpoint gets 404 with the text 404 page not found.
  • While DonutChat is briefly unavailable, for example during maintenance, requests can get 503 with the text server is not ready. Retry with backoff.

Endpoints ignore fields they don’t recognize, except POST /bots/v1/thread-replies/activity, which rejects them. No endpoint takes an idempotency key, so retrying a request that timed out can post the same message twice.

Call the APIs from your server. The HTTP endpoints don’t send CORS headers, so cross-origin calls from a browser fail, and a token in browser code is visible to anyone who opens the page.

Message and reply text can be up to 80,000 UTF-8 bytes. Limits on sender names and typing status text are in bytes too. DonutChat counts the bytes of the text itself, not of its escaped JSON form. An English letter, digit or space is 1 byte. Accented letters and characters from other scripts take 2 to 4 bytes each. An emoji usually takes 4 bytes, and combined emoji such as flags take 8 bytes or more.

To check a length, use Buffer.byteLength(text, 'utf8') in Node.js or len(text.encode('utf-8')) in Python.

Chat, message and reply IDs are 64-bit integers. Send them as JSON numbers: a quoted ID such as "chat_id": "1234" is rejected with 400 invalid_json (invalid_activity on POST /bots/v1/thread-replies/activity).

Chat, message and reply IDs can be larger than JavaScript’s Number.MAX_SAFE_INTEGER (2^53 − 1), and chat IDs usually are. JSON.parse() and response.json() round such numbers without any error, so requests that use the rounded ID fail or point at the wrong message:

JSON.parse('{"chat_id": 9007199254740993}').chat_id; // 9007199254740992

In Node.js 22 or later, read large integers as BigInt and write them back as plain JSON numbers:

const parseJSON = (text) =>
JSON.parse(text, (key, value, context) =>
Number.isInteger(value) && !Number.isSafeInteger(value) ? BigInt(context.source) : value);
const toJSON = (value) =>
JSON.stringify(value, (key, v) => (typeof v === 'bigint' ? JSON.rawJSON(v.toString()) : v));
const event = parseJSON('{"chat_id": 9007199254740993, "message_id": 5678}');
event.chat_id; // 9007199254740993n
toJSON({ chat_id: event.chat_id, content: 'Hi' }); // '{"chat_id":9007199254740993,"content":"Hi"}'

Small IDs stay ordinary numbers, so compare IDs with String(a) === String(b) and use String(id) to print them or use them as map keys. Python’s json module and 64-bit integer types in other languages keep IDs exact without extra work.

Guides: Connect a Hermes agent, Build and deploy notifications and Progress and stopping. Reference: Errors and Limits.