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) β€” accepts s, m, h, d (e.g., 30s, 10m, 1h, 2d). Invalid formats are rejected.

  • Countdown formatting β€” formatCountdown turns milliseconds into Hh Mm Ss strings shown in the embed.

  • Winner selection β€” pickWinners shuffles entrants (simple random sort) and slices to the requested number of winners. It only considers non-bot users who reacted. (Because it uses sort(() => 0.5 - Math.random()) this is a simple shuffle β€” good for small giveaways.)

  • Ticker / live countdown β€” startTicker edits 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 at endAt.

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, sets ended = 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.json and 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 sets endAt = now + extra. It unpauses the giveaway and restarts the ticker. Invalid duration formats are rejected. Saves changes and confirms.

Notes

  • Editing duration adds a fresh period from now (it does not extend relative to previous endAt unless you calculate that externally). The code calls startTicker again 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

  • pause sets paused = true and writes to disk. The ticker will stop editing while paused.

  • resume clears paused and (as implemented) sets endAt = Date.now() + 60000 β€” i.e., it gives a 1-minute buffer and restarts the ticker. Save and confirm.

Important

  • The resume code currently resets endAt to 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: UTC and Entry emoji: πŸŽ‰). This is a simple informational response.


Storage & persistence

  • Giveaways are persisted in data/giveaways.json and 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 persists endAt but 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 Reactions and Read Message History so 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 where ended === false and paused === 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 endAt to 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