Slack¶
The Slack provider uses slack-go with Socket Mode for real-time events.
Installation¶
Configuration¶
import "github.com/plexusone/omnichat/providers/slack"
p, err := slack.New(slack.Config{
BotToken: "xoxb-...", // Bot token
AppToken: "xapp-...", // App-level token for Socket Mode
Logger: slog.Default(),
})
Config Options¶
| Field | Type | Required | Description |
|---|---|---|---|
BotToken |
string |
Yes | Bot token (xoxb-...) |
AppToken |
string |
Yes | App token (xapp-...) for Socket Mode |
Logger |
*slog.Logger |
No | Logger instance |
Creating a Slack App¶
- Go to Slack API
- Click Create New App > From scratch
- Name your app and select a workspace
Enable Socket Mode¶
- Go to Socket Mode in sidebar
- Enable Socket Mode
- Create an App-Level Token with
connections:writescope - Save the token (
xapp-...)
Bot Token Scopes¶
Go to OAuth & Permissions and add these scopes:
| Scope | Purpose |
|---|---|
chat:write |
Send messages |
channels:history |
Read channel messages |
groups:history |
Read private channel messages |
im:history |
Read DM messages |
mpim:history |
Read group DM messages |
users:read |
Get user information |
reactions:read |
Read reactions |
Event Subscriptions¶
Go to Event Subscriptions and subscribe to:
| Event | Description |
|---|---|
message.channels |
Messages in public channels |
message.groups |
Messages in private channels |
message.im |
Direct messages |
message.mpim |
Group direct messages |
reaction_added |
Reactions added to messages |
member_joined_channel |
Users joining channels |
Install to Workspace¶
- Go to Install App
- Click Install to Workspace
- Authorize the app
- Copy the Bot Token (
xoxb-...)
Usage¶
Basic Setup¶
package main
import (
"context"
"log/slog"
"os"
"github.com/plexusone/omnichat/provider"
"github.com/plexusone/omnichat/providers/slack"
)
func main() {
logger := slog.Default()
p, err := slack.New(slack.Config{
BotToken: os.Getenv("SLACK_BOT_TOKEN"),
AppToken: os.Getenv("SLACK_APP_TOKEN"),
Logger: logger,
})
if err != nil {
panic(err)
}
router := provider.NewRouter(logger)
router.Register(p)
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
return router.Send(ctx, "slack", msg.ChatID, provider.OutgoingMessage{
Content: "Hello from Slack!",
})
})
ctx := context.Background()
router.ConnectAll(ctx)
defer router.DisconnectAll(ctx)
select {}
}
Sending Messages¶
// Simple message
router.Send(ctx, "slack", channelID, provider.OutgoingMessage{
Content: "Hello, Slack!",
})
// Reply in thread
router.Send(ctx, "slack", channelID, provider.OutgoingMessage{
Content: "This is a thread reply",
ReplyTo: parentMessageTS, // Thread timestamp
})
Sending Media¶
// Send a file
router.Send(ctx, "slack", channelID, provider.OutgoingMessage{
Content: "Here's the report:",
Media: []provider.Media{{
Type: provider.MediaTypeDocument,
Data: fileBytes,
Filename: "report.pdf",
MimeType: "application/pdf",
}},
})
// Send an image
router.Send(ctx, "slack", channelID, provider.OutgoingMessage{
Media: []provider.Media{{
Type: provider.MediaTypeImage,
Data: imageBytes,
Filename: "screenshot.png",
MimeType: "image/png",
}},
})
Message Mapping¶
| Slack | OmniChat |
|---|---|
| Channel ID | ChatID |
| Message TS | ID |
| User ID | SenderID |
| User Name | SenderName |
| Text | Content |
| Thread TS | ReplyTo |
| Files | Media |
| IM Channel | IsDM = true |
Event Handling¶
The provider handles these Slack events:
Messages¶
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
// msg.Content contains the message text
// msg.ChatID is the channel ID
// msg.ReplyTo is set if this is a thread reply
return nil
})
Reactions¶
Reactions are delivered as messages with special content:
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
if strings.HasPrefix(msg.Content, ":") && strings.HasSuffix(msg.Content, ":") {
// This is a reaction
emoji := strings.Trim(msg.Content, ":")
log.Printf("Reaction %s added", emoji)
}
return nil
})
Member Joins¶
Member join events are delivered as system messages.
Channel Types¶
| Type | IsDM |
Description |
|---|---|---|
| Public channel | false |
C... prefix |
| Private channel | false |
G... prefix |
| Direct message | true |
D... prefix |
| Group DM | true |
G... prefix |
Environment Variables¶
Troubleshooting¶
Bot not receiving messages¶
- Verify Socket Mode is enabled
- Check Event Subscriptions are configured
- Ensure bot is invited to channels (
/invite @botname) - Verify App Token has
connections:writescope
Permission errors¶
- Check OAuth scopes in app settings
- Reinstall app after adding scopes
- Verify bot is a member of the channel
Connection drops¶
Socket Mode reconnects automatically. For persistent issues:
- Check App Token is valid
- Verify network connectivity
- Check Slack status page
Rate limiting¶
Slack has rate limits (~1 message/second per channel). The provider handles backoff automatically.
Limitations¶
- No support for Block Kit (rich messages) through OmniChat interface
- Reactions are simplified to emoji strings
- Thread replies require parent message timestamp