Slack ChatGPT Bot: Team Productivity Integration 2026

Bring ChatGPT intelligence directly into your Slack channels for instant answers, workflow automation, and seamless team collaboration. Engineering teams using Slack ChatGPT bots report a 50% reduction in context switching and 30% faster decision-making. Instead of toggling between Slack and ChatGPT browser tabs, your team gets AI-powered insights exactly where conversations happen.

This comprehensive guide walks you through building a production-ready Slack ChatGPT bot with OAuth authentication, event-driven messaging, slash commands, and interactive components. Whether you're an engineering manager looking to boost productivity or a DevOps engineer automating incident response, you'll learn how to integrate ChatGPT's conversational AI into your Slack workspace using the official Slack Bolt SDK and MCP server architecture.

By the end of this tutorial, you'll have a fully functional Slack bot that responds to mentions, processes slash commands, handles interactive components, and scales across multiple workspaces with OAuth 2.0.

Why Build a Slack ChatGPT Bot

Slack ChatGPT bot integration transforms how engineering teams access AI-powered assistance without disrupting their workflow. Instead of forcing developers to context-switch between communication tools and AI interfaces, the bot brings intelligence directly into Slack threads.

Real-World Use Cases:

  • Q&A Bot: Answer technical questions in #engineering channels without leaving Slack
  • Code Review Assistant: Analyze pull request snippets pasted in Slack threads
  • Standup Summaries: Generate daily standup reports from channel activity
  • Incident Response: Provide troubleshooting steps during outages in #incidents
  • Documentation Search: Query internal knowledge bases via natural language
  • Translation: Convert messages between languages for distributed teams

Team Productivity Benefits:

Teams report significant productivity gains after deploying Slack ChatGPT bots:

  • 50% reduction in context switching: No more toggling between browser tabs
  • 30% faster decision-making: Instant access to AI insights during discussions
  • Improved knowledge sharing: AI answers visible to entire channel, not just one person
  • Asynchronous collaboration: Bot responds 24/7 across time zones
  • Reduced interruptions: Answer common questions without pinging senior engineers

Technical Advantages:

Slack's event-driven architecture makes it ideal for ChatGPT integration:

  • Real-time messaging: Sub-second bot responses via WebSocket connections
  • Rich UI components: Buttons, modals, and interactive elements for complex workflows
  • Enterprise-grade security: OAuth 2.0, token encryption, workspace-level permissions
  • Scalable infrastructure: Handles thousands of messages/hour with proper rate limiting
  • Developer-friendly API: Bolt SDK abstracts complexity with middleware patterns

For teams already using MakeAIHQ's ChatGPT app builder, integrating your existing MCP server with Slack takes minutes instead of days.

Prerequisites and Setup

Before building your Slack ChatGPT bot, ensure you have the following requirements in place:

Slack Workspace Requirements:

  • Admin access to create and configure Slack apps
  • Development workspace for testing (create a free workspace at slack.com if needed)
  • App creation permissions (Workspace Admins or Owners only)

