A Discord integration bot connects your server to the tools your team already works in, like Trello, Notion, Google Sheets, Twitch or your own API. Updates land in the right channel on their own, and members act on them with slash commands instead of switching tabs. I build these as small bots you own: your Discord application, your API keys, your repository.
Not every integration needs a bot. If data only flows into Discord, a channel webhook is free and needs no hosting, and Zapier, Make or IFTTT connect many apps to Discord without code. You need a bot when data flows both ways, when members trigger actions with commands or buttons, or when the rules outgrow a zap.
What a Discord integration bot does
Take a Trello board, which I connected to Discord as an internal project (it's one of the case studies on this page).
For a member, a developer types /create-card with a card name and a list. The bot creates the card through Trello's API and replies with the details. Later, someone comments on that card in Trello. Trello sends a webhook, the bot checks Trello's signature, and the comment appears as an embed in the team's channel. Nobody has to keep the board open to know what changed.
For an admin, /set-board picks which board the bot works on, and at startup the bot registers its own Trello webhook so changes flow back. In a client build, admin commands like that are hidden from regular members with Discord's default member permissions. My build has eight slash commands for boards, lists and cards, and turns more than ten Trello event types, from comments to attachments to member changes, into readable embeds.
The other common shape runs one way. For Rivals League, a go-live notifier checks the league's Twitch channel every minute and, when it goes live, posts to each game's channel (CS2, League of Legends and VALORANT), with a six-hour cooldown per game so nobody gets spammed. It doesn't use a bot user: a scheduled function polls Twitch and posts through one Discord webhook per game channel. When you can build it that way, you should.
Webhook, Zapier or a bot?
Prices are from each vendor's pricing page as of September 2026.
| Option | Direction | Cost | Where it stops |
|---|---|---|---|
| Discord channel webhook | Into Discord | Free | Can't read messages, take commands or react to members |
| Zapier | Both | Free: 100 tasks a month, two-step zaps, checks every 15 minutes. Professional from $19.99 a month billed annually ($29.99 monthly) for 750 tasks | No slash-command trigger; the Webhooks by Zapier trigger needs a paid plan |
| Make | Both | Free: 1,000 credits a month, 15-minute minimum interval. Core from $9 a month for 10,000 credits | Discord triggers are channel messages, invites and members only |
| IFTTT | Mostly into Discord | Every Discord trigger and action is marked Pro: Pro $2.99 a month, Pro+ $8.99, both billed annually | Two Discord triggers and two actions |
| Custom bot | Both, in real time | Build from $590; hosting from $49 a month with Care | Costs more up front and needs hosting |
Pick a webhook when the other system can send an HTTP request and you only need notices in a channel. Create one under Server Settings > Integrations > Webhooks and paste the URL into the other tool. You can try it first with the webhook sender and embed builder, which posts a test message from your browser. For GitHub, add /github to the end of the URL and Discord formats commits and pull requests itself. From a script, it's one request:
curl -H "Content-Type: application/json" \
-d '{"username": "Deploy bot", "content": "Build 142 is live on production."}' \
"$DISCORD_WEBHOOK_URL"Discord's own help article lists Twitch and YouTube among the services that "can't really use webhooks". They won't post to a Discord webhook for you, so something has to sit in between.
Pick Zapier or Make when both apps are in their catalogs, a delay of a few minutes is fine (15 on the free plans) and volume is low. Both meter every action, so a busy channel can use up a plan quickly.
Pick a bot when members need to trigger things, when data must flow both ways, when you need rules a zap can't express (deduplication, cooldowns, routing by game or role), or when you'd rather own the code than pay per task. If your brief describes something a webhook or a zap will handle, I'll say so instead of quoting a build.
What it connects to
| System | How changes reach Discord | Limits to design for |
|---|---|---|
| Trello | Webhooks signed with HMAC-SHA1; the bot writes back through the REST API | Trello checks your URL with a HEAD request first, retries a failed delivery 3 times (after 30, 60 and 120 seconds) and disables a webhook that has kept failing for 30 days |
| Notion | Webhooks such as page.created and comment.created, signed with HMAC-SHA256 |
Events carry IDs, not content, so the bot fetches the page. page.content_updated is batched. 180 API requests a minute per connection, 600 on Business and Enterprise |
| Google Sheets | The Sheets API has no webhooks: an installable Apps Script trigger calls the bot, or the bot polls | 60 reads and 60 writes per minute per user per project. Edits made by scripts or the API don't fire onEdit |
| Twitch | EventSub stream.online webhooks, or polling Get Streams (up to 100 channels per request) |
EventSub callbacks need HTTPS on port 443 and an answer within a few seconds |
| Your own API or database | Your app calls the bot's endpoint or a webhook; the bot calls your API with a scoped key | Whatever your API allows |
Google Sheets is often the right database for a small league, because admins already live in it. The registration bot I co-built for a Swedish online esports league pulled seeding in from the league's sheet and wrote teams and players back out. One trap: a simple onEdit trigger can't use services that need authorization, which includes fetching an outside URL, so pushing edits to Discord takes an installable trigger.
Twitch has a built-in Discord integration, but it's for Partners and Affiliates and manages subscriber roles. For go-live posts, MEE6's Twitch alerts need MEE6 Premium ($11.99 a month as of September 2026), which is cheaper than a build for a few streamers in one channel. A custom go-live notifier makes sense when routing depends on your own data: game, division, cooldowns, or a streamer list from your roster.
What it costs
| Tier | Price | Typical integration | Timeline |
|---|---|---|---|
| Starter | from $590 | One system, one direction, or a few commands against one API: go-live alerts routed by game, board updates in a channel, a Sheets lookup. Up to about 5 slash commands | 1 to 2 weeks |
| Community | from $1,490 | Two-way sync with a database, admin commands and an audit log, alongside other bot features | 2 to 4 weeks |
| Platform | from $3,500 | Several APIs, a web dashboard, multi-server setups | 4 to 8 weeks |
The quote goes up with two-way sync (someone has to win when both sides change the same record), members linking their own accounts, importing history, and event volume that needs queuing. It comes down when data flows one way into one channel, the other system already sends webhooks, and you can share API credentials and test data on day one.
Every build includes the source code, deployment on your own Discord application and 30 days of bug fixes. Every build also includes the first month of Care, which is $49 a month after that for hosting, monitoring and updates. Later changes are $90 an hour in prepaid 5-hour blocks. For a wider view, see how much a custom Discord bot costs or try the cost estimator.
How the build works
- Brief. Tell me the two systems, what should happen between them and who may trigger what, on the brief form.
- Spec. If the scope is fuzzy, a Bot Blueprint ($249) gets you a call, a written spec and a fixed quote, credited in full if you order within 30 days.
- Build in a private test server, against test copies of your board, sheet or database.
- Launch on your own Discord application, with API keys in your accounts. You pay 50% to book the slot and 50% when the delivery passes the agreed checklist (Platform builds are billed per milestone).
- Care keeps it hosted, monitored and updated when Discord changes things, with one small change a month included.
I take a limited number of builds each month, so put any deadline in the brief.
Technical notes
Verify every incoming webhook, and reject anything that doesn't check out:
- Trello: base64 HMAC-SHA1 of the raw body plus the exact callback URL, keyed with your app secret, in
X-Trello-Webhook. - Twitch: HMAC-SHA256 of message ID, timestamp and body, prefixed
sha256=. Twitch also recommends rejecting messages older than 10 minutes and skipping IDs you've already processed. - Notion: HMAC-SHA256 of the body in
X-Notion-Signature, keyed with the verification token Notion sends at setup. - Discord, if the bot takes interactions over HTTP: Ed25519 signatures. Discord sends invalid ones on purpose to check that you reject them.
This is the Trello check as it ran in my tests (Express 5.2, Node.js 24). It hashes the raw bytes rather than re-serialized JSON and compares in constant time:
const crypto = require('node:crypto');
const express = require('express');
const app = express();
const TRELLO_SECRET = process.env.TRELLO_SECRET; // your Trello app secret
const CALLBACK_URL = process.env.TRELLO_CALLBACK_URL; // exactly as registered with Trello
function isFromTrello(rawBody, signature) {
if (!Buffer.isBuffer(rawBody)) return false; // not sent as JSON, so not from Trello
const expected = crypto
.createHmac('sha1', TRELLO_SECRET)
.update(rawBody)
.update(CALLBACK_URL)
.digest();
const received = Buffer.from(signature ?? '', 'base64');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}
// Trello sends a HEAD request when the webhook is created and expects a 200.
app.head('/trello', (req, res) => res.sendStatus(200));
app.post('/trello', express.raw({ type: 'application/json' }), (req, res) => {
if (!isFromTrello(req.body, req.get('x-trello-webhook'))) return res.sendStatus(401);
res.sendStatus(200); // answer first, then do the work
const { action } = JSON.parse(req.body);
console.log(action.type); // hand the event to the bot, for example to post an embed
});
app.listen(process.env.PORT ?? 3000);Keep secrets out of code. Tokens, API keys and webhook secrets go in environment variables, never the repository. A Discord webhook URL counts as a secret, because anyone who has it can post.
Respect rate limits on both sides. Discord allows a bot 50 requests per second overall, publishes per-route limits in response headers and says not to hard-code them. On a 429, wait for Retry-After. An IP that makes 10,000 invalid requests (401, 403 or 429) in 10 minutes is temporarily blocked. Notion's per-minute limit and the Sheets per-user quota are easy to hit if every command calls the API, so queue writes and cache reads.
Store as little as possible: ID mappings (Trello card to Discord message), recent event IDs for deduplication, and settings. A slash-command bot doesn't need the Message Content intent, because command input arrives in the interaction. The slash commands guide shows that side with tested code.
Send me the two systems and what should happen between them on the brief form. If a webhook will do, that's the first thing you'll hear.