Scripting Guide
Lesson 2: Events and Payloads
The 15 events agents can subscribe to, the exact payload shape each one delivers, and how to pick the right one.
One agent, one event
When you create an agent you bind it to exactly one event from a fixed list. The event determines two things: when your function runs and what the payload argument contains. Getting the payload shape right is most of the work of writing a correct agent.
The event catalog
| Event | Fires when | Payload shape |
|---|---|---|
messageCreate | A user (not a bot) sends a message | The message object itself |
messageUpdate | A user edits a message | { before, after } (before is a light snapshot, after is a full message) |
messageDelete | A user's message is deleted | The deleted message object |
guildMemberAdd | Someone joins the server | { member, guild } |
guildMemberRemove | Someone leaves or is kicked | { member, guild } |
guildMemberUpdate | Nickname, roles, or timeout changes | { before, after, guild } |
guildBanAdd | Someone is banned | { user, reason, guild } |
guildBanRemove | Someone is unbanned | { user, reason, guild } |
channelCreate | A channel is created | { channel, guild } |
channelDelete | A channel is deleted | { channel, guild } |
roleCreate | A role is created | { role, guild } |
roleDelete | A role is deleted | { role, guild } |
messageReactionAdd | A user adds a reaction | { reaction, emoji, message, user, guild } |
messageReactionRemove | A user removes a reaction | { reaction, emoji, message, user, guild } |
interactionCreate | A button, menu, or modal your agents created is used | The interaction object |
Message and reaction events never fire for actions performed by bots, and interactionCreate never fires for GuildScript's own commands and menus. You still write if (message.author.bot) return; in message agents as a safety habit, but the platform already prevents the worst feedback loops.
Reading a payload
Payload objects are plain data snapshots with async action methods attached. For example, a guildMemberAdd payload:
export async function onJoin(payload) {
// This event's payload has two top-level keys: member and guild.
const { member, guild } = payload;
// Plain data you can read directly:
// member.id, member.displayName, member.user.username,
// member.joinedTimestamp, member.roleIds, ...
// guild.id, guild.name, guild.memberCount, ...
// Async lookups go through the guild object:
const channel = await guild.channels.fetch("123456789012345678");
if (!channel || channel.error) return; // bad ID or missing access
await channel.send(
"Welcome " + member.displayName + "! You are member #" + guild.memberCount + "."
);
}Before-and-after events
messageUpdate and guildMemberUpdate deliver a before and an after so you can detect what changed. before is a plain snapshot (data only); after carries the action methods.
export async function onMemberUpdate({ before, after, guild }) {
if (before.nickname === after.nickname) return; // something else changed
const log = await guild.channels.fetch("123456789012345678");
if (!log || log.error) return;
await log.send(
after.user.username + " changed nickname: " +
(before.nickname ?? "(none)") + " -> " + (after.nickname ?? "(none)")
);
}Choosing the right event
- Want to respond to text people type?
messageCreate. - Want welcome flows or autoroles?
guildMemberAdd. - Want goodbye logs?
guildMemberRemove. - Want moderation logging?
messageDelete,messageUpdate,guildBanAdd,guildMemberUpdate. - Want reaction roles or starboards?
messageReactionAddandmessageReactionRemove. - Want clickable UI (buttons, menus, modals)? Build it from any event, handle it with
interactionCreate(Lesson 7).
Common pitfalls
- Destructuring the wrong shape.
const { member } = payloadworks onguildMemberAddbut isundefinedonmessageCreate, where the payload is the message itself. - Expecting events that are not in the list. There is no voiceStateUpdate, no presenceUpdate, and no scheduled/timer event. If it is not in the table above, an agent cannot subscribe to it.
- Comparing `before` methods.
beforein update events is data only; call actions onafter. - Reacting to deletes with replies. On
messageDeletethe message is gone; you cannot reply to it. Send to a channel instead.
Exercise
Create a goodbye.js agent on guildMemberRemove that posts <username> left the server to a log channel of your choice. Then create a second agent on guildBanAdd that posts the ban reason (payload.reason may be null; print no reason given in that case).