All topics
General · Learning hub

Slack notes for developers

Master Slack with a curated set of 3 developer notes — core concepts, patterns, and interview prep. Maintained by the DevRecall team.

Save this stack to your DevRecallMore General notes
Slack

Slack API & Webhooks

Slack API & Webhooks Slack provides several integration points: Incoming Webhooks (push messages), Slash Commands, Events API (receive events), Web API (full pr

Slack API & Webhooks

Slack provides several integration points: Incoming Webhooks (push messages), Slash Commands, Events API (receive events), Web API (full programmatic control), and Socket Mode (no public URL needed).

Incoming Webhooks

The simplest way to post messages to Slack. Create a Slack App, enable Incoming Webhooks, and get a URL to POST to.

# Post a simple message
curl -X POST https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX \
  -H 'Content-type: application/json' \
  --data '{"text": "Hello from my app!"}'
// Node.js example
async function notifySlack(message: string) {
  await fetch(process.env.SLACK_WEBHOOK_URL!, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: message,
      // Use blocks for rich formatting
      blocks: [
        {
          type: 'section',
          text: { type: 'mrkdwn', text: `*Alert:* ${message}` }
        }
      ]
    })
  })
}

Block Kit — Rich Messages

Block Kit is Slack's UI framework for building rich, interactive messages. Blocks replace plain text for anything beyond simple notifications.

{
  "blocks": [
    {
      "type": "header",
      "text": { "type": "plain_text", "text": "Deployment Complete" }
    },
    {
      "type": "section",
      "fields": [
        { "type": "mrkdwn", "text": "*Environment:*\nProduction" },
        { "type": "mrkdwn", "text": "*Status:*\n:white_check_mark: Success" }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": { "type": "plain_text", "text": "View Logs" },
          "url": "https://app.example.com/logs",
          "style": "primary"
        }
      ]
    }
  ]
}

Web API

import { WebClient } from '@slack/web-api'

const slack = new WebClient(process.env.SLACK_BOT_TOKEN)

// Post a message
await slack.chat.postMessage({
  channel: '#deployments',
  text: 'Build passed!',
  blocks: [...],
})

// Update an existing message
await slack.chat.update({
  channel: 'C1234567890',
  ts: '1234567890.123456',  // message timestamp = unique ID
  text: 'Updated message',
})

// Upload a file
await slack.filesUploadV2({
  channel_id: 'C1234567890',
  filename: 'report.csv',
  content: csvData,
})

// Get channel list
const { channels } = await slack.conversations.list({ types: 'public_channel' })

// Lookup user by email
const { user } = await slack.users.lookupByEmail({ email: 'user@example.com' })

Slash Commands

// Express handler for /deploy slash command
// Slack sends a POST with application/x-www-form-urlencoded
app.post('/slack/commands/deploy', express.urlencoded({ extended: true }), async (req, res) => {
  const { text, user_id, response_url } = req.body

  // Respond immediately (Slack times out at 3s)
  res.json({ text: 'Deploying...' })

  // Do async work, then use response_url to post follow-up
  await deploy(text)
  await fetch(response_url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ text: `Deploy of ${text} complete!` })
  })
})
Slack

Building Slack Bots & Apps

Building Slack Bots & Apps Bolt Framework (Official SDK) Bolt is Slack's official SDK for building apps in Node.js, Python, and Java. It handles OAuth, event ro

Building Slack Bots & Apps

Bolt Framework (Official SDK)

Bolt is Slack's official SDK for building apps in Node.js, Python, and Java. It handles OAuth, event routing, and middleware automatically.

import { App } from '@slack/bolt'

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  // Socket Mode (no public URL needed — great for development)
  socketMode: true,
  appToken: process.env.SLACK_APP_TOKEN,
})

// Listen to messages mentioning the bot
app.message('hello', async ({ message, say }) => {
  await say(`Hey <@${message.user}>!`)
})

// Handle a slash command
app.command('/todo', async ({ command, ack, respond }) => {
  await ack()  // must acknowledge within 3s
  await respond(`Added: ${command.text}`)
})

// Handle button click
app.action('approve_button', async ({ body, ack, client }) => {
  await ack()
  await client.chat.update({
    channel: body.channel!.id,
    ts: body.message!.ts,
    text: 'Request approved!',
  })
})

await app.start(3000)

Events API

Subscribe to Slack events (messages, reactions, user changes) via HTTP endpoint or Socket Mode. Configure subscriptions in your app's Event Subscriptions settings.

// Common event subscriptions
app.event('app_mention', async ({ event, client }) => {
  // Bot was @mentioned
  await client.chat.postMessage({
    channel: event.channel,
    thread_ts: event.ts,  // reply in thread
    text: `You mentioned me: ${event.text}`,
  })
})

app.event('reaction_added', async ({ event }) => {
  console.log(`${event.user} reacted with :${event.reaction}: on message ${event.item.ts}`)
})

