exported functions and types are documented here.
- Client (dgate.go)
- Event Constants (types/subscribable.go)
- Handler Signatures
- discord/channel.go
- discord/interactions.go
- discord/gateway.go
- discord/handlers.go
- discord/utils.go
- types/config.go
- types/events.go
- types/discord.go
- discord/guild.go
- discord/user.go
The Client struct is the main entrypoint.
type Client struct {
Selfbot *discord.Selfbot
Gateway *discord.Gateway
Config *types.Config
}The logged-in user is available at client.Gateway.Selfbot.User after Connect returns. This is a types.User struct populated from the READY event before any handlers fire.
func NewClient(token string, config *types.Config) *ClientCreates a new client. config must not be nil -- pass &types.DefaultConfig to use the defaults.
client := discoself.NewClient("your-user-token", &types.DefaultConfig)func (client *Client) Connect() errorOpens the WebSocket connection, runs the login handshake, and starts the event loop. Blocks until the connection is established. The READY event fires and handlers are called before this returns.
if err := client.Connect(); err != nil {
fmt.Println("Error connecting:", err)
return
}func (client *Client) Close()Closes the gateway connection and stops the event loop.
client.Close()func (client *Client) AddHandler(event string, function any) errorRegisters a callback for a gateway event. Must be called before Connect. The function signature must exactly match the event type -- passing the wrong signature silently fails (the handler is not registered). Use the constants from types/subscribable.go for event names.
Supported events and their required function signatures:
| Event constant | Function signature |
|---|---|
types.GatewayEventReady |
func(data *types.ReadyEventData) |
types.GatewayEventMessageCreate |
func(data *types.MessageEventData) |
types.GatewayEventMessageUpdate |
func(data *types.MessageEventData) |
types.GatewayEventMessageDelete |
func(data *types.MessageDeleteEventData) |
types.GatewayEventTypingStart |
func(data *types.TypingStartEventData) |
types.GatewayEventPresenceUpdate |
func(data *types.PresenceUpdateEventData) |
types.GatewayGuildMembersChunk |
func(data *types.GuildMembersChunkEventData) |
types.GatewayEventReconnect |
func() |
types.GatewayEventInvalidated |
func() |
client.AddHandler(types.GatewayEventReady, func(data *types.ReadyEventData) {
fmt.Printf("Logged in as: %s\n", data.User.Username)
})
client.AddHandler(types.GatewayEventMessageCreate, func(data *types.MessageEventData) {
fmt.Println(data.Content)
})func (client *Client) SendMessage(channelID string, content string) boolSends a text message to a channel. Returns true on success.
client.SendMessage("1234567890123456789", "hello")func (client *Client) SendMessageWithReply(channelID string, content string, replyMessageID string) boolSends a message as a reply to replyMessageID. Returns true on success.
client.SendMessageWithReply("1234567890123456789", "got it", "9876543210987654321")func (client *Client) EditMessage(channelID string, messageID string, content string) boolEdits one of your own messages. Returns true on success.
client.EditMessage("1234567890123456789", "1122334455667788990", "updated content")func (client *Client) DeleteMessage(channelID string, messageID string) boolDeletes one of your own messages. Returns true on success.
client.DeleteMessage("1234567890123456789", "1122334455667788990")func (client *Client) SendTyping(channelID string) boolSends a typing indicator to a channel. Returns true on success.
client.SendTyping("1234567890123456789")func (client *Client) AddReaction(channelID string, messageID string, emoji string) boolAdds a reaction to a message. For Unicode emoji pass the character directly. For custom emoji use name:id format. Returns true on success.
client.AddReaction("1234567890123456789", "1122334455667788990", "🐢")func (client *Client) RemoveReaction(channelID string, messageID string, emoji string) boolRemoves your own reaction from a message. Returns true on success.
client.RemoveReaction("1234567890123456789", "1122334455667788990", "turtle:9988776655443322110")func (client *Client) DeleteAllReactions(channelID string, messageID string) boolRemoves all reactions from a message. Returns true on success.
client.DeleteAllReactions("1234567890123456789", "1122334455667788990")func (client *Client) GetChannel(channelID string) (types.Channel, error)Fetches a channel by ID. Returns the types.Channel struct or an error.
channel, err := client.GetChannel("1234567890123456789")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(channel.Name)func (client *Client) GetMessage(channelID string, messageID string) (types.MessageData, error)Fetches a single message by ID. Returns the types.MessageData or an error.
msg, err := client.GetMessage("1234567890123456789", "1122334455667788990")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(msg.Content)func (client *Client) GetMessages(channelID string, limit int) ([]types.MessageData, error)Fetches up to 100 messages from a channel. Pass limit 1-100. Returns a slice of types.MessageData or an error.
msgs, err := client.GetMessages("1234567890123456789", 50)
if err != nil {
fmt.Println("Error:", err)
return
}
for _, msg := range msgs {
fmt.Println(msg.Content)
}func (client *Client) GetPinnedMessages(channelID string) ([]types.MessageData, error)Fetches all pinned messages in a channel. Returns a slice of types.MessageData or an error.
msgs, err := client.GetPinnedMessages("1234567890123456789")func (client *Client) PinMessage(channelID string, messageID string) boolPins a message in a channel. Returns true on success.
client.PinMessage("1234567890123456789", "1122334455667788990")func (client *Client) UnpinMessage(channelID string, messageID string) boolUnpins a message in a channel. Returns true on success.
client.UnpinMessage("1234567890123456789", "1122334455667788990")func (client *Client) CreateThread(channelID string, messageID string, name string) (types.Channel, error)Creates a public thread from an existing message. Returns the created types.Channel (thread) or an error.
thread, err := client.CreateThread("1234567890123456789", "1122334455667788990", "Discussion Thread")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(thread.ID)func (client *Client) GetSlashCommands(guildID string) (types.ApplicationCommandIndex, error)Fetches all slash commands available in a guild. See lower-level version in discord/interactions.go for details.
func (client *Client) GetUserSlashCommands() (types.ApplicationCommandIndex, error)Fetches slash commands available globally to your user. See lower-level version in discord/interactions.go for details.
func (client *Client) SendSlashCommandWithOptions(channelID string, guildID string, command types.ApplicationCommand, options []any) boolFires a slash command with option values. See lower-level version in discord/interactions.go for details.
func (client *Client) ClickButton(e *types.MessageEventData, interactionID string) boolClicks a message component button. See lower-level version in discord/interactions.go for details.
func (client *Client) GetGuild(guildID string) (types.Guild, error)Fetches a guild by ID. Returns the types.Guild struct or an error.
guild, err := client.GetGuild("9876543210987654321")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(guild.Name)func (client *Client) GetGuildChannels(guildID string) ([]types.Channel, error)Fetches all channels in a guild. Returns a slice of types.Channel or an error.
channels, err := client.GetGuildChannels("9876543210987654321")
if err != nil {
fmt.Println("Error:", err)
return
}
for _, ch := range channels {
fmt.Println(ch.Name)
}func (client *Client) GetGuildRoles(guildID string) ([]types.Role, error)Fetches all roles in a guild. Returns a slice of types.Role or an error.
roles, err := client.GetGuildRoles("9876543210987654321")
if err != nil {
fmt.Println("Error:", err)
return
}
for _, role := range roles {
fmt.Println(role.Name)
}func (client *Client) KickMember(guildID string, userID string) errorKicks a member from a guild. Returns an error if the operation fails.
err := client.KickMember("9876543210987654321", "111111111111111111")
if err != nil {
fmt.Println("Error:", err)
}func (client *Client) BanMember(guildID string, userID string, deleteMessageSeconds int) errorBans a member from a guild. deleteMessageSeconds sets how many seconds of messages to delete (0 to 604800). Returns an error if the operation fails.
err := client.BanMember("9876543210987654321", "111111111111111111", 86400) // Delete 1 day of messages
if err != nil {
fmt.Println("Error:", err)
}func (client *Client) UnbanMember(guildID string, userID string) errorRemoves a ban from a user in a guild. Returns an error if the operation fails.
err := client.UnbanMember("9876543210987654321", "111111111111111111")func (client *Client) AddRole(guildID string, userID string, roleID string) errorAdds a role to a guild member. Returns an error if the operation fails.
err := client.AddRole("9876543210987654321", "111111111111111111", "222222222222222222")func (client *Client) RemoveRole(guildID string, userID string, roleID string) errorRemoves a role from a guild member. Returns an error if the operation fails.
err := client.RemoveRole("9876543210987654321", "111111111111111111", "222222222222222222")func (client *Client) LeaveGuild(guildID string) boolLeaves a guild. Returns true on success.
client.LeaveGuild("9876543210987654321")func (client *Client) SetSlowmode(channelID string, seconds int) boolSets the slowmode delay (in seconds) for a channel. Pass 0 to disable. Returns true on success.
client.SetSlowmode("1234567890123456789", 5) // 5 second slowmodefunc (client *Client) GetUser(userID string) (types.User, error)Fetches a user's profile by ID. Returns the types.User struct or an error.
user, err := client.GetUser("111111111111111111")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(user.Username)func (client *Client) GetProfile(userID string, guildID string) (types.User, error)Fetches the full profile of a user in a guild context. Returns the types.User struct or an error.
user, err := client.GetProfile("111111111111111111", "9876543210987654321")func (client *Client) ModifyUsername(username string, password string) boolChanges the account's username. Requires the account password. Returns true on success.
client.ModifyUsername("NewUsername", "current_password")func (client *Client) SetStatus(status string) boolSets the online status. Valid values: "online", "idle", "dnd", "invisible". Returns true on success.
client.SetStatus("idle")func (client *Client) SetCustomStatus(text string, emoji string) boolSets a custom status message and optional emoji. Pass an empty string for emoji to set a text-only status. Returns true on success.
client.SetCustomStatus("Working on stuff", "🕳️")
client.SetCustomStatus("Just text", "")func (client *Client) ClearCustomStatus() boolRemoves the custom status. Returns true on success.
client.ClearCustomStatus()func (client *Client) SetNickname(guildID string, nickname string) boolChanges the account's nickname in a guild. Pass an empty string to reset the nickname. Returns true on success.
client.SetNickname("9876543210987654321", "MyNickname")
client.SetNickname("9876543210987654321", "") // Reset nicknamefunc (client *Client) SendFriendRequest(username string) boolSends a friend request to a user by username. Returns true on success.
client.SendFriendRequest("someuser")func (client *Client) RemoveFriend(userID string) boolRemoves a friend or cancels an outgoing friend request by user ID. Returns true on success.
client.RemoveFriend("111111111111111111")func (client *Client) BlockUser(userID string) boolBlocks a user by ID. Returns true on success.
client.BlockUser("111111111111111111")func (client *Client) SendSlashCommand(channelID string, guildID string, command types.ApplicationCommand) boolFires a slash command with no options. Get a valid types.ApplicationCommand from discord.GetSlashCommands first. Returns true on success.
client.SendSlashCommand("1234567890123456789", "9876543210987654321", command)func (client *Client) GetMembers(guildID string, memberIDs []string) errorRequests member data for a list of user IDs in a guild. Results arrive asynchronously via the types.GatewayGuildMembersChunk event.
client.GetMembers("9876543210987654321", []string{"111111111111111111", "222222222222222222"})
client.AddHandler(types.GatewayGuildMembersChunk, func(data *types.GuildMembersChunkEventData) {
for _, member := range data.Members {
fmt.Println(member.User.Username)
}
})Defined in types/subscribable.go. Always use these constants with AddHandler rather than raw strings.
const (
GatewayEventReady = "READY"
GatewayEventMessageCreate = "MESSAGE_CREATE"
GatewayEventMessageUpdate = "MESSAGE_UPDATE"
GatewayEventMessageDelete = "MESSAGE_DELETE"
GatewayEventTypingStart = "TYPING_START"
GatewayEventPresenceUpdate = "PRESENCE_UPDATE"
GatewayEventReconnect = "RECONNECT"
GatewayEventInvalidated = "INVALIDATED"
GatewayGuildMembersChunk = "GUILD_MEMBERS_CHUNK"
)AddHandler uses a type assertion on the function value. If the signature does not match exactly, the handler is silently dropped and an error is returned. Always check the return value of AddHandler during development.
if err := client.AddHandler(types.GatewayEventMessageCreate, myHandler); err != nil {
log.Fatal("handler registration failed:", err)
}Lower-level channel functions that take a *discord.Gateway directly. The Client methods above call these internally.
import "github.com/krishnassh/discoself/discord"All functions mirror their Client equivalents but accept *discord.Gateway as the first argument instead.
discord.SendMessage(gateway, channelID, content string) bool
discord.SendTyping(gateway, channelID string) bool
discord.DeleteMessage(gateway, channelID, messageID string) bool
discord.EditMessage(gateway, channelID, messageID, content string) bool
discord.SendMessageWithReply(gateway, channelID, content, replyMessageID string) bool
discord.AddReaction(gateway, channelID, messageID, emoji string) bool
discord.RemoveReaction(gateway, channelID, messageID, emoji string) bool
discord.DeleteAllReactions(gateway, channelID, messageID string) bool
discord.GetChannel(gateway, channelID string) (types.Channel, error)
discord.GetMessage(gateway, channelID, messageID string) (types.MessageData, error)
discord.GetMessages(gateway, channelID string, limit int) ([]types.MessageData, error)
discord.GetPinnedMessages(gateway, channelID string) ([]types.MessageData, error)
discord.PinMessage(gateway, channelID, messageID string) bool
discord.UnpinMessage(gateway, channelID, messageID string) bool
discord.CreateThread(gateway, channelID, messageID, name string) (types.Channel, error)func GetSlashCommands(gateway *Gateway, guildID string) (types.ApplicationCommandIndex, error)Fetches all slash commands available in a guild. Returns an ApplicationCommandIndex containing both Applications []Application and ApplicationCommand []ApplicationCommand.
index, err := discord.GetSlashCommands(gateway, "9876543210987654321")
if err != nil {
fmt.Println("Error:", err)
return
}
for _, cmd := range index.ApplicationCommand {
fmt.Println(cmd.Name, cmd.ApplicationID)
}func GetUserSlashCommands(gateway *Gateway) (types.ApplicationCommandIndex, error)Fetches slash commands available globally to your user (outside any specific guild).
index, err := discord.GetUserSlashCommands(gateway)func SendSlashCommand(gateway *Gateway, channelID string, guildID string, command types.ApplicationCommand) boolLower-level version of client.SendSlashCommand. Takes a *Gateway directly. Fires the command with an empty options list.
func SendSlashCommandWithOptions(gateway *Gateway, channelID string, guildID string, command types.ApplicationCommand, options []any) boolFires a slash command with option values. options is marshalled to JSON and sent as the command's options field.
discord.SendSlashCommandWithOptions(gateway, channelID, guildID, command, []any{"arg1", "arg2"})func ClickButton(gateway *Gateway, e *types.MessageEventData, interactionID string) boolClicks a message component button. e is the message event containing the button. interactionID is the CustomID field of the button component to click.
client.AddHandler(types.GatewayEventMessageCreate, func(e *types.MessageEventData) {
if len(e.Components) > 0 && len(e.Components[0].Buttons) > 0 {
discord.ClickButton(client.Gateway, e, e.Components[0].Buttons[0].CustomID)
}
})Note: MessageComponent.Buttons is a []types.Buttons -- the nested field is named Buttons, not Components.
Internal types and functions. Mostly will be needed directly.
type Gateway struct {
CloseChan chan struct{}
Closed bool
Config *types.Config
Connection *websocket.Conn
GatewayURL string
Handlers Handlers
LastSeq int
Selfbot *Selfbot
SessionID string
ClientBuildNumber string
}func CreateGateway(selfbot *Selfbot, config *types.Config) *GatewayCreates a *Gateway. Called internally by NewClient. config must not be nil.
func (gateway *Gateway) Connect() errorRuns the full connection sequence: dials WebSocket, receives HELLO, starts heartbeat, sends IDENTIFY or RESUME (if a valid session exists), waits for READY, then starts the event loop. Called internally by client.Connect.
func (gateway *Gateway) Close() errorCloses the WebSocket connection and signals the event loop to stop.
func (gateway *Gateway) GetMembers(id string, ids []string) errorSends a REQUEST_GUILD_MEMBERS payload. Called internally by client.GetMembers.
func (handlers *Handlers) Add(event string, function any) errorRegisters a handler on a *Handlers instance. Returns an error if the event name is unrecognised or the function signature does not match. Called internally by client.AddHandler.
func UtcNow() time.TimeReturns the current time in UTC.
func TimeSnowflake(dt time.Time, high bool) int64Converts a time.Time to a Discord snowflake. high=true returns the top of that millisecond's range, high=false returns the bottom. Useful for timestamp-based message history pagination.
snowflake := discord.TimeSnowflake(time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), false)func GenerateNonce() stringGenerates a nonce string from the current time as a snowflake. Used internally when sending messages.
func GenerateSessionID() stringGenerates a random 16-character alphanumeric session ID. Used internally during the IDENTIFY handshake.
func GenerateSuperProperties(gateway *Gateway) stringReturns a base64-encoded JSON string for the X-Super-Properties header. Built from the gateway's config and the logged-in user's locale. Used internally. Computed once after login and cached subsequent calls return the cached value.
type Config struct {
Presence string
ApiVersion string
Browser string
BrowserVersion string
Capabilities int64
Device string
Os string
OsVersion string
UserAgent string
}DefaultConfig is provided as a ready-to-use value:
var DefaultConfig = Config{
Presence: "offline",
ApiVersion: "10",
Browser: "Chrome",
BrowserVersion: "135.0.0.0",
Capabilities: 4093,
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
}Pass &types.DefaultConfig to NewClient. Passing nil will panic.
Key event data types passed to handlers:
type ReadyEventData struct {
Version int `json:"v"`
User User `json:"user"`
Guilds []Guild `json:"guilds"`
SessionID string `json:"session_id"`
ResumeGatewayURL string `json:"resume_gateway_url"`
}type MessageEventData struct {
MessageData
ReferencedMessage MessageData `json:"referenced_message"`
}Embeds MessageData:
type MessageData struct {
ID string `json:"id"`
ChannelID string `json:"channel_id"`
GuildID string `json:"guild_id"`
Author User `json:"author"`
Content string `json:"content"`
Timestamp string `json:"timestamp"`
EditedTimestamp string `json:"edited_timestamp"`
Tts bool `json:"tts"`
MentionEveryone bool `json:"mention_everyone"`
Mentions []User `json:"mentions"`
MentionRoles []string `json:"mention_roles"`
MentionChannels []string `json:"mention_channels"`
Attachments []Attachment `json:"attachments"`
Components []MessageComponent `json:"components"`
Embeds []Embed `json:"embeds"`
Reactions []Reaction `json:"reactions"`
Nonce string `json:"nonce"`
Pinned bool `json:"pinned"`
WebhookID string `json:"webhook_id"`
Type int `json:"type"`
Activity MessageActivity `json:"activity"`
Application MessageApplication `json:"application"`
Flags int `json:"flags"`
ReferencedMessage MessageReference `json:"referenced_message"`
Interaction MessageInteraction `json:"interaction"`
Thread Channel `json:"thread"`
StickerItems []StickerItem `json:"sticker_items"`
}type MessageDeleteEventData struct {
ID string `json:"id"`
ChannelID string `json:"channel_id"`
GuildID string `json:"guild_id"`
}type TypingStartEventData struct {
ChannelID string `json:"channel_id"`
GuildID string `json:"guild_id"`
UserID string `json:"user_id"`
Timestamp int64 `json:"timestamp"`
}type PresenceUpdateEventData struct {
User User `json:"user"`
GuildID string `json:"guild_id"`
Status string `json:"status"`
}Lower-level guild functions that take a *discord.Gateway directly.
import "github.com/krishnassh/discoself/discord"All functions mirror their Client equivalents but accept *discord.Gateway as the first argument.
discord.GetGuild(gateway, guildID string) (types.Guild, error)
discord.GetGuildChannels(gateway, guildID string) ([]types.Channel, error)
discord.GetGuildRoles(gateway, guildID string) ([]types.Role, error)
discord.KickMember(gateway, guildID, userID string) error
discord.BanMember(gateway, guildID, userID string, deleteMessageSeconds int) error
discord.UnbanMember(gateway, guildID, userID string) error
discord.AddRole(gateway, guildID, userID, roleID string) error
discord.RemoveRole(gateway, guildID, userID, roleID string) error
discord.LeaveGuild(gateway, guildID string) bool
discord.SetSlowmode(gateway, channelID string, seconds int) boolLower-level user functions that take a *discord.Gateway directly.
import "github.com/krishnassh/discoself/discord"All functions mirror their Client equivalents but accept *discord.Gateway as the first argument.
discord.GetUser(gateway, userID string) (types.User, error)
discord.GetProfile(gateway, userID, guildID string) (types.User, error)
discord.ModifyUsername(gateway, username, password string) bool
discord.SetStatus(gateway, status string) bool
discord.SetCustomStatus(gateway, text, emoji string) bool
discord.ClearCustomStatus(gateway) bool
discord.SetNickname(gateway, guildID, nickname string) bool
discord.SendFriendRequest(gateway, username string) bool
discord.RemoveFriend(gateway, userID string) bool
discord.BlockUser(gateway, userID string) boolAlso includes lower-level versions of reaction functions:
discord.RemoveReaction(gateway, channelID, messageID, emoji string) bool
discord.DeleteAllReactions(gateway, channelID, messageID string) boolKey shared types:
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Discriminator string `json:"discriminator"`
Avatar string `json:"avatar"`
Bot bool `json:"bot,omitempty"`
System bool `json:"system,omitempty"`
MFAEnabled bool `json:"mfa_enabled,omitempty"`
Banner string `json:"banner,omitempty"`
AccentColor int `json:"accent_color,omitempty"`
Locale string `json:"locale,omitempty"`
Verified bool `json:"verified,omitempty"`
Email string `json:"email,omitempty"`
Flags uint64 `json:"flag,omitempty"`
PremiumType uint64 `json:"premium_type,omitempty"`
PublicFlags uint64 `json:"public_flag,omitempty"`
}Message components (e.g. button rows) use these types:
type MessageComponent struct {
Type int `json:"type"`
Buttons []Buttons `json:"components"`
}
type Buttons struct {
Type int `json:"type,omitempty"`
Style int `json:"style,omitempty"`
Label string `json:"label,omitempty"`
CustomID string `json:"custom_id,omitempty"`
Disabled bool `json:"disabled,omitempty"`
Emoji ButtonEmoji `json:"emoji,omitempty"`
}Note: the nested button slice is accessed as .Buttons, not .Components, despite the JSON key being components.
type ApplicationCommand struct {
ID string `json:"id"`
Type int `json:"type"`
ApplicationID string `json:"application_id"`
Version string `json:"version"`
Name string `json:"name"`
Description string `json:"description"`
}type ApplicationCommandIndex struct {
Applications []Application `json:"applications"`
ApplicationCommand []ApplicationCommand `json:"application_commands"`
Version *string `json:"version,omitempty"`
}