Development Environment:

  • Node.js 18+ installed with npm/yarn
  • Slack Bolt SDK (@slack/bolt package)
  • ChatGPT MCP server endpoint (build one with MakeAIHQ's AI Conversational Editor)
  • HTTPS endpoint for Slack event delivery (use ngrok for local development)

Technical Knowledge:

  • Familiarity with Express.js/Node.js middleware patterns
  • Understanding of OAuth 2.0 flows
  • Basic knowledge of Slack's event-driven architecture
  • Experience with async/await JavaScript

Optional Tools:

  • Database for multi-workspace OAuth token storage (PostgreSQL, MongoDB, or Firestore)
  • Redis for rate limiting and caching
  • Logging service (Datadog, Splunk) for production monitoring

If you're new to Slack bot development, review the official Slack API documentation and explore Slack Bolt SDK examples before proceeding.

Implementation Guide

Step 1: Create Slack App and Configure Manifest

Navigate to api.slack.com/apps and click Create New AppFrom an app manifest. Select your development workspace and paste this complete app manifest:

display_information:
  name: ChatGPT Team Assistant
  description: AI-powered assistant for instant answers and workflow automation
  background_color: "#0A0E27"
  long_description: "Bring ChatGPT intelligence to your Slack workspace. Ask questions, summarize threads, translate messages, and automate workflows without leaving Slack. Built with MakeAIHQ's ChatGPT app platform."

features:
  app_home:
    home_tab_enabled: true
    messages_tab_enabled: true
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: ChatGPT Bot
    always_online: true
  slash_commands:
    - command: /chatgpt-ask
      url: https://your-domain.com/slack/commands
      description: Ask ChatGPT a question
      usage_hint: "[your question]"
      should_escape: false
    - command: /chatgpt-summarize
      url: https://your-domain.com/slack/commands
      description: Summarize recent channel messages
      usage_hint: "[number of messages]"
      should_escape: false
    - command: /chatgpt-translate
      url: https://your-domain.com/slack/commands
      description: Translate text to another language
      usage_hint: "[target language] [text]"
      should_escape: false

oauth_config:
  redirect_urls:
    - https://your-domain.com/slack/oauth_redirect
  scopes:
    bot:
      - app_mentions:read
      - channels:history
      - channels:read
      - chat:write
      - chat:write.public
      - commands
      - files:read
      - im:history
      - im:read
      - im:write
      - users:read

settings:
  event_subscriptions:
    request_url: https://your-domain.com/slack/events
    bot_events:
      - app_mention
      - message.channels
      - message.im
      - file_shared
  interactivity:
    is_enabled: true
    request_url: https://your-domain.com/slack/interactions
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: true

Key Configuration Points:

  • Event Request URL: Replace your-domain.com with your HTTPS endpoint (use ngrok for local testing: ngrok http 3000)
  • OAuth Scopes: Minimal permissions for read/write messages and respond to mentions
  • Slash Commands: Three example commands (add more as needed)
  • Token Rotation: Enabled for security best practices

After creating the app, navigate to Basic Information and copy your Signing Secret and App Credentials (Client ID, Client Secret). You'll need these for OAuth and request verification.

Step 2: Build Event Handler for Messages

Install the Slack Bolt SDK and create your main bot server:

npm install @slack/bolt dotenv

Create bot.js with a complete event handler:

const { App } = require('@slack/bolt');
const axios = require('axios');
require('dotenv').config();

// Initialize Bolt app with credentials
const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: process.env.SLACK_STATE_SECRET,
  scopes: ['app_mentions:read', 'channels:history', 'chat:write', 'chat:write.public', 'commands'],
  installationStore: {
    storeInstallation: async (installation) => {
      // Store OAuth tokens in your database
      // Replace with your database logic (Firestore, PostgreSQL, etc.)
      console.log('Storing installation:', installation);
      return;
    },
    fetchInstallation: async (installQuery) => {
      // Fetch OAuth tokens from your database
      console.log('Fetching installation:', installQuery);
      return null; // Replace with database query
    },
    deleteInstallation: async (installQuery) => {
      // Delete OAuth tokens from database
      console.log('Deleting installation:', installQuery);
      return;
    },
  },
});

// Event handler for app mentions (@ChatGPT Bot)
app.event('app_mention', async ({ event, context, client, say }) => {
  try {
    // Extract user message (remove bot mention)
    const userMessage = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();

    // Get user info for personalization
    const userInfo = await client.users.info({ user: event.user });
    const userName = userInfo.user.real_name || userInfo.user.name;

    // Show typing indicator
    await client.chat.postMessage({
      channel: event.channel,
      thread_ts: event.thread_ts || event.ts,
      text: '_Thinking..._',
    });

    // Call ChatGPT MCP server
    const chatgptResponse = await callChatGPTMCP({
      prompt: userMessage,
      userId: event.user,
      userName: userName,
      context: 'slack_mention',
    });

    // Post ChatGPT response in thread
    await say({
      text: chatgptResponse,
      thread_ts: event.thread_ts || event.ts,
      blocks: [
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: chatgptResponse,
          },
        },
        {
          type: 'actions',
          elements: [
            {
              type: 'button',
              text: { type: 'plain_text', text: 'Follow-up Question' },
              action_id: 'follow_up_question',
              value: event.ts,
            },
            {
              type: 'button',
              text: { type: 'plain_text', text: 'Share with Team' },
              action_id: 'share_response',
              value: event.ts,
              style: 'primary',
            },
          ],
        },
      ],
    });

  } catch (error) {
    console.error('Error handling app mention:', error);
    await say({
      text: `Sorry, I encountered an error: ${error.message}`,
      thread_ts: event.thread_ts || event.ts,
    });
  }
});