app.event('message', async ({ event }) => {
  // Filter: only DMs
  if (event.channel_type === 'im') {
    console.log('DM received:', event.text)
  }
})

Modals & Shortcuts

// Open a modal from a shortcut
app.shortcut('create_ticket', async ({ shortcut, ack, client }) => {
  await ack()
  await client.views.open({
    trigger_id: shortcut.trigger_id,
    view: {
      type: 'modal',
      callback_id: 'ticket_modal',
      title: { type: 'plain_text', text: 'Create Ticket' },
      submit: { type: 'plain_text', text: 'Create' },
      blocks: [
        {
          type: 'input',
          block_id: 'title',
          label: { type: 'plain_text', text: 'Title' },
          element: { type: 'plain_text_input', action_id: 'title_input' }
        },
        {
          type: 'input',
          block_id: 'priority',
          label: { type: 'plain_text', text: 'Priority' },
          element: {
            type: 'static_select',
            action_id: 'priority_select',
            options: [
              { text: { type: 'plain_text', text: 'High' }, value: 'high' },
              { text: { type: 'plain_text', text: 'Low' }, value: 'low' },
            ]
          }
        }
      ]
    }
  })
})

// Handle modal submission
app.view('ticket_modal', async ({ view, ack, client, body }) => {
  await ack()
  const title = view.state.values.title.title_input.value
  const priority = view.state.values.priority.priority_select.selected_option?.value
  // Create ticket...
})

OAuth & App Distribution

// Bolt handles OAuth automatically with installationStore
const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: 'my-state-secret',
  scopes: ['channels:read', 'chat:write', 'commands'],
  installationStore: {
    storeInstallation: async (installation) => {
      // Save installation to DB
      await db.saveInstallation(installation)
    },
    fetchInstallation: async (installQuery) => {
      return await db.getInstallation(installQuery.teamId)
    },
  },
})
Slack

Workflow Automation & Best Practices

Slack Workflow Automation & Best Practices Workflow Builder (No-Code) Workflow Builder: Automations → Workflow Builder — create workflows without code Triggers:

Slack Workflow Automation & Best Practices

Workflow Builder (No-Code)

  • Workflow Builder: Automations → Workflow Builder — create workflows without code

  • Triggers: message shortcut, emoji reaction, scheduled time, webhook

  • Steps: send message, create channel, update topic, call webhook, custom step

  • Custom steps: published as part of your Slack app — appear in Workflow Builder for all users

  • Variables: pass data between steps (user name, message text, channel)

Useful Notification Patterns

// Alert with severity color (attachments for color sidebar)
await slack.chat.postMessage({
  channel: '#alerts',
  attachments: [{
    color: severity === 'critical' ? '#FF0000' : '#FFA500',
    blocks: [
      {
        type: 'section',
        text: { type: 'mrkdwn', text: `*[${severity.toUpperCase()}]* ${message}` }
      }
    ]
  }]
})

// Threaded updates — keep channel clean
const { ts } = await slack.chat.postMessage({ channel, text: 'Starting deploy...' })
// ... later ...
await slack.chat.postMessage({ channel, thread_ts: ts, text: 'Step 1 complete' })
await slack.chat.postMessage({ channel, thread_ts: ts, text: 'Deploy finished!' })

// Ephemeral message — only visible to one user
await slack.chat.postEphemeral({
  channel,
  user: userId,
  text: 'Only you can see this error details',
})

Rate Limits & Error Handling

  • Tier 1 (1 req/min): conversations.create, etc.

  • Tier 2 (20 req/min): most Web API methods

  • Tier 3 (50 req/min): chat.postMessage, reactions.add

  • Tier 4 (100 req/min): high-frequency methods

  • Rate limit response: HTTP 429 with Retry-After header

  • @slack/web-api retries automatically with exponential backoff by default

  • Workspace limits: 1 message/second per channel — batch or queue notifications

Security

  • Verify request signatures: X-Slack-Signature header prevents spoofed requests — Bolt does this automatically

  • Never expose Bot Token client-side — always make Slack API calls from backend

  • Use short-lived trigger_ids (valid 3s) — open modals immediately after ack()

  • Store tokens encrypted — use Slack's token rotation for long-lived installations

  • Restrict app scopes to minimum required — don't request channels:history unless needed

Development Tips

# ngrok for local development (exposes localhost to Slack)
ngrok http 3000
# Use the https URL in Slack app settings → Event Subscriptions

# Socket Mode for development (no ngrok needed)
# Enable in Slack app settings → Socket Mode

# Slack CLI (official)
npm install -g @slack/cli
slack login
slack create my-app
slack run      # local development with hot reload
slack deploy   # deploy to Slack hosting

Keep your Slack knowledge sharp.

Save this stack to your personal DevRecall — add your own notes, track what you're learning, and share what you know with the community.

Get started — free forever