Developers
Build & Grow
"DiscordForge is the perfect place to grow your bot's user base. We provide powerful tools and a dedicated community to help you succeed."
Adding a Bot
Adding your bot to DiscordForge is simple and takes less than 2 minutes.
- Open the Menu and select Add.
- Choose Bot from the submission options.
- Fill in your Bot's details (Client ID, Prefix, Description, etc.).
- Copy the verification code (e.g., df-verify-xyz) and add it to your bot's About Me section in the Discord Developer Portal (not on DiscordForge or top.gg).
- Click Submit. Our system will verify the code automatically.
- Once a moderator approves it, your bot will be listed!
Announcements
Keep your users updated directly from your bot's profile page.
- Visibility: Announcements appear at the top of your bot's profile.
- Markdown: Full Markdown support including links, lists, and code blocks.
- One at a time: Each new announcement overwrites the previous one.
Widgets
Show off your bot's status on your website or GitHub README.
Go to your bot's profile, click the Actions menu, and select Widget.
Management
Need to update your bot's description, prefix, or links?
- Go to your Dashboard
- Click Edit on your project card
- Save changes instantly
Growth Tools
Forge Synergy
Link your bot to a Perfect Match partner project to cross-promote audiences.
API Access
We offer a robust REST API for posting stats and fetching bot data. Use our official SDKs for the best experience.
How to get your API Key
- Go to Dashboard → My Bots.
- Click on your bot's card to open its details.
- Navigate to the API Access tab.
- Click Generate or Regenerate.
Update your bot's server, shard, user, and voice connection counts.
{ "server_count": 1500, "shard_count": 5, "user_count": 120000, "voice_connections": 12 }
Check whether a user voted in the last 8 hours.
{ "hasVoted": true, "votedAt": "2026-05-03T08:42:11.000Z", "nextVoteAt": "2026-05-03T16:42:11.000Z" }
Fetch a bot's public profile. Accepts the bot's DiscordForge ID or Discord client ID. No auth required.
{ "id": "...", "name": "Forge Bot", "prefix": "/", "shortDescription": "...", "avatar": "...", "voteCount": 1240, "serverCount": 5300, "tags": ["moderation", "utility"], "owner": { "id": "...", "name": "..." } }
Sync your bot's slash commands. Accepts both custom and Discord API formats.
{ "commands": [ { "name": "ban", "description": "Ban a user", "usage": "/ban <user> [reason]", "category": "Moderation" } ] }
Heartbeat / Push-based Uptime. Ping this endpoint every 5 minutes from your bot to record uptime without needing the DiscordForge bot on your server. Once called for the first time, our system switches your bot to push-based monitoring and stops scanning your Discord guilds.
{ "success": true, "message": "Heartbeat recorded successfully", "status": "online", "uptimeChecks": 5409, "uptimeOnline": 5409 }
Check whether a user can bump a server and when their cooldown expires. Cooldown duration depends on the user's tier (Free: 2h, Premium: 1h, Forge/Pioneer: 30 min).
{ "canBump": false, "cooldownExpiresAt": "2026-05-05T20:30:00.000Z", "tierLabel": "FORGE", "cooldownMs": 1800000 }
Approved bots can update their own safe listing fields. Send at least one allowed field: prefix, shortDescription, description, tags, supportServer, website, socials, languages, hasPaidFeatures, paidFeaturesAvailable, webInterface, or installableAsUserApp.
{ "shortDescription": "Moderation tools with clear review queues.", "tags": "moderation, utility", "website": "https://example.com", "webInterface": true }
Category, invite and OAuth URLs, identity, ownership, team, approval, verification, ranking, assets, boosts, entitlements, and API keys cannot be changed through this API.
Publish a public release update for an approved bot. Content is sanitized Markdown, limited to 4,000 characters.
{ "title": "v2.4.0: Scheduled reminders", "content": "Added recurring reminders and improved /remind.", "type": "UPDATE" }
Migrate to Developer API v1
All v1 routes require Authorization: Bearer YOUR_BOT_API_KEY. The old routes remain compatibility aliases until 14 October 2026, 00:00 UTC, then return 410 Gone with the replacement URL.
| Legacy route | Use instead |
|---|---|
| POST /api/external/bots/commands | POST /api/v1/bots/commands |
| GET/POST /api/external/bots/heartbeat | GET/POST /api/v1/bots/heartbeat |
| GET /api/external/bump/cooldown | GET /api/v1/bump/cooldown |
| POST /api/bots/stats | POST /api/v1/bots/stats |
Before retirement, legacy responses include Deprecation, Sunset, and Link migration headers. Rotate no key for this migration: your existing bot API key remains valid.
Automatic Bot Status
DiscordForge automatically detects your bot's status if it shares a server with the Forge bot. Forge is a public bot, so you can invite it to any server your bot is already in and uptime checks kick in automatically.
Why is my bot showing as offline?
It's almost always one of two things:
You haven't added Forge to a shared server (most common)
Forge is public and we no longer auto-check every new bot. For uptime to work, the Forge bot needs to be in at least one server your bot is also in.
Your bot's presence is set to Offline or Invisible
Some bots set their own presence to invisible in code. When that happens Discord reports them as offline to everyone, including us, even though the process is running fine. Check your bot's presence config and set it to online, idle, or dnd. All three count as online on our end.
Still stuck after both? Ping staff with your bot's invite link and we'll take a look.
Vanity URLs
Set a custom vanity URL for your bot or server profile, making it easier to share and remember. Available to FORGE subscribers and PIONEER rank holders.
- 3-32 characters, lowercase letters, numbers, and hyphens
- Must be unique across the platform
- Configure in Dashboard → Bot or Server Settings
Webhooks
Vote webhooks fire whenever a user upvotes your bot on DiscordForge. Use them to reward voters instantly: grant a Discord role, unlock a premium feature, or DM a custom message. The reward flow is the #1 driver of recurring votes – bots that wire it up see 4x higher repeat votes than bots that don't.
Setup
- Go to Dashboard → My Bots → your bot.
- Open the Webhooks tab.
- Set the Webhook URL to your handler endpoint (HTTPS required).
- Create a Secret you control and store it as FORGE_WEBHOOK_SECRET in your bot's env. It is separate from your Bot API key.
- Save the webhook settings, then use Test Webhook to verify wiring (sends a payload with isTest: true).
Request
Headers: Authorization: <YOUR_SECRET>, Content-Type: application/json
Body:
{ "id": "123456789012345678", "username": "voteruser", "weeklyVotes": 42, "totalVotes": 150, "isTest": false }
id – Discord user ID of the voter (snowflake string).username – Discord username at the time of the vote.weeklyVotes – voter's vote count for your bot in the last 7 days.totalVotes – voter's lifetime vote count for your bot.isTest – true only when the dashboard's "Send Test" button fired the request. Skip rewards for test events.Expected response
Return any 2xx status within 5 seconds. Body content is ignored. A non-2xx response or timeout does not block the vote.
Security
- Always verify the secret. The Authorization header must equal the secret you copied during setup. Reject anything else with 401.
- HTTPS only. The dashboard rejects http:// URLs.
- Rotate the secret if it leaks. Regenerate from the dashboard and update your env. The old secret is invalidated immediately.
- Treat id as the user identifier. Don't trust username – Discord usernames can change.
Examples
import express from 'express'; import crypto from 'crypto'; const app = express(); app.use(express.json()); const FORGE_WEBHOOK_SECRET = process.env.FORGE_WEBHOOK_SECRET; app.post('/webhooks/forge-vote', (req, res) => { // 1. Verify the secret in the Authorization header const auth = req.headers.authorization; if (auth !== FORGE_WEBHOOK_SECRET) { return res.status(401).json({ error: 'Invalid secret' }); } // 2. Parse the payload const { id, username, weeklyVotes, totalVotes, isTest } = req.body; // Skip test events in production handlers if (isTest) { console.log('Received test webhook for', username); return res.status(200).json({ ok: true }); } // 3. Reward the user (example: grant a Discord role for 12h; role duration is intentionally longer than the 8h vote cooldown) grantVoterRole(id); // 4. Acknowledge within 5 seconds – non-2xx triggers retries (3 attempts) return res.status(200).json({ ok: true }); }); app.listen(3000, () => console.log('Webhook listener on :3000'));
Webhooks v2
Subscribe multiple HTTPS endpoints to signed DiscordForge events. Legacy Webhook remains available and unchanged.
Legacy Webhook
The existing vote-only integration with one URL and secret. Keep it unchanged for compatibility.
Webhooks v2
An opt-in event system with multiple endpoints, per-endpoint subscriptions, signed payloads, test deliveries, and delivery history.
Setup
- Open your bot listing and find Webhooks v2.
- Add an endpoint name and a public HTTPS URL.
- Select one or more events and save the endpoint.
- Store the generated endpoint secret securely.
- Send a test delivery for a subscribed event before going live.
A bot can have up to three active endpoints. URLs must use HTTPS, contain no credentials, and cannot target localhost or private networks.
Event envelope
Every v2 delivery uses the same envelope. The data object changes with the event type.
{ "id": "evt_b19d2b4d5c03427eb3994cd16a7e513b", "type": "vote.created", "created_at": "2026-08-05T01:49:28.767Z", "bot_id": "1503878409934340197", "data": { "voter_id": "1180554986686525506", "streak": 4, "total_votes": 100, "weekly_votes": 12 } }
idStable event identifier. Use it for idempotency.typeOne of the supported event names.created_atISO 8601 timestamp in UTC.bot_idThe bot's public Discord client ID.dataEvent-specific payload fields.Request headers
Content-Type: application/jsonJSON request body.X-Forge-Signaturesha256=<hex HMAC-SHA256 of the raw request body>.X-Forge-EventThe event type in the envelope.X-Forge-DeliveryThe delivery record identifier.
Verify the signature
- Read the raw request body before parsing JSON.
- Compute HMAC-SHA256 with the endpoint secret.
- Prefix the hexadecimal digest with sha256=.
- Compare the result with X-Forge-Signature using a timing-safe comparison.
- Parse JSON only after the signature is valid.
import crypto from 'node:crypto'; import express from 'express'; const app = express(); const secret = process.env.FORGE_WEBHOOK_SECRET; app.post('/webhooks/forge', express.raw({ type: 'application/json' }), (req, res) => { const rawBody = req.body.toString('utf8'); const received = req.header('X-Forge-Signature') || ''; const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); const valid = received.length === expected.length && crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected)); if (!valid) return res.status(401).json({ error: 'Invalid signature' }); const event = JSON.parse(rawBody); console.log(event.type, event.id, event.data); return res.sendStatus(204); });
Supported events
| Event | When it fires | data fields |
|---|---|---|
| vote.created | Fires after a user creates a bot vote. | voter_id, streak, total_votes, weekly_votes |
| review.created | Fires when a new bot review is created. Updating an existing review does not emit another event. | review_id, reviewer_id, rating, snippet, review_count |
| milestone.votes | Fires when a bot reaches a supported vote milestone. | threshold, total_votes |
Review snippets are limited to 240 characters.
Delivery behavior
- Source actions do not wait for the receiver network request.
- Any 2xx response marks the delivery as delivered.
- The receiver has five seconds to respond.
- Failed deliveries retry after 1 minute, 5 minutes, and 30 minutes, for four attempts total.
- Use the event ID or delivery ID to ignore duplicate deliveries.
- Test deliveries include test: true and source: dashboard and do not change votes or reviews.
Troubleshooting
- URL rejected: use a public HTTPS endpoint without credentials.
- Signature mismatch: verify the raw body, endpoint secret, sha256= prefix, and timing-safe comparison.
- Duplicate event: store handled event or delivery IDs before applying side effects.
- Repeated 4xx or 5xx responses: inspect delivery history and fix the receiver before retrying.
- Test event unavailable: subscribe the endpoint to that event first.
Machine-readable API reference
OpenAPI currently documents the public /api/v1 API. This page is the source of truth for outbound Webhooks v2 delivery behavior.
Open public/openapi.jsonVote Notifications
Get real-time Discord notifications whenever someone votes for your bot.
Zero-Code Setup
Vote notifications are sent directly to your Discord server by the Forge bot. No server infrastructure needed. Configure it in Dashboard → Integrations.