// Event handler for direct messages
app.event('message', async ({ event, context, client, say }) => {
  // Ignore bot messages and threaded replies (handled by app_mention)
  if (event.subtype || event.thread_ts) return;

  try {
    const chatgptResponse = await callChatGPTMCP({
      prompt: event.text,
      userId: event.user,
      context: 'slack_dm',
    });

    await say({
      text: chatgptResponse,
      thread_ts: event.ts,
    });

  } catch (error) {
    console.error('Error handling DM:', error);
    await say(`Error: ${error.message}`);
  }
});

// Helper function to call ChatGPT MCP server
async function callChatGPTMCP({ prompt, userId, userName = 'User', context = 'slack' }) {
  try {
    const response = await axios.post(process.env.CHATGPT_MCP_ENDPOINT, {
      messages: [
        {
          role: 'system',
          content: `You are a helpful Slack bot assistant. User: ${userName} (${userId}). Context: ${context}`,
        },
        {
          role: 'user',
          content: prompt,
        },
      ],
      max_tokens: 500,
      temperature: 0.7,
    }, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.CHATGPT_API_KEY}`,
      },
      timeout: 25000, // Slack requires response within 3 seconds, but we handle async
    });

    return response.data.choices[0].message.content;

  } catch (error) {
    console.error('ChatGPT MCP error:', error.response?.data || error.message);
    throw new Error('Failed to get response from ChatGPT');
  }
}

// Start the app
(async () => {
  const port = process.env.PORT || 3000;
  await app.start(port);
  console.log(`⚡️ Slack ChatGPT bot is running on port ${port}`);
})();

Environment Variables (.env):

SLACK_SIGNING_SECRET=your_signing_secret
SLACK_CLIENT_ID=your_client_id
SLACK_CLIENT_SECRET=your_client_secret
SLACK_STATE_SECRET=random_secret_for_oauth_state
CHATGPT_MCP_ENDPOINT=https://your-mcp-server.com/chat
CHATGPT_API_KEY=your_api_key
PORT=3000

This event handler listens for app_mention and message events, calls your ChatGPT MCP server, and posts responses in threads. The interactive buttons enable follow-up questions and team sharing.

Step 3: Implement Slash Commands

Slash commands provide explicit bot interactions. Add this handler to bot.js:

// Slash command: /chatgpt-ask [question]
app.command('/chatgpt-ask', async ({ command, ack, client, respond }) => {
  await ack(); // Acknowledge command immediately (required within 3 seconds)

  try {
    const question = command.text.trim();

    if (!question) {
      return await respond({
        response_type: 'ephemeral',
        text: 'Usage: `/chatgpt-ask [your question]`',
      });
    }

    // Post public message to channel
    await respond({
      response_type: 'in_channel',
      text: `<@${command.user_id}> asked: "${question}"`,
    });

    // Get ChatGPT response
    const answer = await callChatGPTMCP({
      prompt: question,
      userId: command.user_id,
      context: 'slash_command',
    });

    // Post answer
    await respond({
      response_type: 'in_channel',
      text: answer,
      blocks: [
        {
          type: 'section',
          text: { type: 'mrkdwn', text: `*Answer:*\n${answer}` },
        },
      ],
    });

  } catch (error) {
    console.error('Error in /chatgpt-ask:', error);
    await respond({
      response_type: 'ephemeral',
      text: `Error: ${error.message}`,
    });
  }
});

// Slash command: /chatgpt-summarize [number]
app.command('/chatgpt-summarize', async ({ command, ack, client, respond }) => {
  await ack();

  try {
    const messageCount = parseInt(command.text.trim()) || 10;

    // Fetch recent messages from channel
    const result = await client.conversations.history({
      channel: command.channel_id,
      limit: Math.min(messageCount, 100), // Max 100 messages
    });

    // Extract message text
    const messages = result.messages
      .filter(msg => !msg.subtype && msg.text) // Ignore system messages
      .map(msg => msg.text)
      .reverse()
      .join('\n');

    // Get summary from ChatGPT
    const summary = await callChatGPTMCP({
      prompt: `Summarize these Slack messages concisely:\n\n${messages}`,
      userId: command.user_id,
      context: 'summarize',
    });

    await respond({
      response_type: 'in_channel',
      text: `*Channel Summary (last ${messageCount} messages):*\n${summary}`,
    });

  } catch (error) {
    console.error('Error in /chatgpt-summarize:', error);
    await respond({
      response_type: 'ephemeral',
      text: `Error: ${error.message}`,
    });
  }
});

// Slash command: /chatgpt-translate [language] [text]
app.command('/chatgpt-translate', async ({ command, ack, respond }) => {
  await ack();

  try {
    const parts = command.text.split(' ');
    const targetLanguage = parts[0];
    const textToTranslate = parts.slice(1).join(' ');

    if (!targetLanguage || !textToTranslate) {
      return await respond({
        response_type: 'ephemeral',
        text: 'Usage: `/chatgpt-translate [language] [text]`\nExample: `/chatgpt-translate spanish Hello world`',
      });
    }

    const translation = await callChatGPTMCP({
      prompt: `Translate to ${targetLanguage}: ${textToTranslate}`,
      userId: command.user_id,
      context: 'translate',
    });

    await respond({
      response_type: 'in_channel',
      text: `*Translation (${targetLanguage}):*\n${translation}`,
    });

  } catch (error) {
    console.error('Error in /chatgpt-translate:', error);
    await respond({
      response_type: 'ephemeral',
      text: `Error: ${error.message}`,
    });
  }
});

Each slash command acknowledges within 3 seconds (Slack requirement), processes the request asynchronously, and posts results to the channel. Responses use response_type: 'in_channel' for visibility or 'ephemeral' for private messages.

Step 4: Add Interactive Components

Interactive components (buttons, modals, message actions) enable rich user experiences. Add these handlers:

// Handle "Follow-up Question" button
app.action('follow_up_question', async ({ ack, body, client }) => {
  await ack();

  try {
    // Open modal for follow-up input
    await client.views.open({
      trigger_id: body.trigger_id,
      view: {
        type: 'modal',
        callback_id: 'follow_up_modal',
        title: { type: 'plain_text', text: 'Follow-up Question' },
        submit: { type: 'plain_text', text: 'Ask' },
        close: { type: 'plain_text', text: 'Cancel' },
        private_metadata: JSON.stringify({
          channel: body.channel.id,
          thread_ts: body.message.thread_ts || body.message.ts,
        }),
        blocks: [
          {
            type: 'input',
            block_id: 'question_input',
            element: {
              type: 'plain_text_input',
              action_id: 'question',
              multiline: true,
              placeholder: { type: 'plain_text', text: 'Ask a follow-up question...' },
            },
            label: { type: 'plain_text', text: 'Your Question' },
          },
        ],
      },
    });

  } catch (error) {
    console.error('Error opening modal:', error);
  }
});

// Handle modal submission
app.view('follow_up_modal', async ({ ack, body, view, client }) => {
  await ack();

  try {
    const metadata = JSON.parse(view.private_metadata);
    const question = view.state.values.question_input.question.value;

    // Get ChatGPT response
    const answer = await callChatGPTMCP({
      prompt: question,
      userId: body.user.id,
      context: 'follow_up',
    });

    // Post answer in original thread
    await client.chat.postMessage({
      channel: metadata.channel,
      thread_ts: metadata.thread_ts,
      text: answer,
      blocks: [
        {
          type: 'section',
          text: { type: 'mrkdwn', text: `*Follow-up Answer:*\n${answer}` },
        },
      ],
    });

  } catch (error) {
    console.error('Error handling modal submission:', error);
  }
});

// Handle "Share with Team" button
app.action('share_response', async ({ ack, body, client }) => {
  await ack();

  try {
    // Post original message to channel (remove thread)
    await client.chat.postMessage({
      channel: body.channel.id,
      text: `<@${body.user.id}> shared this AI response:`,
      blocks: body.message.blocks,
    });

    // Send ephemeral confirmation
    await client.chat.postEphemeral({
      channel: body.channel.id,
      user: body.user.id,
      text: '✅ Response shared with the channel!',
    });

  } catch (error) {
    console.error('Error sharing response:', error);
  }
});

These interactive components create a conversational flow: mention the bot → get response with buttons → click "Follow-up Question" → modal appears → submit → answer posted in thread. The "Share with Team" button promotes AI responses from threads to main channel.

Step 5: OAuth Installation Flow

For multi-workspace distribution, implement OAuth 2.0:

// OAuth installation route
app.get('/slack/install', async (req, res) => {
  try {
    // Generate OAuth URL with state for CSRF protection
    const url = `https://slack.com/oauth/v2/authorize?client_id=${process.env.SLACK_CLIENT_ID}&scope=${encodeURIComponent('app_mentions:read,channels:history,chat:write,chat:write.public,commands')}&state=${generateStateSecret()}`;

    res.redirect(url);
  } catch (error) {
    console.error('OAuth install error:', error);
    res.status(500).send('Error initiating OAuth');
  }
});

