Webhooks — bypass bot rate limits for high volume
Webhooks: bypass bot rate limits for high volume
Section titled “Webhooks: bypass bot rate limits for high volume”A bot user has one global rate-limit bucket per route, shared across every guild it’s installed in. For a high-volume publisher (CI alerts, cross-poster, metrics relay) this becomes the bottleneck long before Discord’s per-channel limits do. The fix is webhooks — each webhook URL has its own bucket.
Use case
Section titled “Use case”Ops engineer says: “Set up a webhook in #ci-alerts and use it for all GitHub Actions notifications. Don’t burn our bot’s rate limit on this.”
Two tool calls split across time: provision the webhook once (capture the
token), then call webhooks_execute from there on out.
Tool flow
Section titled “Tool flow”-
Provision the webhook (one time).
webhooks_createreturns the full webhook record including the token. Capture theidandtokenand store them outside the agent’s working memory — typically in a secrets manager or a sealed config file.{"name": "webhooks_create","arguments": {"channel_id": "222233334444555566","name": "github-actions-notifier","audit_reason": "ops: bypass bot bucket for CI alerts"}}{"id": "444455556666777788","type": 1,"channel_id": "222233334444555566","application_id": null,"name": "github-actions-notifier","avatar": null,"token": "REDACTED-treat-as-credential","untrusted_name": "github-actions-notifier"} -
Post via
webhooks_execute.The token replaces bot authentication. No
Authorizationheader is sent on this call — the token in the request body is the credential. This is theauth: falsesemantics in the tool’s transport layer.{"name": "webhooks_execute","arguments": {"webhook_id": "444455556666777788","token": "REDACTED-treat-as-credential","content": "Build #4127 failed on `main` — https://github.com/cappylab/discord-mcp/actions/runs/4127","username": "GitHub Actions","wait": true}}{"name": "webhooks_execute","arguments": {"webhook_id": "444455556666777788","token": "REDACTED-treat-as-credential","flags": 32768,"with_components": true,"components": [{"type": 17,"accent_color": 16711680,"components": [{ "type": 10, "content": "## Build #4127 failed" },{ "type": 10, "content": "Branch: `main` — Run: [4127](https://github.com/cappylab/discord-mcp/actions/runs/4127)" }]}],"wait": true}}{"message_id": "888899990000111199","channel_id": "222233334444555566","webhook_id": "444455556666777788"}
Why webhooks beat the bot for high volume
Section titled “Why webhooks beat the bot for high volume”| Concern | Bot user | Webhook |
|---|---|---|
| Rate-limit bucket | shared across all guilds | per webhook URL |
| Auth | Authorization: Bot <token> header | token in URL/body, no header |
| Display identity | bot’s name + avatar | per-message username and avatar_url override |
| Can react / reply / edit other messages | yes | no |
| Cost to provision | one bot install per workspace | one webhooks_create per channel |
When sending Components V2 through a webhook, you must set both:
flags: 32768— theIS_COMPONENTS_V2bit (1 << 15).with_components: true— query parameter telling Discord to include the component tree in the returned message (only matters whenwait: true).
Caveats
Section titled “Caveats”- Webhooks can only post. They can’t react, reply with interactions, or edit messages other than their own. For interactive flows, stick with the bot.
- One channel per webhook. A webhook is bound to its creation channel. Cross-posting requires multiple webhooks.
- Token leakage = full impersonation. Treat tokens like API keys. Anyone with the token can post as the webhook with no further auth.
See also
Section titled “See also”webhooks_create— schema for provisioning, including the token field.webhooks_execute— full execute schema (content, embeds, components, threads).webhooks_modify_with_token,webhooks_delete_with_token— token-only mutations (no bot auth required).- Recipe: Components V2 announcement — the rich-layout flow this recipe pairs with.
- Architecture: rate limits — how Cockatiel buckets bot vs webhook traffic separately.