Discord Module
A Rawtoh bot in your Discord server — messages, reactions, roles, DMs and slash commands.
The Discord module adds the Rawtoh bot to your server. Everything that happens there — messages, reactions, members joining, slash commands — comes in as events, and your actions can post, react, hand out roles or answer a command.
Getting started
- Open the Discord module site and sign in with your Rawtoh account — same session as the dashboard
- Pick your organization and click Add to a Discord server. Discord asks which server to add the bot to; you need Manage Server there
- Back on the module site, click Install with Rawtoh. The server becomes a module instance in your organization. You need the owner role
Each server is its own instance, so a community server and a mod-team server can run side by side and be targeted with module("discord", "<instance>"). A server belongs to one organization at a time.
Channel, role, user and message IDs are Discord snowflakes. To copy one, enable Developer Mode in Discord (Settings → Advanced), then right-click a channel, role or user and choose Copy ID. channel.list and role.list return them too.
Events
| Event | Description |
|---|---|
message.create | A message is posted in the server (the bot's own messages excluded). Payload: id, channel_id, author, content, timestamp, reply_to |
message.delete | A message is deleted |
reaction.add | Someone reacts to a message. emoji is the character, or name:id for a custom emoji |
member.join | A member joins the server |
member.leave | A member leaves or is removed |
command.invoke | A member uses one of the server's slash commands. Payload: name, options, user, channel_id, token |
Events carry the whole server. To react in one channel only, filter on channel_id in the trigger:
import { event } from "rawtoh"
export default event.payload.channel_id === "123456789012345678"
&& event.payload.content.startsWith("!clip")What you can do
Messages
message.send— post in a channel, optionally as a reply withreply_to.@everyoneand@herenever pingmessage.edit/message.delete— edit or delete one of the bot's messagesmessage.react— add a reactiondm.send— send a direct message to a member of the server
Members and roles
member.get— a member with their rolesmember.add_role/member.remove_roleguild.get,channel.list,role.list— the server, its channels and its roles
Slash commands
command.create/command.update/command.delete— manage the server's commands by name. Options follow Discord's format (type 3 string, 4 integer, 5 boolean, 6 user, 7 channel)command.list/command.getcommand.reply— answer a command with thetokenfrom its event
Slash commands, step by step
Commands are declared once per server, on the module site under Commands, or from an action:
import { module } from "rawtoh"
await module("discord").request("command.create", {
name: "stats",
description: "Today's stream stats",
options: [{ type: 3, name: "period", description: "day or week", required: false }],
})When a member types /stats, Discord shows "Rawtoh is thinking…" and the module emits command.invoke. A trigger picks the command by name:
import { event } from "rawtoh"
export default event.payload.name === "stats"and the action answers with command.reply, which replaces the "thinking…" placeholder. You have 15 minutes; after that Discord shows "did not respond". message.send would post a separate message and leave the placeholder hanging.
import { event, module, storage } from "rawtoh"
const subs = (await storage.get("subs-today")) ?? 0
await module("discord").request("command.reply", {
token: event.payload.token,
content: `${subs} new subs today, asked by ${event.payload.user.username}`,
})Example: welcome new members
A trigger on member.join and this action:
import { event, module } from "rawtoh"
await module("discord").request("message.send", {
channel_id: "123456789012345678",
content: `Welcome <@${event.payload.user.id}>! Grab a role in #roles.`,
})
await module("discord").request("member.add_role", {
user_id: event.payload.user.id,
role_id: "987654321098765432",
})Example automations
- Stream goes live on Twitch → post the announcement in #live with the title and category
- Slash command →
/clipcreates a Twitch clip and replies with the link - Reaction added → give the matching role for a reaction-roles message
- Message in #suggestions → react with 👍 and 👎 to open the vote
- Cron every morning → post yesterday's recap in #stats