// OAuth callback route
app.get('/slack/oauth_redirect', async (req, res) => {
  try {
    const { code, state } = req.query;

    // Verify state to prevent CSRF
    if (!verifyStateSecret(state)) {
      return res.status(403).send('Invalid state parameter');
    }

    // Exchange code for access token
    const result = await app.client.oauth.v2.access({
      client_id: process.env.SLACK_CLIENT_ID,
      client_secret: process.env.SLACK_CLIENT_SECRET,
      code,
    });

    // Store installation in database
    await storeInstallation({
      teamId: result.team.id,
      teamName: result.team.name,
      botToken: result.access_token,
      botUserId: result.bot_user_id,
      userId: result.authed_user.id,
      scope: result.scope,
      installedAt: new Date(),
    });

    res.send('<h1>Success!</h1><p>ChatGPT Bot installed. Return to Slack and type <code>@ChatGPT Bot hello</code> to test.</p>');

  } catch (error) {
    console.error('OAuth callback error:', error);
    res.status(500).send('OAuth failed');
  }
});

// Helper functions for OAuth state management
function generateStateSecret() {
  return require('crypto').randomBytes(32).toString('hex');
}

function verifyStateSecret(state) {
  // Implement state verification (store in Redis with TTL)
  return true; // Replace with actual verification
}

