Giveaway Commands
Updated 3/30/2026
What the giveaway system does (short)
Starts timed giveaways that post an embed members can enter by reacting with π. The bot updates the embed with a live countdown and selects winners when the giveaway ends.
Stores giveaways persistently in a JSON file so giveaways survive restarts (
data/giveaways.json). The code writes updates immediately on change.Moderators can end/reroll/cancel/edit/pause/resume giveaways and list active ones. The bot also exposes a small settings summary.
Important helpers & mechanics (implementation notes)
Duration parsing (
ms) β acceptss,m,h,d(e.g.,30s,10m,1h,2d). Invalid formats are rejected.Countdown formatting β
formatCountdownturns milliseconds intoHh Mm Ssstrings shown in the embed.Winner selection β
pickWinnersshuffles entrants (simple random sort) and slices to the requested number of winners. It only considers non-bot users who reacted. (Because it usessort(() => 0.5 - Math.random())this is a simple shuffle β good for small giveaways.)Ticker / live countdown β
startTickeredits the giveaway embed every ~5 seconds to update time remaining. When time expires it fetches π reactions, picks winners, marks the giveaway ended, saves the file, and updates the embed with winners. The ticker stops if the giveaway is ended or paused.Note: timers are in-process intervals. While the code persists
endAt, running countdown intervals are not re-hydrated automatically on bot restart β if the bot restarts a running giveaway will remain in storage but live countdown edits rely on the in-memory ticker.
Reaction entry β after starting a giveaway the bot reacts to the message with π so users can click to enter. That reaction is used to gather entrants. Make sure the bot has
Add Reactions.
Commands β purpose, syntax, examples, notes
All subcommands are under /giveaway. Below each subcommand shows syntax and behavior.
/giveaway start <duration> <winners> <prize>
Purpose β Start a new giveaway posted by the bot in the current channel.
Syntax
/giveaway start duration:1h winners:2 prize:"2 months Nitro"
Behavior
Validates duration format. Creates an embed with prize, winners count, and time left, posts it, reacts with π and persists an object in
data/giveaways.json. Starts the ticker to update the embed periodically and automatically end the giveaway atendAt.
Quick example
/giveaway start duration:1h winners:1 prize:"Free Nitro"
/giveaway end <message_id>
Purpose β Force-end a giveaway and immediately pick winners.
Syntax
/giveaway end message_id:123456789012345678
Behavior
Fetches the giveaway and the original message, gathers users who reacted with π (filters out bots), picks winners using
pickWinners, setsended = true, saves, edits the embed with the winners and replies with a confirmation.
/giveaway reroll <message_id>
Purpose β Select new winners for a giveaway that has already ended.
Syntax
/giveaway reroll message_id:123456789012345678
Behavior
Validates giveaway exists and is ended; fetches reaction users, picks new winners, and reports the new winners in the interaction reply (does not edit the original embed in this implementation).
/giveaway cancel <message_id>
Purpose β Cancel an active giveaway (removes it from storage).
Syntax
/giveaway cancel message_id:123456789012345678
Behavior
Deletes the giveaway entry from
giveaways.jsonand replies with confirmation. It does not delete the original Discord message (you can remove it manually if desired).
/giveaway list
Purpose β List active (not ended) giveaways.
Syntax
/giveaway list
Behavior
Returns a list of active giveaways showing prize and relative time remaining (Discord relative timestamp) or βNo active giveaways.β Helpful to find message IDs or quick audit.
/giveaway edit <message_id> <field> <new_value>
Purpose β Edit a running giveawayβs prize or duration.
Syntax
/giveaway edit message_id:123456789012345678 field:prize new_value:"New Prize"
/giveaway edit message_id:123... field:duration new_value:"30m"
Behavior
prizeβ updates the prize text.durationβ calculates extra milliseconds from the new value and setsendAt = now + extra. It unpauses the giveaway and restarts the ticker. Invalid duration formats are rejected. Saves changes and confirms.
Notes
Editing
durationadds a fresh period from now (it does not extend relative to previousendAtunless you calculate that externally). The code callsstartTickeragain so the countdown resumes.
/giveaway pause <message_id> and /giveaway resume <message_id>
Purpose β Temporarily pause and later resume a giveaway.
Syntax
/giveaway pause message_id:123...
/giveaway resume message_id:123...
Behavior
pausesetspaused = trueand writes to disk. The ticker will stop editing while paused.resumeclearspausedand (as implemented) setsendAt = Date.now() + 60000β i.e., it gives a 1-minute buffer and restarts the ticker. Save and confirm.
Important
The resume code currently resets
endAtto 1 minute from resume rather than restoring the original remaining time β this is a design choice in the implementation (you may want a version that restores the previously stored remaining time).
/giveaway settings
Purpose β Show default giveaway settings.
Syntax
/giveaway settings
Behavior
Replies with a short summary (the current code replies:
Timezone: UTCandEntry emoji: π). This is a simple informational response.
Storage & persistence
Giveaways are persisted in
data/giveaways.jsonand saved every time the code modifies the giveaways object. On first access a file is created if missing. This makes giveaway entries durable over restarts. However, live countdown intervals (setInterval) are in-memory only and are not automatically re-spawned on restart β the code persistsendAtbut does not rehydrate timers on boot. Consider this when running long giveaways across deployments.
Permissions & required bot abilities
The bot must have Send Messages, Embed Links, and Add Reactions in the channel where giveaways run (it reacts with π and edits embeds). If you plan to pin/delete messages automatically or manage roles for winners youβd also need the corresponding Discord permissions.
Best practices
Start giveaways in a dedicated channel (e.g.,
#giveaways) to keep moderation simple and avoid message clutter.Test short giveaways (e.g.,
1m) in a staff channel to confirm bot permissions and winner selection work as expected.When pausing/resuming be aware resume currently gives a 1-minute endAt buffer β if you need the original remaining duration restored, update the code to store the remaining time before pause.
Keep prize text concise so it fits cleanly into the embed description the bot edits.
If you need more robust rerolls or audit trails, log entrants to a separate audit file or modify winner selection to be deterministic with a seed (the current method shuffles randomly).
Troubleshooting checklist
No one can enter β confirm the bot has
Add ReactionsandRead Message Historyso it can react and read existing reactions. The bot adds the π reaction immediately after posting the giveaway.Giveaway countdown not updating β countdowns are performed by an in-memory interval (
startTicker). If the bot restarts the interval stops; the giveaway still exists (persisted) but you wonβt see live edits until a ticker is restarted (e.g., by editing the giveaway or re-running startTicker). Consider adding a startup routine that re-spawns tickers for giveaways whereended === falseandpaused === false.Winners appear to repeat or none selected β the code fetches reaction users and filters out bots. If nobody reacted (or only bots reacted) the winner list will be empty and the embed will say βNo valid entries.β Also note the simple shuffle/pick logic β for large entry sets you may want a more robust random sampling.
Resume gives only 1 minute β resuming resets
endAtto 1 minute from resume by design. If you need a different behavior, change the resume logic to restore the previous remaining time.
Quick moderator cheat-sheet
/giveaway start duration:1h winners:1 prize:"Free Nitro"
/giveaway end message_id:123456789012345678
/giveaway reroll message_id:123456789012345678
/giveaway cancel message_id:123456789012345678
/giveaway list
/giveaway edit message_id:123... field:prize new_value:"New Prize"
/giveaway edit message_id:123... field:duration new_value:"30m"
/giveaway pause message_id:123...
/giveaway resume message_id:123...
/giveaway settings