Interactions
These guides adapt the Discord.js interaction topics to the current discord.go API. They use bot.Router for application commands and component routes, components builders for payloads, and bot.InteractionContext for replies.
Before You Start
- Use Go
1.26.4or newer, as declared by the repositorygo.mod. - Set
DISCORD_TOKENto a bot token. Do not put a token in source code. - Install the application in a test guild with the
applications.commandsscope. - Use
intents.Guildsfor the interaction-only examples. Buttons, menus, and modals arrive as interactions and do not require message-content intent. - Run a copied example from the repository root with
go run ./examples/name.
Topic Map
- Interactions explains interaction types, routing, and the one-initial-response rule.
- Buttons creates custom-ID and link buttons.
- Action Rows composes legacy interactive components.
- Select Menus handles string and user selections.
- Modals opens forms and reads submitted text inputs.
- Display Components builds Components V2 layouts.
Acknowledgement Rule
Discord expects the initial interaction response quickly. In discord.go, use exactly one of Reply, ReplyEphemeral, ReplyComplex, Defer, DeferUpdate, Update, ShowModalBuilder, or another initial response method. After a deferral, use EditReply or Followup; after a component update, do not call a second initial Reply. A duplicate acknowledgement returns bot.ErrInteractionAlreadyResponded.
Tutorial: First Interaction
- Read
DISCORD_TOKENfrom the environment. - Register a command on
bot.NewRouter(). - Create the bot with
intents.Guildsandbot.WithRouter. - Reply from the handler and start
b.Run().
Complete Runnable Example
Copy this to examples/interaction-ping/main.go, set DISCORD_TOKEN, and run go run ./examples/interaction-ping.
go
package main
import (
"log"
"os"
"github.com/discord-go/discord.go/bot"
"github.com/discord-go/discord.go/intents"
)
func main() {
token := os.Getenv("DISCORD_TOKEN")
if token == "" {
log.Fatal("DISCORD_TOKEN is required")
}
router := bot.NewRouter()
router.Command("ping", "Check whether the bot is online", func(ctx *bot.InteractionContext) {
if err := ctx.Reply("Pong"); err != nil {
log.Printf("ping response: %v", err)
}
})
b := bot.New(token, bot.WithIntents(intents.Guilds), bot.WithRouter(router))
if err := b.Run(); err != nil {
log.Fatal(err)
}
}Shared Safety Rules
- Use
interactions.VerifyRequest, notVerifySignature, for incoming HTTP interaction webhooks.VerifySignaturechecks only the Ed25519 signature and allows replay attacks.VerifyRequestadditionally enforces timestamp freshness (5-minute window) to reject replayed requests. If you useinteractions.Server, this is handled automatically. See the interaction server example for a complete runnable program. - Treat custom IDs, selected values, and modal values as untrusted input.
- Authorize a component at click time; rendering a button is not authorization.
- Keep custom IDs stable and short. Put sensitive or long-lived state in server storage rather than exposing it in the ID.
- Defer before slow database or REST work, then use a bounded context.
- Return or log every response error. A silently ignored failed acknowledgement makes the next recovery attempt ambiguous.