async function storeInstallation(installation) {
  // Store in your database (Firestore, PostgreSQL, MongoDB)
  console.log('Storing installation:', installation);
  // Example Firestore:
  // await db.collection('slack_installations').doc(installation.teamId).set(installation);
}

The OAuth flow enables users to install your bot in any Slack workspace. Store tokens securely in a database with encryption. For production apps, implement token rotation and webhook signature verification.

Advanced Features

Thread-Aware Conversations:

Track conversation context across Slack threads by storing message history:

const conversationHistory = new Map(); // Replace with Redis for production

app.event('app_mention', async ({ event, say }) => {
  const threadKey = `${event.channel}_${event.thread_ts || event.ts}`;

  // Retrieve thread history
  const history = conversationHistory.get(threadKey) || [];
  history.push({ role: 'user', content: event.text });

  // Send full history to ChatGPT for context
  const response = await callChatGPTMCP({
    messages: history,
    userId: event.user,
  });

  history.push({ role: 'assistant', content: response });
  conversationHistory.set(threadKey, history.slice(-10)); // Keep last 10 messages

  await say({ text: response, thread_ts: event.thread_ts || event.ts });
});

Channel-Specific Knowledge Bases:

Customize bot behavior per channel by loading channel-specific context:

const channelKnowledge = {
  'C123456': 'This is #engineering. Provide technical answers with code examples.',
  'C789012': 'This is #sales. Focus on business value and ROI.',
};

app.event('app_mention', async ({ event, say }) => {
  const channelContext = channelKnowledge[event.channel] || 'General workspace';

  const response = await callChatGPTMCP({
    prompt: `${channelContext}\n\nUser question: ${event.text}`,
    userId: event.user,
  });

  await say({ text: response });
});

