10-step playbook from 'create application in Dev Portal' to 'verified bot serving 100+ servers.' Real intent gates, real verification gotchas, real agent prompts.
Open in Dock→Developers shipping a public Discord bot
Building a Discord bot is easy in the first hour and brutally bureaucratic at the 100-server mark. Verification is required to grow past 75-100 servers, requires Privileged Gateway Intents approval, an ID verification, and a written description of every dangerous command the bot exposes. This playbook walks the 10 gates with the official Discord docs, the discord.js / discord.py snippets that work, and agent prompts for what agents do well: drafting the verification application, summarising commands, designing slash command argument schemas.
Outcome
Your Discord bot live, verified, with all required Privileged Intents approved, hosted with the right gateway resilience, and a path past the 100-server cap.
Time1-3 weeks (most of it Discord verification queue)DifficultyintermediateForDevelopers shipping a public Discord bot beyond a single server.
Top to bottom. Each step has tasks, pointers, gotchas.
01 / 10
Create the application + bot user in the Developer Portal
30 min
Every Discord bot is an Application with a Bot user. Create the application in the Developer Portal, then add a Bot to it. The bot's token is the credential that authenticates as the bot; treat it like a password. If it leaks, regenerate immediately.
Tasks
Sign in to the Discord Developer Portal
Click New Application → name + icon (icon is 512x512 PNG)
Open Bot tab → Add Bot
Click Reset Token, copy the token, paste into your secrets manager
Toggle Public Bot off (you'll flip it on at submission time)
Set the bot's username + avatar (separate from the application name)
Note the Application ID (used in slash command registration)
If your bot token leaks (committed to git, posted in a Discord channel), Discord auto-detects via secret scanning and revokes within minutes. Regenerate from the Bot tab.
Public Bot OFF means only you can add the bot to a server. Useful during development; flip ON before submission.
Application ID and Bot ID are usually the same number, but they're conceptually different. Use Application ID for slash command registration, Bot ID for permission checks on user objects.
02 / 10
Set the OAuth2 scopes + bot permissions and generate the invite URL
30 min
Bots are added to servers via an OAuth2 invite URL with two things: scopes (always bot + applications.commands for slash commands) and permissions (a bitmask of what the bot can do). Pick the MINIMUM permissions; servers admins are increasingly suspicious of bots requesting Administrator.
Tasks
Open OAuth2 → URL Generator in the Developer Portal
Select scopes: bot + applications.commands
Select bot permissions: Send Messages + Read Message History + whatever else you need
Avoid Administrator unless you literally cannot ship without it
Copy the generated URL, add the bot to your dev server
Verify the bot shows online when your dev server is open and your gateway client is running
The Administrator permission overrides every channel-level restriction. Server admins reject bots that ask for it without a real reason.
Slash commands require the applications.commands scope in addition to bot. Forgetting it makes commands silently fail to register.
The generated URL embeds the permissions bitmask. Updating the URL after the bot is in 100 servers does NOT re-prompt admins; you keep the original perms.
03 / 10
Pick discord.js or discord.py and ship a working command
2-4 hr
discord.js (Node) and discord.py (Python) are the two viable libraries. Both ship slash command builders, gateway clients, and REST helpers. Pick whichever ecosystem you're already in. Ship one slash command end-to-end before you scale up.
Tasks
Install discord.js (npm i discord.js) or discord.py (pip install -U discord.py)
Initialise a Client with the minimum intents (Guilds is mandatory for slash commands)
Define one slash command: /ping → reply with 'pong'
Register the command on your dev guild (instant) instead of globally (1-hour propagation)
Run the bot locally, /ping in your dev server, confirm reply
Global slash commands take up to 1 hour to propagate. Use guild-scoped commands during development for instant feedback.
Slash command names must be 1-32 chars, lowercase, no spaces. Capital letters fail registration with a confusing error.
Discord rate-limits command registration. Re-registering all commands on every code change burns rate limits; only re-register when the schema changed.
04 / 10
Request the right Privileged Gateway Intents
30 min to enable, 1-3 weeks to get approved post-100
Three intents are 'Privileged': MESSAGE_CONTENT, GUILD_MEMBERS, GUILD_PRESENCES. Until you're in 100 servers you can toggle them on yourself in the Developer Portal. AFTER 100 servers you must apply for them via verification. Pick exactly the intents your bot uses; over-requesting gets the verification denied.
Tasks
Open the Developer Portal → Bot tab → Privileged Gateway Intents
Enable MESSAGE_CONTENT only if you read raw message bodies (vs slash commands)
Enable GUILD_MEMBERS only if you need member join/leave events or member listing
Enable GUILD_PRESENCES only if you need user online/offline status
If your bot is purely slash-command-driven: you may need NO privileged intents
Match your client's intent bitmask in code to what's enabled in the portal
If your code requests an intent that's not enabled in the portal, the gateway connection fails with a 4014 error. Match exactly.
MESSAGE_CONTENT became privileged in 2022. Most bots don't need it; slash commands give you what you need without reading message bodies.
GUILD_PRESENCES is the most-rejected intent on verification. Only request if your bot's core feature requires online/offline status (e.g. activity-tracking bots).
05 / 10
Host the gateway worker on always-on infra
2-4 hr
A Discord bot must hold an open WebSocket to the gateway. Serverless / Lambda / Vercel functions don't fit (no long-lived process). You need a VM or container with a persistent process. Cheap options: Fly.io, Railway, Render. Expect $5-10/mo for a small instance.
Tasks
Pick a host (Fly.io, Railway, Render, a $5 DigitalOcean droplet)
Containerize the bot in a Dockerfile
Add a process supervisor / restart policy (Fly auto-restarts; Render has 'always-on' service type)
Set DISCORD_TOKEN as an env var in the host
Verify the bot reconnects on temporary network blips (gateway disconnects ~once a day)
Set up structured logging (timestamps, guild_id, user_id) so you can debug rate limits
Don't run the bot on your laptop. The instant your laptop sleeps, the gateway disconnects and the bot goes offline. Free hobby tiers (Heroku-style) often sleep too.
At 2,500 guilds you MUST shard. discord.js / discord.py both have sharding helpers; the rewrite is 1-2 days, plan for it before you hit the cap.
Discord rate-limits gateway connect attempts. If your bot crashes and restarts every minute, you'll get cut off. Add a 5s back-off between connection retries.
06 / 10
Build the help / about / privacy commands users expect
2-3 hr
Public bots that pass verification consistently ship four 'meta' commands: /help, /about, /support (link to your support server), /privacy. Discord's verification team specifically looks for these — they're a quick proxy for whether the bot is professionally maintained.
Tasks
Implement /help: list every command, grouped by category, with a 1-line description
Implement /about: bot version, links to source / docs / support server
Implement /support: invite link to a support server you actually monitor
Implement /privacy: link to a hosted Privacy Policy page
Implement /tos: link to a Terms of Service page (required by Discord for verification)
Host the Privacy + ToS pages on your own domain (a static page is fine)
Privacy Policy + Terms of Service URLs are FIELDS in the Developer Portal. Filling them is required for verification. Use real URLs, not 'TBD'.
If your bot collects user IDs, message text, or any other personal data, your Privacy Policy must say so explicitly. Discord checks.
/support links should resolve to a server you can actually moderate. A dead support server is a bigger negative signal than no support server.
07 / 10
Stress-test rate limits + error handling
3-5 hr
Discord's REST API is rate-limited per route + globally. Sending 5 messages/second to one channel will trigger a 429 response with a Retry-After header. discord.js / discord.py handle most of this automatically, but custom REST calls (webhooks, bulk operations) need explicit back-off. Test before you hit it in production.
Tasks
Read the Rate Limits section of the Discord API docs end-to-end
If using raw fetch / axios for any REST call: implement Retry-After back-off
Add Sentry / OpenTelemetry to the bot for error tracking
Stress-test with a script that fires 50 commands in 5 seconds
Confirm the bot doesn't crash on a 429; it should queue and retry
Confirm gateway reconnect works on 1006 disconnects (network blip)
Global rate limit is 50 requests/second across the whole bot. discord.js handles this for you; raw HTTP calls bypass it and risk a temp ban.
DM rate limits are stricter than channel limits and not visible in the docs. If your bot DMs users, expect to hit limits at ~5 DMs/minute per recipient.
Cloudflare 429s look different from Discord 429s. Both have Retry-After headers but different scopes. Log the full response body to tell them apart.
08 / 10
Submit for verification (and prepare 1-3 weeks of waiting)
4-8 hr to prepare, 1-3 weeks Discord queue
At ~75 servers Discord starts surfacing the Verification banner in the Developer Portal. You MUST submit before 100 because new server adds halt at 100 unverified. Verification = ID verification (Stripe Identity flow) + a written application explaining each Privileged Intent + each potentially-dangerous command.
Tasks
Watch your server count. At 75, prepare the verification application
Open Developer Portal → Bot → Apply for Verification
Complete the Stripe Identity flow (gov ID + selfie)
Write the application: bot description, every Privileged Intent + why, every dangerous command + why
Confirm Privacy Policy + ToS URLs are live + accurate
Submit; expect 1-3 week response, sometimes longer in December
On approval: Privileged Intents go through automatically + the 100-server cap lifts
On rejection: address the cited reason exactly + resubmit
If you reach 100 servers UNVERIFIED, all NEW server adds are blocked until verification completes. Existing servers are fine. Submit before you hit 100.
Stripe Identity (the ID verification provider) sometimes rejects valid IDs on first scan. Re-take the selfie in better light + try again before contacting support.
Verification is keyed to a single human. If you're a team, the human listed on the Stripe Identity scan owns the verified status. Don't pick someone who might leave.
Agent prompt for this step
Draft the Discord bot verification application.
Read the bot's source code + the Brief. Output, in order:
1. **Bot description** (300 chars): one paragraph, what the bot does for users + which audiences it serves.
2. **Privileged Intent justifications** (one per intent): if requesting MESSAGE_CONTENT / GUILD_MEMBERS / GUILD_PRESENCES, write 3-5 sentences per intent. State the user-visible feature, why an alternative (slash commands, mentions, message references) wouldn't work.
3. **Dangerous command justifications**: list any commands that ban / kick / mute / mass-message / DM users. For each, name the command + why your bot needs it + how you mitigate abuse (permission gating, audit logs, cooldowns).
4. **Data handling summary**: what user data the bot stores, where, retention, deletion-on-request flow.
Tone: factual, technical, concise. The reviewers are engineers triaging in volume; write for skim.
09 / 10
Set up monitoring, on-call, and the upgrade-to-shard checklist
2-4 hr
Once verified, the operations layer matters: gateway disconnects, REST rate limits, server outages. Discord's status page is the first place to check on incident days. At 2,500 servers you MUST shard, so reserve a few hours to plan the transition before you're at 2,000.
Tasks
Set up uptime monitoring on the bot's gateway connection (heartbeat to a /healthz endpoint or a Prometheus counter)
Subscribe to Discord's status page RSS for outage awareness
Set up alerting on gateway disconnect rate above 1/hour
Document the sharding rewrite plan (discord.js ShardingManager / discord.py AutoShardedClient)
Plan to test sharding at 2,000 servers, deploy at 2,400, before the 2,500 hard cap
Set up an on-call rotation if the bot is critical to a paying customer
Sharding is mandatory at 2,500 guilds. Hitting the cap with a single shard fails the gateway connection and takes the bot offline for every server.
Status page subscriptions help, but Discord's biggest outages take 30+ min to acknowledge. Always check #discord-developers in the Discord API server first.
If you ship breaking changes (renamed slash commands, removed permissions), users see them as 'unknown command' for ~1 hour during global propagation. Communicate ahead.
10 / 10
Grow past verification: directories, partnerships, free dev tier
2-4 hr to set up, ongoing
Verified bots are eligible for the App Directory (Discord's official bot listing) and can apply for the Verified Server program if you run a community. The free Developer Tier gives access to monetisation (subscriptions inside Discord) post-verification.
Tasks
Submit the bot to the Discord App Directory (separate from verification)
Optional: apply for a Verified Discord Server for your support community
If you want to monetise: explore Premium App Subscriptions inside Discord
List the bot on top.gg / Bots on Discord (third-party directories) for SEO
Build a public landing page with a 'Add to Discord' button (the OAuth2 invite URL)
App Directory submissions need polished assets: square icon, banner, screenshots, accurate categories. Reuse the verification work; don't half-do it.
Premium App Subscriptions take a 10% Discord cut + payment processing. Pricing must end in .99 or .49 (Discord's pricing tiers).
Third-party listings (top.gg) require a bot stat reporter that pings their API every few minutes. Don't promise uptime you can't deliver, or you'll get demoted.
Hand the template to your agent
Workspace-wide agent prompt.
Paste this into your agent's permanent system prompt so the agent reads, writes, and maintains the template's surfaces as you work through the steps.
Agent system prompt
You are an agent on the "Build a Discord bot and verify it" playbook workspace at your-org/build-a-discord-bot.
Your role: maintain the four surfaces (Steps, Pointers, Brief, Verification log) as the user works through the 10-step playbook.
Cadence:
- When the user marks a step Done, append a line to the Brief.
- When server count crosses 50, 75, 90, or 100, append a row to Verification log + draft the next-step nudge in the Brief.
- When Discord responds to a verification request, capture the response (approval / rejection / clarification) in Verification log.
First MCP tool calls:
1. list_surfaces(workspace_slug="build-a-discord-bot")
2. list_rows(workspace_slug="build-a-discord-bot", surface_slug="steps")
3. get_doc(workspace_slug="build-a-discord-bot", surface_slug="brief")
Do NOT modify canonical step titles. Append substeps as new rows.
FAQ
Common questions on this template.
Do I need to verify my Discord bot?
Only if you want to grow past 100 servers. Below 100, you can run the bot, including with Privileged Intents, by toggling them in the Developer Portal. At 100 servers, new server adds halt and Privileged Intents lock until verification completes.
How long does verification take?
Typical: 1-3 weeks. Slower in December and around major Discord product launches. The Stripe Identity step is fast (5-10 min). The application review is the slow part. Submit before you hit 75 servers if you can — you don't want to be at 99 with a stuck application.
Can my bot run without Privileged Intents?
Yes, increasingly so. If your bot is slash-command-driven (no message-content reading), you can ship without any Privileged Intents. This used to be uncommon; since 2022 it's the recommended path. Most modern bots only request privileged intents if a feature literally cannot exist without them.
Why is my bot not responding to messages?
Three checks in order: (1) does your bot have permission in the channel (Send Messages + Read Message History)? (2) does the bot's gateway client have the right intents (Guilds is mandatory; MESSAGE_CONTENT for reading message bodies)? (3) is your gateway worker actually online? Run a /ping slash command first to isolate.
Can my AI agents help with the Discord bot?
Yes. Agents are particularly useful for: drafting the verification application (intent justifications, command summaries, data handling), reading the source to find every Privileged Intent the code actually uses, drafting the Privacy Policy + ToS pages from a data audit, monitoring server count + nudging when verification deadlines approach. The playbook ships agent prompts inline.
Open this template as a workspace.
We mint a fresh copy in your org with the steps as table rows, the pointers as a separate table, and the brief as a doc. Bring your agents, start checking off boxes.