Event Requests
Allow your community to submit watch party event requests through a web form! Server moderators can approve or deny submissions, and approved events are automatically created as Discord Scheduled Events.
Overview
The Event Request System provides:
- 🔐 Discord OAuth Login - Secure authentication with Discord, kept in a signed cookie
- 📝 Web-based Form - User-friendly event submission interface
- 💬 Guidance on the Form - Helper text under each field, rewritten per server (see below)
- 🖼️ Artwork Suggestions - Backdrops and posters for the typed title, to pick and crop
- 📺 Where to Watch - Each title's streaming services, shown to moderators and added to the event (see below)
- ✅ Moderation Queue - Review and approve/deny requests
- 🎉 Auto-create Events - Approved events become Discord Scheduled Events
- ⏱️ Rate Limiting - Prevents spam (1 request per 5 minutes per user)
- 🌐 Dedicated Deployment - Each website serves one specific Discord server
How It Works
- User visits your event request form at your configured website
- User logs in with Discord (OAuth authentication)
- System validates guild membership:
- Checks if user is a member of the target server
- Non-members see error with invite link (if configured)
- Only server members can proceed
- User submits event details (with your server's guidance under each field, and artwork suggested for the title):
- Simple Mode (default): Title, description, time only. Moderators assign channels during approval.
- Advanced Mode (opt-in): Full control including channel selection from admin-configured whitelists.
- System revalidates membership at submission (prevents edge case of leaving server after login)
- Request appears in your moderation channel with Approve/Deny buttons, and where the title streams
- Moderator clicks a button to approve or deny
- If approved, Discord Scheduled Event is created automatically, its description ending with where to watch
Security: Guild Membership Required
The bot validates that users are actual members of your Discord server both when they log in and when they submit the form. Non-members see a friendly error message with an invite link to join. This prevents spam from users outside your community.
Default Behavior
By default, event requests use Simple Mode: users submit event ideas and moderators handle channel logistics. This reduces decision fatigue and simplifies the user experience. Enable Advanced Mode with /eggshen-config-events event-requests allow-user-channel-selection allow:true to let users select channels.
Deployment Model
One Website = One Discord Server
Each event request form deployment is dedicated to one specific Discord server. If you host the bot for multiple servers, each server should deploy its own instance of the web form on their own domain.
Example:
- moviefans.example.com → Movie Fans Discord Server
- yourdomain.com → Your Discord Server
Setup Requirements
Prerequisites
This feature requires:
- A web server to host the event request form (e.g., yourdomain.com)
- Discord Client Secret from the Developer Portal
- Web server configuration (e.g., nginx)
- Additional environment variables
Step 1: Discord Developer Portal Setup
CRITICAL: OAuth Redirect URI
You MUST add the redirect URI to Discord Developer Portal BEFORE testing! Without this, users will get "Invalid OAuth2 redirect_uri" errors when trying to login.
- Go to Discord Developer Portal
- Select your bot application
- Navigate to OAuth2 section
- Click Add Redirect and enter:
- For local testing:
http://localhost:3000/api/auth/discord/callback - For production:
https://yourdomain.com/api/auth/discord/callback - The URL MUST match your
OAUTH_REDIRECT_URIenvironment variable exactly
- For local testing:
- Click Save Changes (don't forget this!)
- Copy your Client Secret from the OAuth2 page (keep it secure!)
Step 2: Environment Variables
Add these to your .env file:
# Required for event requests
DISCORD_CLIENT_SECRET=your_client_secret_here
# API Configuration
API_PORT=3000
OAUTH_REDIRECT_URI=https://yourdomain.com/api/auth/discord/callback
FORM_URL=https://yourdomain.com
ALLOWED_ORIGINS=https://yourdomain.com
# Powers the moderator "Crop Image" link button — see Moderator section below
EVENT_CROP_LINK_SECRET=your_generated_secret_here
PUBLIC_BOT_URL=https://yourdomain.com
# Optional: signs the form's login cookie. Leave it out to derive one from
# DISCORD_CLIENT_SECRET; set it to be able to sign everyone out on its own.
SESSION_SECRET=your_generated_secret_hereLocal Testing
For local testing, use:
OAUTH_REDIRECT_URI=http://localhost:3000/api/auth/discord/callback
FORM_URL=http://localhost:PORT
ALLOWED_ORIGINS=http://localhost:PORTStep 3: Deploy Web Form
The bot includes a web form in the /public folder. Deploy these files to your web server:
public/index.html- Event request formpublic/app.js- Form logicpublic/style.css- Styling
Required Configuration:
- Copy
public/config.example.jstopublic/config.js - Set
GUILD_IDto your Discord server's Guild ID:
window.EGG_SHEN_CONFIG = {
GUILD_ID: 'YOUR_GUILD_ID_HERE', // Change this!
};public/config.js is gitignored, so a future git pull on your server will never overwrite it.
Finding Your Guild ID
Run /eggshen-config-events event-requests get-link in your Discord server to see your Guild ID.
Example deployment:
- Copy
config.example.jstoconfig.jsinpublic/and setGUILD_ID - Upload
/publiccontents (including your newconfig.js) tohttps://yourdomain.com - Ensure the domain matches your environment variables
Reverse Proxy Upload Size Limit
If you're proxying /api/ to the bot through nginx (or a similar reverse proxy) rather than exposing the bot's API port directly, set that proxy's own request body size limit — nginx defaults to 1MB, which silently rejects most real event images before they ever reach the bot. The bot's own upload limit is 8MB, so configure the proxy to allow at least that much:
location /api/ {
client_max_body_size 10M;
proxy_pass http://localhost:3000;
# ...
}Without this, image uploads on the web form fail silently — the browser gets a proxy-level 413 Request Entity Too Large error page instead of the bot's normal JSON error response, and nothing shows up in the bot's own logs since the request never reached it.
Step 4: Configure Your Server
Event Requests Disabled by Default
Event requests are disabled by default for all servers. You must enable them using the toggle command below. Until enabled, the event request form will show a "disabled" message to users.
Use /eggshen-config-events event-requests commands in your Discord server:
1. Enable event requests (required first step):
/eggshen-config-events event-requests toggle enabled:true2. Configure required settings (the website URL is set with /eggshen-config-website, not an event-requests subcommand):
/eggshen-config-events event-requests moderation-channel channel:#event-requests
/eggshen-config-events event-requests server-name name:"Your Server Name"
/eggshen-config-website url url:https://yourdomain.com3. Optional settings:
/eggshen-config-events event-requests invite-url url:https://discord.gg/yourserverStep 5: Get Your Link
/eggshen-config-events event-requests get-linkThis shows your configured Form URL, plus a reminder to set GUILD_ID in public/config.js on your web server if you haven't already.
Share your Form URL with your community!
Configuration Commands
All configuration is done via /eggshen-config-events event-requests subcommands:
View Current Settings
/eggshen-config-events event-requests viewShows your current configuration including the event request link.
Enable/Disable
/eggshen-config-events event-requests toggle enabled:true
/eggshen-config-events event-requests toggle enabled:falseTurn event requests on or off for your server.
Default State
Event requests are disabled by default. You must explicitly enable them with enabled:true before users can submit requests. When disabled, the event request form shows a message telling users the feature is not available.
Set Moderation Channel
/eggshen-config-events event-requests moderation-channel channel:#event-requestsChoose where event requests will be sent for approval. Must be a text channel.
Set Server Display Name
/eggshen-config-events event-requests server-name name:"My Awesome Server"This name appears on the event request form.
Set Website URL
/eggshen-config-website url url:https://yourdomain.comThe website where your event request form is hosted. This lives on /eggshen-config-website (not under event-requests) because the same site URL is shared by other web features; check it with /eggshen-config-website view.
Set Invite Link (Optional)
/eggshen-config-events event-requests invite-url url:https://discord.gg/yourserverDiscord invite link shown on the form. Leave empty to hide.
Allow/Disallow Voice Requests
/eggshen-config-events event-requests allow-voice-requests allow:true
/eggshen-config-events event-requests allow-voice-requests allow:falseControl whether users can request voice/stage channels for events. When disabled, all events will be text-channel only.
Use cases for disabling:
- Server primarily uses text chat for watch parties
- Voice channels are reserved for specific purposes
- Simplify the event request form
Get Configuration Summary
/eggshen-config-events event-requests get-linkShows your form URL and reminds you to configure the GUILD_ID in your web form deployment.
Optional: Choose Simple or Advanced Mode
Simple Mode (default):
/eggshen-config-events event-requests allow-user-channel-selection allow:falseUsers submit basic event details only (title, description, time). The form hides channel selectors and shows: "Moderators will select the channels when approving your event." Moderators assign channels during approval.
Best for:
- New communities still establishing channel structure
- Servers with dedicated event coordinators
- Reducing decision fatigue for casual users
- Simplifying the submission process
Advanced Mode (opt-in):
/eggshen-config-events event-requests allow-user-channel-selection allow:trueUsers select specific text/voice channels from admin-configured whitelists (see below). Form shows Location field (required) and optional Voice Channel checkbox.
Best for:
- Experienced communities with established channels
- Power users who understand channel structure
- Community-driven events where users know best location
- Servers where moderators prefer not to assign channels
Recommended Default
Keep Simple Mode enabled by default. It provides the best experience for most users by removing the complexity of channel selection. Only switch to Advanced Mode if your community specifically requests more control.
Optional: Whitelist Allowed Channels
Advanced Mode Only
Channel whitelisting only applies when Advanced Mode is enabled. In Simple Mode, moderators assign channels during approval, so whitelisting is not needed.
By default (in Advanced Mode), users can select from all text channels and all voice/stage channels in your server. You can restrict this to specific channels:
Whitelist text channels:
/eggshen-config-events event-requests set-allowed-text-channels channel-ids:"123456,789012,345678"Whitelist voice channels:
/eggshen-config-events event-requests set-allowed-voice-channels channel-ids:"111222,333444"Allow all channels (reset to default):
/eggshen-config-events event-requests set-allowed-text-channels channel-ids:"all"
/eggshen-config-events event-requests set-allowed-voice-channels channel-ids:"all"When to Use Channel Whitelisting
Good use cases:
- Limit events to dedicated watch party channels (#movie-night, #tv-night)
- Exclude announcement or admin-only channels
- Simplify dropdown for servers with 50+ channels
- Prevent accidental selection of inappropriate channels
How to get Channel IDs:
- Enable Developer Mode in Discord Settings → Advanced
- Right-click any channel → Copy Channel ID
- Paste IDs comma-separated (no spaces)
Independent Controls
Text and voice whitelists are independent:
- You can limit text channels while allowing all voice channels
- Or vice versa
- Or limit both
- Empty list (default) = all channels of that type allowed
User Experience
Submitting a Request
- Visit the link provided by server admins
- Click "Login with Discord" to authenticate
- Fill out the form:
- Event title (required)
- Description (optional)
- Event image (optional) - Upload an image file, paste an image URL, or pick artwork suggested for your title — either way you'll get a chance to crop it
- Location (required) - Text channel for the watch party
- Voice channel (optional) - Check the box to add voice/stage channel
- Start date and time (required)
- End date and time (optional)
- Frequency (optional: Once, Daily, Weekly, Biweekly, Monthly)
- Each field has a short note on what the server wants; a server can rewrite these for its own community
- Click "Submit Request"
- Wait for moderator approval
Artwork Suggestions
Once you've typed the title, the form suggests artwork for it from TMDB: wide backdrops first (they fit an event cover with little cropping), then a couple of posters. If several titles match, like the Fargo film and the show, each gets its own row with its year, so you pick from the right one. Nothing is chosen for you. Click one to open it in the crop tool, or ignore them and use your own image.
Picking artwork also tells the bot exactly which title you mean, so the moderators' 📺 Where to watch line uses that title instead of guessing from what you typed. Trying different suggestions doesn't count against the upload limit; the one you keep is uploaded when you submit.
Event Image
Picking a file (PNG, JPEG, GIF, or WebP, up to 8MB) or pasting a direct image URL and clicking Fetch & Crop both upload it right away and load it into a crop tool, pre-framed to match Discord's event cover shape. Providing neither is fine too — moderators can always add or change the image when they approve your request (see below).
Drag to adjust the framing as much as you like — this only updates the preview, not the server, so there's no limit on how many times you re-adjust it. The final framing is uploaded once you submit the form. If you change your mind about the image entirely, click Change Image to clear it and pick a different file or URL.
Channel Selection
Location is where the watch party chat happens (text channel, always required).
Voice channel is optional and only shown if enabled by server admins. Check the box if you want to include a voice/stage channel for the event.
Time Zones
The form automatically detects and shows your own local timezone next to the time fields (e.g. "Times shown in your local timezone: America/Los_Angeles"), so type the start/end time as it would appear on your own clock — no conversion needed. Once approved, the event is created correctly for everyone: Discord shows scheduled events in each viewer's own local timezone automatically, the same way it handles every other timestamp, so a moderator (or anyone else) sees the right time on their own clock too, regardless of where they are.
For Moderators
When a request is submitted:
- Request appears in moderation channel with all details, including 📺 Where to watch: which of your server's streaming services carry the title (see Where to Watch)
- Shows location (text channel) and voice channel (if requested)
- Approval buttons vary based on request:
- Text-only request: ✅ Approve, ✏️ Edit, or ❌ Deny
- Request with voice: ✅ Approve Both, 💬 Text Only, ✏️ Edit, or ❌ Deny
- Choose approval type:
- Approve Both → Creates voice channel event with text channel coordination
- Text Only → Creates text-only event (removes voice channel from request)
- Edit → Opens a form to correct the title, description, or start/end time — saving it immediately approves the request too (see below)
- Deny → Opens a form for an optional reason, then removes the request without creating an event
Editing a Request (Immediately Approves It)
If a submitter's title is wrong or the description needs more detail, click ✏️ Edit. This opens a form pre-filled with the current title and description, along with the event's start/end time — update any field and submit.
The Edit form also includes an optional Image URL field. Use it to add an image to a request that didn't include one, or to replace whatever image the submitter provided (upload or URL) — an image URL entered here always wins over the submitter's. Leaving it blank doesn't clear an existing image; there's no separate "remove image" action, only "optionally override it."
Saving the edit both updates the request and approves it in the same step — there's no separate Approve click needed afterward:
- If the request already has a text channel (the submitter picked one, or advanced mode isn't in use), saving creates the event right away, using a voice channel too if one was requested.
- If no channel is set yet, saving shows the same channel-selection step Approve normally shows — pick a channel there and the event is created from your edited title/description.
If you want to review the edit before it goes live, or need to change something Edit doesn't cover, deny the request instead and ask the submitter to resubmit — editing is meant for quick corrections a moderator is comfortable approving outright, not a staging step.
The Edit form also includes Start Time (UTC) and End Time (UTC, optional) fields, pre-filled with the request's current schedule. Both use a strict YYYY-MM-DD HH:mm 24-hour format (e.g. 2026-09-15 20:00) and are always interpreted as UTC — not your local time or the server's — since a modal has no timezone picker; convert to UTC before typing a value. Leaving End Time blank means the event has no set end time. Start Time must be in the future and, if both are set, End Time must be after Start Time — an invalid or past value is rejected with an explanation and nothing is saved. Discord's own event page (the confirmation's Event URL) still displays the final schedule correctly in every viewer's own local timezone automatically — this is Discord's own behavior (every scheduled event is created in the creator's local time and shown back to each viewer in theirs, with no server-wide timezone concept at all), not something this bot computes.
Cropping or Replacing the Image
Every event request in the moderation channel shows a 🖼️ Crop Image button alongside Approve/Edit/Deny (if a bot address — this server's bot URL, or the bot's PUBLIC_BOT_URL — and EVENT_CROP_LINK_SECRET are configured — see setup guide). Clicking it gives you a private Open Crop Page link. The page needs no login (the link itself is what authorizes you), and has the same image options as the request form:
- Adjust the framing of whatever image the submitter provided, whether they uploaded a file or pasted a URL
- Upload a different image file and crop that instead
- Paste an image URL and click Fetch & Crop to crop that instead
- Add an image to a request that didn't have one at all
Each link is just for you, works for 30 minutes, and is used up by one save. Click Crop Image again any time for a new one. Once you save a crop, it becomes the image used when the request is approved. The Edit button's Image URL field still works for a quick swap, but an image set there is used as-is, without cropping.
Cropping From the True Original
The crop page always loads the submitter's original, uncropped image — not their already-cropped result — so you can reframe it freely without compounding crops on top of crops. If you upload or fetch a different image instead, that becomes the new original for any future re-crop.
The moderation-channel embed shows a 🖼️ Image field (✅ Uploaded, 🔗 Linked (URL), or ❌ None) so you can see at a glance whether a request has an image before deciding whether to crop, override, or leave it as-is.
Denying with a Reason
Clicking ❌ Deny opens a form with an optional reason field. Whatever you enter (or leave blank) is:
- Shown on the moderation-channel embed, so other moderators can see why without asking
- Sent as a direct message to the person who submitted the request, so they're not left wondering what happened
If the bot can't DM the submitter (for example, they have server DMs disabled), the denial still completes — you'll just see a note that the notification couldn't be delivered.
Everyone Sees What Happened
Approving or denying a request updates the original request's message in place (title, color, and buttons change to reflect the outcome) — but a silent edit to an old message is easy to miss if you weren't already looking right at it. On top of that, the bot posts a new message to the moderation channel announcing the outcome:
- Approved: who approved it and a link to the newly created event
- Denied: who denied it, and the reason if one was given
This applies to every way a request gets approved — the Approve buttons, picking a channel after Approve, and saving an edit — so the whole moderation team can see what happened and why without having to notice an old message changed.
This is on by default. To turn it off (only the original request message updates, no separate announcement):
/eggshen-config-events event-requests announce-decisions enabled:falseAnnouncing Approved Events to Members
The decision message above goes to the moderation channel, which members usually can't see. To also post a 📅 New watch party message where they can, pick a destination:
/eggshen-config-events event-requests announcement-channel where:The event's own channel
/eggshen-config-events event-requests announcement-channel channel:#watch-parties where:A specific channelThe event's own channel posts in the text channel where the watch party takes place. The post links the event (so Discord shows its card with the Interested button) and credits the submitter without pinging them. It's off by default; where:Off turns it back off.
If the bot can't post there (usually a missing Send Messages permission), the event is still created, and the approving moderator's reply says the announcement failed and why.
Moderator Permissions
Only members with Manage Events permission or Administrator/Moderator roles can approve/deny/edit requests.
Rate Limiting
Built-in protection against spam:
- 1 request per 5 minutes per user (by IP address)
- 10 channel lookups per minute per user
- 5 image uploads per 5 minutes per user (by IP address)
- Sessions expire after 24 hours
Limits are scoped per domain, not just per IP — if you run a dev deployment alongside production (see Multiple Servers below), submitting on one domain doesn't use up the other domain's limit, even though both are served by the same bot process.
Security Features
- ✅ Discord OAuth authentication (no passwords stored)
- ✅ Session-based login (24-hour expiration), with a signed cookie: it can't be edited or forged to claim another member
- ✅ Requests are made as whoever is logged in; the form can't submit on someone else's behalf
- ✅ HTTP-only secure cookies
- ✅ CORS protection
- ✅ Rate limiting
- ✅ Request expiration (7 days)
- ✅ Uploaded images are validated by type (PNG/JPEG/GIF/WebP) and capped at 8MB
- ✅ Uploaded images are automatically deleted ~90 days after their event's date has passed (or sooner if the request is never approved)
Customizing for Your Server
Making It Your Own
The event request system is designed to be easily customized:
- Set
GUILD_IDinpublic/config.js(copied frompublic/config.example.js) - Point to your Discord server - Configure server name and invite - Use
/eggshen-config-events event-requestscommands - Adjust the guidance - the form comes with helper text under each field, an intro and a footer;
/eggshen-config-events event-requests guidancerewrites any of it for your server (see below) - Customize styling - Edit
public/style.cssto match your branding - Deploy to your domain - Host on any web server (Apache, nginx, Netlify, Vercel, etc.)
Guidance on the Form
Every form tells people what to expect before they request. The defaults cover it in general terms:
- Intro: Discord login only confirms membership; check the Events tab first; moderators review every request
- Event title: pick something that fits the server; add the release year
- Description: say where to watch it; services most people have get more people joining
- Event image: upload and crop a cover; moderators may adjust it
- Date & time: schedule within the next 2 weeks; you'll be the host and start the countdown
- Frequency: ask a moderator before setting up a recurring event
- Footer: questions go to a moderator
Rewrite any of it for your community:
/eggshen-config-events event-requests guidance part:page ← the intro at the top, the footer at the bottom
/eggshen-config-events event-requests guidance part:fields ← the text under the title, description, image, date & time, and frequencyEach opens a Discord form, filled in with what the form shows now. Empty a box to go back to the default, or type none to show nothing there. Lines starting with • or - become a list, **bold** is bold, and https:// links can be clicked. Guidance belongs to the server, so when one bot backs several sites, each site shows its own server's text.
For example, a horror server might put "Keep it horror or horror-adjacent." under the title, and name the channels its events use in the intro.
Where to Watch, on Each Request
Each request's title is looked up for where it streams, among the services your server cares about:
/eggshen-config-events event-requests streaming services:Shudder, AMC+, Tubi, Plex, Roku, Prime Video, Hulu, Peacock, HooplaModerators see it on the request; approving adds it to the event's description, with a link to every other place to watch. Free services are marked "(free)". It never guesses: no exact match, no line. See Configuration › Where to Watch for the details.
Multiple Servers (Advanced)
If you host the bot for multiple communities, each should deploy their own instance:
Server 1: Deploy to movienight.com with config.js → GUILD_ID = 'SERVER_1_ID'
Server 2: Deploy to gamenight.com with config.js → GUILD_ID = 'SERVER_2_ID'
Server 3: Deploy to bookclub.com with config.js → GUILD_ID = 'SERVER_3_ID'Each deployment is independent with its own:
- Domain/subdomain
- Guidance on the form and where-to-watch services (set per server in Discord)
config.js(gitignored, so a shared repo checkout never overwrites another deployment's Guild ID)- Custom branding and styling
- Separate Discord OAuth configuration
For Bot Hosts
If you're running the bot for multiple servers and want to offer event requests as a feature, provide each server with:
- Instructions to deploy the web form files
- Their specific Guild ID to set in
config.js - Discord OAuth setup guide
Local Testing
Want to test before deploying?
1. Start the Bot
The API server starts automatically:
npm startYou should see: ✓ API server listening on port 3000
2. Serve the Web Form
# Using Python
cd public && python3 -m http.server 8080
# OR using Node.js http-server
npx http-server public -p 80803. Configure for Testing
# .env
OAUTH_REDIRECT_URI=http://localhost:3000/api/auth/discord/callback
FORM_URL=http://localhost:PORT
ALLOWED_ORIGINS=http://localhost:PORTDon't forget to add http://localhost:3000/api/auth/discord/callback to Discord Developer Portal!
4. Test the Flow
- Copy
public/config.example.jstopublic/config.jsand setGUILD_IDto your test server's ID - Configure your test server:
# In Discord
/eggshen-config-events event-requests toggle enabled:true
/eggshen-config-events event-requests moderation-channel channel:#test-events
/eggshen-config-events event-requests server-name name:"Test Server"
/eggshen-config-website url url:http://localhost:PORT
# Check configuration
/eggshen-config-events event-requests view- Open
http://localhost:PORTin browser and test the full flow!
Troubleshooting
"Site can't be reached" Error
- ✅ Check if the bot is running (API server starts with bot)
- ✅ Verify
API_PORTin.env(default: 3000) - ✅ Check firewall rules if deployed to production
- ✅ Ensure the bot process is running with
pm2 statusor similar
"Guild not found" Error
- ✅ Verify the guild ID in the URL is correct
- ✅ Ensure the bot is a member of that server
- ✅ Check event requests are enabled:
/eggshen-config-events event-requests view
"Invalid OAuth2 redirect_uri" Error
Common Issue
This is the most common error when setting up event requests. It means Discord doesn't recognize your callback URL.
Solution:
- Go to Discord Developer Portal
- Select your application → OAuth2 → Redirects
- Add the exact URL from your
OAUTH_REDIRECT_URIenvironment variable - Click Save Changes (required!)
- Wait 1-2 minutes for changes to propagate
- Try logging in again
Common mistakes:
- ❌ Forgetting to click "Save Changes" in Discord portal
- ❌ Using HTTP instead of HTTPS in production
- ❌ Typo in the URL (even
/callbackvs/callbacksmatters) - ❌ Port number mismatch
Validate your configuration:
npm run validate-oauthOAuth Redirect Mismatch
- ✅
OAUTH_REDIRECT_URIin.envmust exactly match Discord Developer Portal - ✅ Check for HTTP vs HTTPS mismatches
- ✅ Verify port numbers match
- ✅ Restart the bot after changing
.env - ✅ Run
npm run validate-oauthto check configuration
Requests Not Appearing
- ✅ Check moderation channel is set:
/eggshen-config-events event-requests view - ✅ Verify the bot's role has View Channel, Send Messages, and Embed Links in that specific channel — a channel-level permission override (common in mod-only channels) can block the bot even when its server-wide role looks correct
- ✅ Check bot logs for errors
"Failed to Create Event: Missing Permissions" on Approval
- ✅ The bot's role needs the server-wide Manage Events permission — this is separate from the moderation-channel permissions above and isn't something you can grant per-channel
- ✅ Server Settings → Roles → (the bot's role) → enable Manage Events, then retry the approval — no restart needed
CORS Errors
- ✅ Add your website URL to
ALLOWED_ORIGINSin.env - ✅ Restart the bot after changing environment variables
- ✅ Check browser console for specific CORS errors
Login Not Working
- ✅ Verify
DISCORD_CLIENT_SECRETis set correctly in.env - ✅ Check redirect URI matches in Discord Developer Portal
- ✅ Clear browser cookies and try again
- ✅ Check bot logs for OAuth errors
API Endpoints
The bot exposes these endpoints for the event request system:
| Endpoint | Method | Description |
|---|---|---|
/api/health | GET | Health check |
/api/guild-config/:guildId | GET | Get server configuration |
/api/auth/discord | GET | Start OAuth flow |
/api/auth/discord/callback | GET | OAuth callback handler |
/api/auth/session | GET | Check current session |
/api/auth/logout | POST | Logout user |
/api/channels/:guildId | GET | List voice/stage channels |
/api/event-request/upload-image | POST | Upload an event image ahead of submission (returns a token) |
/api/event-request | POST | Submit event request |
/crop/:requestId | GET | Moderator crop page (signed-token gated) |
/crop/:requestId/current-image | GET | The request's current image (its stored file, or its image link fetched), for pre-loading the cropper |
/crop/:requestId/fetch-image-url | POST | Fetch a pasted image URL for the cropper (signed token, not used up) |
/crop/:requestId/save | POST | Save a moderator's cropped image (single-use signed token) |
Best Practices
For Server Admins
- 📝 Test locally first before going live
- 🔒 Keep your client secret secure - never share it
- 📢 Share the link in an announcement channel
- 👀 Monitor the moderation queue regularly
- ⚙️ Set clear guidelines for acceptable events
For Web Hosting
- 🔐 Use HTTPS in production for security
- 🌐 Use a memorable domain that matches your community brand
- 📊 Monitor traffic and adjust rate limits if needed
- 💾 Back up your configuration regularly
- 🎨 Customize the styling to match your server's theme
Example Use Cases
Movie Watch Party Server
Server Name: "Friday Horror Nights"
Invite URL: https://discord.gg/horrorlovers
Website: https://horrornights.com
GUILD_ID: '1234567890123456789'Users submit horror movie requests for Friday watch parties.
Gaming Community
Server Name: "Speedrun Central"
Invite URL: https://discord.gg/speedruns
Website: https://speedrungaming.com
GUILD_ID: '9876543210987654321'Coordinate speedrun events and tournaments. Website: https://speedruncalendar.com
Users can request streaming/racing events in the server.
### Anime ClubServer Name: "Anime Watch Party" Invite URL: https://discord.gg/animewp Website: https://animewatchparty.com
Members submit anime screening requests for weekly viewings.
## Support
Need help setting this up? Check:
- [Technical Setup Guide](https://github.com/r3volution11/Egg-Shen-Bot/blob/main/EVENT_REQUEST_SETUP.md)
- [Bot Installation](./installation.md)
- [Configuration Guide](./configuration.md)
- [GitHub Issues](https://github.com/r3volution11/Egg-Shen-Bot/issues)
::: info Note
The Event Request System is an optional feature. Your bot works perfectly without it! This is for communities that want to formalize their event submission process.
:::