File Attachment Processing:

Process files shared in Slack (PDFs, images, code files):

app.event('file_shared', async ({ event, client, say }) => {
  try {
    // Get file info
    const fileInfo = await client.files.info({ file: event.file_id });
    const file = fileInfo.file;

    // Download file content (requires files:read scope)
    const fileContent = await axios.get(file.url_private, {
      headers: { 'Authorization': `Bearer ${process.env.SLACK_BOT_TOKEN}` },
    });

    // Send to ChatGPT for analysis
    const analysis = await callChatGPTMCP({
      prompt: `Analyze this file:\n\n${fileContent.data}`,
      userId: event.user_id,
    });

    await say({
      text: `File analysis for *${file.name}*:\n${analysis}`,
      channel: event.channel_id,
    });

  } catch (error) {
    console.error('File processing error:', error);
  }
});

Scheduled Messages with Cron:

Send daily summaries or reminders using cron jobs:

const cron = require('node-cron');

// Daily standup reminder at 9 AM
cron.schedule('0 9 * * 1-5', async () => {
  await app.client.chat.postMessage({
    channel: 'C123456', // #engineering channel
    text: '🌅 Good morning! Ready for standup? Use `/chatgpt-summarize 50` to review yesterday\'s activity.',
  });
});

For more advanced integrations, explore MakeAIHQ's template marketplace with pre-built ChatGPT workflows for Slack.

Testing and Validation

1. Local Testing with ngrok:

Start your bot locally and expose it with ngrok:

# Terminal 1: Start bot
node bot.js

# Terminal 2: Expose with ngrok
ngrok http 3000

