Slack

How To Create a Slack Bot - Complete Build Tutorial

William Westerlund
October 23, 2025
Read time

Follow a complete create Slack bot build tutorial from app setup to deployment. Learn OAuth scopes, events, slash commands, modals, file uploads, and production hosting.

📡
⌨️
🪟
📎

Slack App Foundations

A Slack app is the container for your bot, commands, and UI. It listens with the Events API and acts with the Web API. Use messages, modals, App Home, and interactive components to create complete workflows. For context on Slack features, see our guides on what Slack is, Slack AI, and omnichannel support.

Workflow Builder

No Code
  • Fast automation
  • Built in triggers
  • Limited logic

Marketplace Apps

Freemium
  • Thousands of choices
  • Two way sync
  • Vendor limits

Custom App

Project Based
  • Full control
  • Private data
  • Dev effort
📊
Tip: Start with no code for quick wins. Move to a custom app when you need complex logic, security controls, or deep integrations with tools covered in our ticketing systems and workflow automation articles.

How To Create a Slack Bot Checklist

Plan scopes and features. Create the app in a dev workspace.

  • Store secrets in environment variables.
  • Add minimal bot token scopes.
  • Install the app to get the xoxb token.
  • Wire Events API and Interactivity to a public HTTPS URL.
  • Implement app_mention and one helpful command.
  • Add a modal for structured input.
  • Upload a sample file.
  • Deploy to Heroku or Lambda.
  • Update URLs in the Slack dashboard and reinstall if scopes changed.

Create the App and Get Credentials

Register your app, then secure your tokens. You need the Client ID, Client Secret, and Signing Secret for OAuth and request verification.

1

Create the App

Go to the Slack API dashboard. Create a new app from scratch in a dev workspace. Name it clearly, for example support-bot.

2

Collect Credentials

Copy Client ID, Client Secret, and Signing Secret. Store them in environment variables, not in code.

3

Add Scopes

Under OAuth and Permissions, add bot token scopes like chat:write, app_mentions:read, and commands. Keep scopes minimal.

4

Install to Workspace

Click Install App to get your xoxb- bot token. Reinstall when you change scopes.

🔐
Security: Use environment variables. Do not commit .env to Git. Consider token rotation later for production.

Initialize a Bolt Project

Use Bolt to handle signatures, OAuth, and event plumbing. Choose Node or Python.

🟨

Node.js Starter

Install dependencies and post a message.

npm init -y


npm install @slack/bolt dotenv

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

const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});

app.event('app_mention', async ({ event, say }) => {
await say(Hi <@${event.user}>);
});

(async () => {
await app.start(process.env.PORT || 3000);
console.log('⚡️ Bolt app running');
})();
🐍

Python Starter

Create a virtual env and reply to a mention.

python3 -m venv venv


source venv/bin/activate
pip install slack-bolt python-dotenv

app.py

import os
from dotenv import load_dotenv
from slack_bolt import App

load_dotenv()
app = App(token=os.environ["SLACK_BOT_TOKEN"],
signing_secret=os.environ["SLACK_SIGNING_SECRET"])

@app.event("app_mention")
def handle_mention(event, say):
say(f"Hi <@{event['user']}>")

if name == "main":
app.start(port=int(os.environ.get("PORT", 3000)))
📡
Local testing: Use a tunnel like ngrok to expose /slack/events. Paste the public URL in Event Subscriptions and Interactivity.

Listen to Events and Add Slash Commands

Subscribe to app_mention and define a command like /echo.

Feature
What It Does
Sample
Events API
Pushes JSON payloads to your endpoint when subscribed events occur
app.event('app_mention', handler)
Slash Command
Lets users invoke your app from any composer
/echo hello world
// Node: simple /echo app.command('/echo', async ({ command, ack, say }) => { await ack(); await say(`You said: ${command.text}`); });
# Python: simple /echo @app.command("/echo") def echo(ack, say, command): ack() say(f"You said: {command['text']}")
⏱️
Ack in time: Acknowledge within 3 seconds or Slack shows an error to the user. Use the provided response_url for delayed replies.

