Direct Messages
Initiate DM conversations with users programmatically.
Open direct message conversations with users using bot.openDM(). For globally recognizable user IDs, the adapter is automatically inferred from the ID format.
DM behavior
DMs behave slightly differently from channel messages:
- Direct message handlers — if you register
onDirectMessage, every incoming DM routes there beforeonSubscribedMessage,onNewMention, and pattern handlers. This keeps DM-centric flows like WhatsApp conversations, Telegram DMs, and web chat on one consistent handler. - Mention fallback — if no
onDirectMessagehandlers are registered, DMs continue through normal routing. Unsubscribed DMs are treated as mentions, so existingonNewMentionbots keep working without requiring the user to @-mention the bot. - Per-conversation threading — Each top-level DM starts a new conversation. Thread replies within a DM continue the same conversation, giving you the same per-thread isolation as channels.
Handle incoming DMs
bot.onDirectMessage(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});Open a DM
From an Author object
The most common pattern — use the author from an incoming message:
bot.onSubscribedMessage(async (thread, message) => {
if (message.text === "DM me") {
const dmThread = await bot.openDM(message.author);
await dmThread.post("Hello! This is a private message.");
}
});From a user ID
Pass a user ID string directly. The adapter is inferred from the ID format:
const dmThread = await bot.openDM("U1234567890"); // Slack| Format | Platform |
|---|---|
U... / W... | Slack |
29:... | Teams |
users/... | Google Chat |
| Numeric ID | Discord or Telegram |
Numeric IDs can be ambiguous when multiple numeric-ID adapters are registered. For platforms whose user IDs are not globally distinguishable, call the adapter directly and wrap the returned thread ID with bot.thread().
const threadId = await bot.getAdapter("whatsapp").openDM("15551234567");
const dmThread = bot.thread(threadId);Check if a thread is a DM
bot.onSubscribedMessage(async (thread, message) => {
if (thread.isDM) {
await thread.post("This is a private conversation.");
}
});