Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/disgoorg/disgo/llms.txt

Use this file to discover all available pages before exploring further.

HTTP interactions allow you to build Discord bots without maintaining a persistent WebSocket connection. This is perfect for serverless deployments, reduced resource usage, and simpler infrastructure.

How HTTP interactions work

Instead of connecting to Discord’s gateway, your bot receives interactions via HTTP webhooks. Discord sends a POST request to your server when users interact with your bot.
HTTP interactions are ideal for serverless platforms like AWS Lambda, Google Cloud Functions, Cloudflare Workers, and Vercel.

Setting up HTTP interactions

1

Configure your public key

Get your application’s public key from the Discord Developer Portal and set it as an environment variable:
export DISGO_TOKEN="your-bot-token"
export DISGO_PUBLIC_KEY="your-public-key"
2

Create your bot with HTTP server

package main

import (
    "context"
    "log/slog"
    "os"
    "os/signal"
    "syscall"

    "github.com/disgoorg/snowflake/v2"
    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/disgoorg/disgo/discord"
    "github.com/disgoorg/disgo/events"
    "github.com/disgoorg/disgo/httpserver"
)

var (
    token     = os.Getenv("disgo_token")
    publicKey = os.Getenv("disgo_public_key")
    guildID   = snowflake.GetEnv("disgo_guild_id")

    commands = []discord.ApplicationCommandCreate{
        discord.SlashCommandCreate{
            Name:        "say",
            Description: "says what you say",
            Options: []discord.ApplicationCommandOption{
                discord.ApplicationCommandOptionString{
                    Name:        "message",
                    Description: "What to say",
                    Required:    true,
                },
            },
        },
    }
)

func main() {
    client, err := disgo.New(token,
        bot.WithHTTPServerConfigOpts(publicKey,
            httpserver.WithURL("/interactions/callback"),
            httpserver.WithAddress(":8080"),
        ),
        bot.WithEventListenerFunc(commandListener),
    )
    if err != nil {
        panic("error while building disgo instance: " + err.Error())
    }

    defer client.Close(context.TODO())

    // Register commands
    if _, err = client.Rest.SetGuildCommands(client.ApplicationID, guildID, commands); err != nil {
        panic("error while registering commands: " + err.Error())
    }

    // Start HTTP server
    if err = client.OpenHTTPServer(); err != nil {
        panic("error while starting http server: " + err.Error())
    }

    slog.Info("bot is now running. Press CTRL-C to exit.")
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
    <-s
}

func commandListener(event *events.ApplicationCommandInteractionCreate) {
    data := event.SlashCommandInteractionData()
    if data.CommandName() == "say" {
        if err := event.CreateMessage(discord.MessageCreate{
            Content: data.String("message"),
        }); err != nil {
            event.Client().Logger.Error("error on sending response", slog.Any("err", err))
        }
    }
}
3

Configure Discord webhook URL

In the Discord Developer Portal, set your “Interactions Endpoint URL” to:
https://your-domain.com/interactions/callback
Discord will verify your endpoint by sending a ping request.

HTTP server configuration

Customize your HTTP server with various options:
client, err := disgo.New(token,
    bot.WithHTTPServerConfigOpts(publicKey,
        // URL path for interactions
        httpserver.WithURL("/interactions"),
        
        // Server address and port
        httpserver.WithAddress(":8080"),
        
        // Custom HTTP server
        httpserver.WithServer(&http.Server{
            Addr: ":8080",
            ReadTimeout: 10 * time.Second,
        }),
        
        // Custom verifier
        httpserver.WithVerifier(customVerifier{}),
    ),
)

Custom signature verification

You can implement custom signature verification:
type customVerifier struct{}

func (customVerifier) Verify(publicKey httpserver.PublicKey, message, sig []byte) bool {
    return ed25519.Verify(publicKey, message, sig)
}

func (customVerifier) SignatureSize() int {
    return ed25519.SignatureSize
}

client, err := disgo.New(token,
    bot.WithHTTPServerConfigOpts(publicKey,
        httpserver.WithVerifier(customVerifier{}),
    ),
)

Serverless deployment

