Slack Integration
BATCH IQ integrates with Slack to send notifications and enable conversational interactions via thread replies. This guide covers setup and migration to a different Slack workspace.
⚠️ Critical Steps for Thread Replies
Section titled “⚠️ Critical Steps for Thread Replies”If thread replies aren’t working, check these three “adding” steps first:
- Add Bot to Channel - Invite the bot:
/invite @YourBotNamein each channel - Add Event Subscriptions - Add
message.channelsevent, then Reinstall to Workspace - Add Bot Scopes - Add
channels:historyscope, then Reinstall to Workspace
After each “add” step, you MUST click “Reinstall to Workspace” for changes to take effect!
Quick Migration Checklist
Section titled “Quick Migration Checklist”When moving to a different Slack account/instance:
-
Create new Slack app in new workspace
- Go to https://api.slack.com/apps
- Create new app → “From scratch”
- Name it (e.g., “QC Test Agent Notifications”)
- Select the new workspace
-
Configure bot scopes ⚠️ CRITICAL FOR THREAD REPLIES
- Go to “OAuth & Permissions”
- Add Bot Token Scopes (click “Add an OAuth Scope”):
chat:write- Send messageschat:write.public- Send to channels the bot isn’t in (recommended)channels:history- REQUIRED - Read channel history (for thread replies)groups:history- REQUIRED - Read private channel history (if using private channels)
- IMPORTANT: After adding scopes, you MUST click “Reinstall to Workspace” at the top of the page for changes to take effect
-
Install app to workspace
- Click “Install to Workspace”
- Authorize the app
- Copy the Bot User OAuth Token (starts with
xoxb-)
-
Set up Event Subscriptions ⚠️ CRITICAL FOR THREAD REPLIES
- Enable Events (toggle ON)
- Request URL:
https://your-convex-deployment.convex.site/api/slack/events - Scroll down to “Subscribe to bot events” section
- Add Bot User Event (click the button):
message.channels- REQUIRED - Messages in public channelsmessage.groups- REQUIRED - Messages in private channels (if using private channels)
- IMPORTANT: After adding events, you MUST click “Reinstall to Workspace” at the top of the page
- Verify the webhook shows “Verified ✓” (green checkmark)
- Copy the Signing Secret from “Basic Information” → “App Credentials”
-
Update Convex environment variables
Terminal window cd packages/backend# Set the new bot tokennpx convex env set SLACK_TOKEN xoxb-your-new-token-here# Set the new signing secretnpx convex env set SLACK_SIGNING_SECRET your-new-signing-secret# Optional: Set custom default channel (if different from hardcoded channels)npx convex env set SLACK_CHANNEL #your-default-channel# Verify they're setnpx convex env list -
Create/verify target channels exist
#qc-agent-lims-managers(for LIMS-related notifications)#qc-agent-mes-managers(for MES-related notifications)- Or update channel names in code if using different names
-
Invite bot to all required channels ⚠️ CRITICAL FOR THREAD REPLIES
- The bot must be a member of the channel to receive events
- In each channel, type:
/invite @YourBotName - Verify the bot appears in the channel member list
- Without this step, the bot cannot receive thread replies!
-
Test notification delivery
Terminal window cd packages/backend./test-slack.sh -
Test thread reply functionality
- Post a notification to Slack
- Reply in the thread
- Verify the bot responds
-
(Optional) Migrate/clear database records
- Review
agent_thread_contextstable for Slack thread mappings - Review
slack_processed_eventstable for event deduplication records - Clear or migrate as needed
- Review
Default Channel Routing
Section titled “Default Channel Routing”Notifications are automatically routed to channels based on event type:
- Agent proposals →
#qc-agent-lims-managers - Approval decisions →
#qc-agent-mes-managers - LIMS events →
#qc-agent-lims-managers - MES events →
#qc-agent-mes-managers
To customize channel routing, update the getTargetChannel() method in packages/backend/convex/notifications/channels/slackChannel.ts.
Environment Variables
Section titled “Environment Variables”All Slack configuration is done via Convex environment variables (not .env.local):
| Variable | Description | Required |
|---|---|---|
SLACK_TOKEN | Bot User OAuth Token (xoxb-...) | Yes |
SLACK_SIGNING_SECRET | Signing secret for webhook verification | Yes |
SLACK_CHANNEL | Default fallback channel | No |
Testing
Section titled “Testing”After setup, verify the integration:
# Test Slack API connectionnpx convex run notifications/test:testSlackIntegration --no-push
# Test Slack channel implementationnpx convex run notifications/test:testSlackChannel --no-pushOr use the convenience script:
cd packages/backend./test-slack.shTroubleshooting
Section titled “Troubleshooting”Missing Token Error
Section titled “Missing Token Error”If you see SLACK_TOKEN not configured, ensure you’ve set it in Convex:
npx convex env set SLACK_TOKEN xoxb-your-tokenInvalid Token Error
Section titled “Invalid Token Error”- Verify you’re using a Bot User OAuth Token (starts with
xoxb-) - Ensure the app is installed to the workspace
- Check that required scopes are added and app is reinstalled
Webhook Verification Failed
Section titled “Webhook Verification Failed”- Verify
SLACK_SIGNING_SECRETis set correctly - Check that the webhook URL in Slack matches your Convex deployment URL
- Ensure the webhook URL is publicly accessible
Bot Not Responding in Threads
Section titled “Bot Not Responding in Threads”If notifications work but thread replies don’t, check these items in order:
1. Event Subscriptions Configuration
Section titled “1. Event Subscriptions Configuration”Most common issue - The bot must be subscribed to message events:
- Go to your Slack app → Event Subscriptions
- Verify Enable Events is turned ON
- Check Request URL matches:
https://your-deployment.convex.site/api/slack/events - Scroll down to “Subscribe to bot events” section
- CRITICAL: Click “Add Bot User Event” and add:
message.channels(required for public channels)message.groups(required for private channels)
- IMPORTANT: After adding events, click “Reinstall to Workspace” at the top of the page
- Verify the webhook shows “Verified ✓” (green checkmark)
- If events are missing, the bot will NOT receive thread replies!
2. Required Bot Scopes
Section titled “2. Required Bot Scopes”The bot needs these scopes to read and respond to threads:
- Go to OAuth & Permissions
- Under Bot Token Scopes, click “Add an OAuth Scope” and add:
chat:write- Send messageschat:write.public- Send to channels bot isn’t inchannels:history- REQUIRED to read thread messagesgroups:history- REQUIRED for private channels
- CRITICAL: After adding scopes, click “Reinstall to Workspace” at the top of the page
- Without
channels:history, the bot cannot read thread messages!
3. Bot Invited to Channel
Section titled “3. Bot Invited to Channel”CRITICAL STEP - The bot must be a member of the channel to receive events:
- In Slack, go to the channel where notifications are posted
- Type:
/invite @YourBotName(replace with your actual bot name) - Verify the bot appears in the channel member list
- If the bot is not in the channel, it will NOT receive thread reply events!
- You must invite the bot to every channel where you want thread replies to work
4. Signature Verification
Section titled “4. Signature Verification”Check Convex logs for signature errors:
- Check your Convex dashboard logs
- Look for
[SlackHandler] Invalid signatureor[SlackHandler] Missing signature headers - Verify
SLACK_SIGNING_SECRETis set correctly:Terminal window npx convex env list | grep SLACK_SIGNING_SECRET - Copy the Signing Secret from Slack app → Basic Information → App Credentials
- Update if needed:
Terminal window npx convex env set SLACK_SIGNING_SECRET your-signing-secret
5. Check Convex Logs
Section titled “5. Check Convex Logs”Look for these log messages when you reply to a thread:
Good signs (events are being received):
[SlackHandler] Received thread reply, scheduling async:[SlackHandler] Processing message async:
Bad signs (events being filtered):
[SlackHandler] Ignoring top-level message (not a thread reply)- You replied to the channel, not the thread[SlackHandler] Ignoring duplicate event:- Event was already processed[SlackHandler] Invalid signature- Signature verification failed[SlackHandler] Missing signature headers- Headers not present
Errors to watch for:
[SlackHandler] Failed to fetch thread parent:- Bot can’t read thread (check scopes)[SlackHandler] Failed to post response:- Bot can’t reply (check scopes/permissions)
6. Verify You’re Replying in a Thread
Section titled “6. Verify You’re Replying in a Thread”The bot only responds to thread replies, not top-level messages:
- Click the notification message to open the thread
- Type your reply in the thread (not in the main channel)
- The reply should appear indented under the notification
7. Test Webhook Manually
Section titled “7. Test Webhook Manually”Verify the webhook URL is accessible:
# Test if the endpoint is reachable (should return 400 for invalid JSON, not 404)curl -X POST https://your-deployment.convex.site/api/slack/events \ -H "Content-Type: application/json" \ -d '{"test": "data"}'If you get 404, the route isn’t configured. If you get 401, signature verification is working (expected without proper signature).
8. Check Event Delivery in Slack
Section titled “8. Check Event Delivery in Slack”- Go to Slack app → Event Subscriptions
- Scroll down to Recent Events
- Reply to a thread
- Check if a new event appears in the list
- If no events appear, the webhook URL might be wrong or unreachable
9. Verify Environment Variables
Section titled “9. Verify Environment Variables”Ensure all required variables are set in production:
# Check all Slack-related env varsnpx convex env list | grep SLACK
# Should show:# SLACK_TOKEN=xoxb-...# SLACK_SIGNING_SECRET=...10. Common Mistakes
Section titled “10. Common Mistakes”- ❌ Bot not invited to the channel (most common - bot must be a member!)
- ❌ Added scopes but didn’t reinstall the app (must click “Reinstall to Workspace”)
- ❌ Added event subscriptions but didn’t reinstall the app (must click “Reinstall to Workspace”)
- ❌ Replying to the channel instead of the thread
- ❌ Webhook URL pointing to wrong deployment
- ❌ Using user token instead of bot token
- ❌ Missing
channels:historyscope - ❌ Missing
message.channelsevent subscription