Messages and DMs
Send, edit and delete messages, attach files and respect recipient privacy.
Examples use the bot client from Your first bot.
Send a message
Use a stable clientId when a message is part of a retried business operation. Reuse that ID for retries of the same message, never for different messages. The SDK creates an ID if you omit it.
const message = await bot.send(channelId, 'Your order is ready.', {
clientId: `order-${orderId}-ready`,
});
await bot.edit(channelId, message.id, 'Your order has been collected.');Files and replies
Upload files through the bot SDK before using imageUrl or fileUrl in a message. Arbitrary external attachment URLs are not accepted. Add replyToId to quote a message. Text is limited to 8,000 characters. Replace report.zip with a file on the machine running your bot.
| Action | Permission |
|---|---|
| Send and edit your own messages | Send Messages |
| Upload a file | Attach Files |
| Read recent channel history | Message Content |
| Delete someone else’s message | Manage Messages |
import { readFile } from 'node:fs/promises';
const bytes = await readFile('./report.zip');
const uploadedFile = await bot.upload(new Blob([bytes]), 'report.zip');
await bot.send(channelId, 'Here is your report.', { fileUrl: uploadedFile.url });Change only what you need
Edits accept text, embeds, uploaded images/files and controls. Omitted fields stay unchanged. Clear embeds or controls with an empty list, and clear text or an uploaded file with null / None. The result still needs text, an embed, a file or a control.
embeds:null / embeds=None is invalid. Use an empty list. Legacy positional text/control edits remain supported.
await bot.edit(channelId, message.id, { embeds: [] });
await bot.edit(channelId, message.id, {
content: 'Here is the corrected file.', fileUrl: uploadedFile.url,
});Direct messages
Open the conversation first, then send to its returned ID. Starting a DM requires an eligible shared-server installation and the recipient’s consent. Blocks and bot DM preferences always apply. There is no bulk-DM endpoint.
const conversation = await bot.openDM(userId);
await bot.sendDM(conversation.id, 'Here is the update you requested.', {
clientId: `requested-${requestId}`,
});Edit or delete your DM messages
Use editDM / edit_dm with the conversation and message IDs. It accepts the same rich fields as a channel edit. deleteDM / delete_dm removes the bot’s own DM message. Current blocks, contact preferences and bot DM grants still apply.
Load older messages
History pages contain up to 100 messages, oldest first. Keep nextCursor as a string and pass it as before to load an older page. A null / None cursor means there are no older messages. Message Content permission and current channel access are required.
const page = await bot.history(channelId, { limit: 50 });
if (page.nextCursor) {
const older = await bot.history(channelId, { before: page.nextCursor, limit: 50 });
console.log('Older messages:', older.messages.length);
}Plan for rate limits
REST admission starts at 120 requests per minute per bot. Channel slow mode and ordinary message limits still apply. Bot DMs allow ten sends per minute per recipient; opening conversations has additional hourly and daily limits. Uploads are capped at 10 MiB and five attempts per bot per day. These are ceilings, not a throughput promise.
Do not retry moderation or other unkeyed actions blindly. Use the API contract for exact limits and keep external side effects idempotent.