AWS Lambda example

package main

import (
    "context"
    "os"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/disgoorg/disgo/httpserver"
)

var client bot.Client

func init() {
    var err error
    client, err = disgo.New(os.Getenv("DISGO_TOKEN"),
        bot.WithHTTPServerConfigOpts(os.Getenv("DISGO_PUBLIC_KEY")),
        bot.WithEventListenerFunc(handleCommand),
    )
    if err != nil {
        panic(err)
    }
}

func handler(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    // Verify and handle the interaction
    return client.HTTPServer().HandleRequest(ctx, request)
}

func main() {
    lambda.Start(handler)
}

func handleCommand(event *events.ApplicationCommandInteractionCreate) {
    // Handle your commands
}

Cloudflare Workers example

package main

import (
    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/syumai/workers"
)

var client bot.Client

func init() {
    var err error
    client, err = disgo.New(workers.Getenv("DISGO_TOKEN"),
        bot.WithHTTPServerConfigOpts(workers.Getenv("DISGO_PUBLIC_KEY")),
        bot.WithEventListenerFunc(handleCommand),
    )
    if err != nil {
        panic(err)
    }
}

func main() {
    workers.Serve(client.HTTPServer())
}

func handleCommand(event *events.ApplicationCommandInteractionCreate) {
    // Handle your commands
}

Differences from gateway bots

What works with HTTP interactions

  • ✅ Slash commands
  • ✅ Button and select menu interactions
  • ✅ Modal submissions
  • ✅ Autocomplete
  • ✅ REST API calls

What doesn’t work

  • ❌ Gateway events (message create, member join, etc.)
  • ❌ Real-time event streaming
  • ❌ Voice connections
  • ❌ Presence updates
  • ❌ Gateway intents
HTTP interactions only receive interaction events. You cannot listen to messages, reactions, or other gateway events.

Responding to interactions

You must respond to interactions within 3 seconds:
func commandListener(event *events.ApplicationCommandInteractionCreate) {
    // Option 1: Immediate response
    event.CreateMessage(discord.MessageCreate{
        Content: "Hello!",
    })
    
    // Option 2: Deferred response (for long operations)
    event.DeferCreateMessage(false)
    
    // Do long operation...
    
    // Then send followup
    event.Client().Rest.CreateFollowupMessage(
        event.ApplicationID,
        event.Token,
        discord.MessageCreate{Content: "Done!"},
    )
}

Deferred responses

For operations that take longer than 3 seconds:
func commandListener(event *events.ApplicationCommandInteractionCreate) {
    // Tell Discord you're processing (shows "Bot is thinking...")
    if err := event.DeferCreateMessage(false); err != nil {
        return
    }
    
    // Do your long operation
    result := performLongOperation()
    
    // Send the result as a followup
    _, err := event.Client().Rest.CreateFollowupMessage(
        event.ApplicationID,
        event.Token,
        discord.MessageCreate{Content: result},
    )
}

Advantages of HTTP interactions

  • Lower costs: No persistent connections mean less resource usage
  • Better scaling: Serverless platforms handle scaling automatically
  • Simpler infrastructure: No need to manage WebSocket connections
  • Faster cold starts: No gateway connection required
  • Regional deployment: Deploy to multiple regions easily

Disadvantages

  • Limited to interactions: Cannot receive gateway events
  • No real-time events: Can’t listen to messages, reactions, etc.
  • Startup verification: Discord pings your endpoint on startup
  • Public endpoint required: Must be accessible from the internet

Best practices

  • Respond quickly: Always respond within 3 seconds or defer
  • Use deferred responses: For operations taking more than 1 second
  • Validate public key: Ensure signature verification is working
  • Handle retries: Discord may retry failed interactions
  • Use environment variables: Store tokens and keys securely
  • Enable HTTPS: Required for production deployments
  • Monitor latency: Keep response times under 1 second when possible

Testing locally

Use a tunnel service to test locally:
# Using ngrok
ngrok http 8080

# Use the ngrok URL as your interactions endpoint
https://abc123.ngrok.io/interactions/callback

Next steps

Build docs developers (and LLMs) love