This example runs a tiny Slack bot with Postgres-backed runtime state. When the bot is mentioned in a channel, or messaged directly if you enable the DM event, it subscribes the thread and replies. Later messages in that subscribed thread are routed through Postgres-backed state.
Create or open a Slack app from the Slack app dashboard:
In OAuth & Permissions, add these Bot Token Scopes:
| Scope | Why this example needs it |
|---|---|
chat:write |
Send replies with chat.postMessage. |
app_mentions:read |
Receive app_mention events when the bot is mentioned. |
im:history |
Optional for channel-only testing, required if you subscribe to message.im so direct messages reach the bot. |
This example does not use ephemeral DM fallback. If you change it to call
PostEphemeral with FallbackToDM: true, also add im:write so the adapter can
open a DM with conversations.open.
In App Home:
- Under Show Tabs, enable the Messages Tab.
- Make the Messages tab writable. Depending on Slack's current UI, this appears as disabling read-only mode or enabling Allow users to send Slash commands and messages from the messages tab.
If Slack shows "Sending messages to this app has been turned off" in the app DM, this App Home Messages tab setting is still off or read-only.
In Event Subscriptions:
-
Enable events.
-
Set the request URL to:
https://YOUR_PUBLIC_HOST/webhooks/slack -
Subscribe to these Bot User Events:
app_mention message.im -
Save changes.
After changing scopes, App Home settings, or event subscriptions, reinstall the app from OAuth & Permissions so Slack applies the new configuration to your workspace.
The app must be reachable from Slack. For local development, expose port 8080
with a tunnel such as ngrok, cloudflared, or Tailscale Funnel, then use that
public HTTPS URL as YOUR_PUBLIC_HOST.
- Go to OAuth & Permissions.
- Click Install to Workspace or Reinstall to Workspace after changing scopes, App Home settings, or event subscriptions.
- Copy Bot User OAuth Token. It starts with
xoxb-; use it asSLACK_BOT_TOKEN. - Go to Basic Information.
- In App Credentials, copy Signing Secret; use it as
SLACK_SIGNING_SECRET.
Treat both values like passwords.
From this example directory:
cd examples/slack-postgres-state
docker compose up -d postgresOr let Pitchfork supervise the service:
cd examples/slack-postgres-state
pitchfork start postgresThe database URL for the local Compose service is:
postgres://chat_sdk_go:chat_sdk_go@127.0.0.1:54330/chat_sdk_go?sslmode=disable
To stop Postgres:
docker compose downTo delete the Postgres volume:
docker compose down -vFrom this example directory:
export SLACK_SIGNING_SECRET="..."
export SLACK_BOT_TOKEN="xoxb-..."
export DATABASE_URL="postgres://chat_sdk_go:chat_sdk_go@127.0.0.1:54330/chat_sdk_go?sslmode=disable"
export PORT=8080
go run .In Slack, mention the bot in a channel where it is present:
@your-bot hello
The bot replies in the same thread and subscribes the thread:
hello world from Postgres state. This thread is now subscribed.
Send another message in the same Slack thread. The bot should route it as a subscribed message and reply:
Postgres remembered this subscribed thread.
- Runtime state is stored in Postgres, so subscriptions, dedupe data, and locks can survive process restarts while Postgres is still running.
- The Postgres state adapter creates its runtime coordination tables on startup.
- Slack URL verification is handled by the Slack adapter at
/webhooks/slack. - Slack request signatures are verified with
SLACK_SIGNING_SECRET. - The bot token is used for
auth.testduring adapter startup andchat.postMessagewhen replying.
Relevant Slack docs:
- App dashboard: https://api.slack.com/apps
- Events API request URLs: https://docs.slack.dev/apis/events-api/
app_mentionevent: https://docs.slack.dev/reference/events/app_mention/message.imevent: https://docs.slack.dev/reference/events/message.im- App Home Messages tab: https://docs.slack.dev/surfaces/app-home
chat:writescope: https://docs.slack.dev/reference/scopes/chat.writeconversations.openscopes: https://docs.slack.dev/reference/methods/conversations.open/- Bot tokens and
xoxb-tokens: https://docs.slack.dev/authentication/tokens