Copy the HTTPS URL (e.g., https://abc123.ngrok.io) and update your Slack app's Event Subscriptions and Interactivity request URLs.

2. Event Delivery Verification:

Test each event type in your development workspace:

  • App Mention: Post @ChatGPT Bot hello in a channel
  • Direct Message: Send a DM to the bot
  • Slash Command: Run /chatgpt-ask what is 2+2
  • Interactive Component: Click the "Follow-up Question" button

Check your bot's logs for incoming events. Slack's Event Subscriptions page shows delivery attempts and error responses.

3. Rate Limit Testing:

Slack enforces rate limits (1 message/second per channel for Tier 1 apps). Test with rapid-fire messages:

for i in {1..10}; do
  curl -X POST https://your-domain.com/slack/events \
    -H "Content-Type: application/json" \
    -d '{"type":"app_mention","event":{"text":"test","user":"U123"}}'
done

Implement exponential backoff for rate limit errors (HTTP 429):

async function postMessageWithRetry(client, params, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await client.chat.postMessage(params);
    } catch (error) {
      if (error.data?.error === 'rate_limited') {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
}

4. Multi-Workspace Testing:

Install your bot in 2-3 test workspaces to validate OAuth token storage and workspace isolation.

Deployment and Distribution

Production Deployment:

Deploy your bot to a production server with:

  • HTTPS: Required for Slack event delivery (use Let's Encrypt for free SSL)
  • Process Manager: PM2 or systemd for automatic restarts
  • Load Balancer: Distribute traffic across multiple instances (Nginx, AWS ALB)
  • Database: PostgreSQL, MongoDB, or Firestore for OAuth token storage
  • Monitoring: Datadog, New Relic, or Sentry for error tracking

Example PM2 deployment:

npm install -g pm2
pm2 start bot.js --name slack-chatgpt-bot
pm2 save
pm2 startup

Slack App Directory Submission:

To distribute publicly, submit to Slack App Directory:

  1. App Listing: Add description, screenshots, category
  2. Permissions Review: Justify each OAuth scope
  3. Security Review: Pass Slack's security audit (HTTPS, token encryption, input validation)
  4. Test Workspace: Provide test credentials for Slack reviewers
  5. Support: Add support email and documentation URL

Approval takes 1-2 weeks. Once approved, your bot appears in the Slack App Directory for any workspace to install.

Enterprise Deployment:

For enterprise customers, support:

  • SAML SSO: Integrate with identity providers (Okta, Azure AD)
  • Custom OAuth: Use customer-specific redirect URIs
  • Data Residency: Deploy in customer's AWS/GCP region
  • Audit Logs: Track all bot actions for compliance

Troubleshooting

Event Delivery Failures:

Symptom: Events not reaching your bot, "endpoint failed" errors in Slack console.

Causes:

  • Request URL returns non-200 status
  • Response takes longer than 3 seconds
  • Invalid SSL certificate

Fixes:

  • Verify endpoint returns 200 OK within 3 seconds
  • Use ngrok or valid SSL certificate (not self-signed)
  • Check logs for errors during event processing
  • Validate Slack signature in middleware:
const { createEventAdapter } = require('@slack/events-api');
const slackEvents = createEventAdapter(process.env.SLACK_SIGNING_SECRET);

slackEvents.on('app_mention', async (event) => {
  // Handle event (signature already verified)
});

OAuth Token Expiration:

Symptom: invalid_auth errors after initial installation.

Causes:

  • User revoked app permissions
  • Token rotation enabled but not implemented

Fixes:

  • Implement token refresh using Slack's OAuth token rotation
  • Store refresh_token and exchange when access_token expires
  • Handle token_revoked webhook to remove installations

Rate Limiting Errors:

Symptom: rate_limited errors (HTTP 429).

Causes:

  • Posting messages faster than 1/second per channel
  • Exceeding Tier 1 rate limits (10,000 API calls/hour)

Fixes:

  • Implement message queue with rate limiting (Bull, AWS SQS)
  • Use exponential backoff for retries (see code example above)
  • Upgrade to Slack's higher tier for increased limits

Timeout Handling (3-Second Limit):

Symptom: "Operation timed out" errors from Slack.

Causes:

  • ChatGPT MCP server takes longer than 3 seconds to respond
  • Synchronous processing blocks event acknowledgment

Fixes:

  • Always acknowledge events immediately with await ack()
  • Process ChatGPT requests asynchronously
  • Post response after acknowledgment (not before)
app.command('/chatgpt-ask', async ({ command, ack, respond }) => {
  await ack(); // Acknowledge IMMEDIATELY (< 3 seconds)

  // Process asynchronously (can take 30+ seconds)
  const response = await callChatGPTMCP({ prompt: command.text });
  await respond({ text: response });
});

For additional support, review Slack's debugging guide or consult the Bolt SDK documentation.

Conclusion

You've built a production-ready Slack ChatGPT bot with OAuth authentication, event-driven messaging, slash commands, and interactive components. Your engineering team can now access AI-powered assistance without leaving Slack, reducing context switching by 50% and accelerating decision-making by 30%.

Key Takeaways:

  • Event-Driven Architecture: Slack's real-time messaging enables instant bot responses via WebSocket connections
  • OAuth 2.0 Multi-Workspace: Distribute your bot across unlimited workspaces with secure token storage
  • Interactive Components: Buttons, modals, and message actions create rich conversational experiences
  • Slash Commands: Provide explicit bot interactions for Q&A, summaries, and translations
  • Production-Ready: Rate limiting, error handling, and timeout management ensure reliability at scale

Next Steps:

  1. Deploy to Production: Use PM2, Docker, or Kubernetes for high-availability deployment
  2. Add Analytics: Track usage with Firebase Analytics or Mixpanel
  3. Expand Commands: Add /chatgpt-search, /chatgpt-image, /chatgpt-code-review
  4. Channel Customization: Load channel-specific knowledge bases for contextualized responses
  5. Submit to App Directory: Distribute publicly for maximum reach

Ready to build your Slack ChatGPT bot without writing code? MakeAIHQ's AI Conversational Editor generates production-ready MCP servers in minutes. Try the Instant App Wizard to deploy your first ChatGPT-powered Slack bot in 5 steps.

Related Resources:

Questions? Contact our team at hello@makeaihq.com or join our community Slack workspace.


About MakeAIHQ: We're building the Shopify of ChatGPT Apps - the easiest way for businesses to reach 800 million ChatGPT users. From zero to ChatGPT App Store in 48 hours, no coding required.