Create Interactive Messages and Modals

Use Block Kit for buttons and menus. Open modals for structured input.

// Node: open a modal from a command app.command('/survey', async ({ ack, body, client }) => { await ack(); await client.views.open({ trigger_id: body.trigger_id, view: { type: 'modal', callback_id: 'survey_view', title: { type: 'plain_text', text: 'Feedback Survey' }, submit: { type: 'plain_text', text: 'Submit' }, blocks: [ { type: 'input', block_id: 'feedback_block', label: { type: 'plain_text', text: 'Your feedback' }, element: { type: 'plain_text_input', action_id: 'feedback_input', multiline: true } } ] } }); }); app.view('survey_view', async ({ ack, body }) => { await ack(); const user = body.user.id; const feedback = body.view.state.values.feedback_block.feedback_input.value; console.log(`Feedback from ${user}: ${feedback}`); });
🪟
Rule: Use the trigger_id within 3 seconds to open a modal. Miss the window and the call fails.

Upload and Share Files

Use the modern upload flow or SDK helpers. Request files:write.

# Python SDK helper: files_upload_v2 from slack_sdk import WebClient client = WebClient(token=os.environ["SLACK_BOT_TOKEN"]) client.files_upload_v2( channel="C12345678", file="report.txt", title="Weekly Report", initial_comment="Here is the report" )

Deploy to Production

Choose Heroku for simplicity, AWS Lambda for serverless, or a VPS for full control. Always serve HTTPS.

🚀

Heroku

Add a Procfile and env vars. Push to the Heroku remote.

# Procfile (Node) web: node app.js # Procfile (Python) web: gunicorn app:app
🧩

AWS Lambda

Use AwsLambdaReceiver and API Gateway. Deploy with Serverless.

const { App, AwsLambdaReceiver } = require('@slack/bolt'); const receiver = new AwsLambdaReceiver({ signingSecret: process.env.SLACK_SIGNING_SECRET }); const app = new App({ token: process.env.SLACK_BOT_TOKEN, receiver }); module.exports.handler = async (event, context, callback) => { const handler = await receiver.start(); return handler(event, context, callback); };
🛡️

VPS

Run Gunicorn behind Nginx with TLS from Let’s Encrypt.

server { listen 443 ssl; server_name your_domain.com; location / { include proxy_params; proxy_pass http://unix:/home/your_user/mybot.sock; } }
🧭
After deploy: Update Event Subscriptions and Interactivity to your public HTTPS URL. Reinstall the app if scopes changed.

Troubleshooting Slack Bot Errors

If Slack shows a timeout, call ack sooner and send results later. If events do not arrive, verify the public URL and the signing secret. If messages fail, confirm chat.write scope and that the bot is in the channel. If modals fail to open, use the trigger_id within three seconds.

If uploads fail, enable files.write and try the SDK helper. Use logs and retry logic to handle transient errors.

Security and UX Best Practices

Protect tokens and design messages that help users act in place.

Security

  • Use env vars for secrets
  • Verify signatures on every request
  • Request least privilege scopes
  • Avoid broad legacy scopes

Reliability

  • Ack fast then process
  • Use retries and idempotency
  • Log and alert failures

UX

  • Keep it brief
  • Use buttons not links out
  • Use App Home for settings
🔗
Build end to end service workflows with resources like customer support tools, knowledge base software, and cloud collaboration.

Ship a Slack Native Ticketing Experience

Use Suptask to turn messages into tickets, assign owners, and resolve requests inside Slack. No context switching.

Used by growing teams • 14 day free trial • No credit card required

William Westerlund

Get started with Suptask

14 Days Free Trial
No Credit Card Required
Get Started Easily
A Add to Slack
Try a Slack Ticketing System Today
No credit card required