← Blog

Claude API Slack Bot Setup Guide

2026-10-07 · 4 min read · SubToAPI Team

Building a Slack bot that talks to Claude means connecting three pieces: a Slack app that listens for messages, a small server that receives those events, and an API call to Claude that generates a reply. This guide walks through each piece in order, from creating the Slack app to deploying a working bot that responds in channels and DMs.

If you just want the fastest path, skip to the "API key" step — you can use either a direct Anthropic API key or an application key from a gateway like SubToAPI, which adds HTTPS streaming, usage metadata per request, and team seats if more than one person needs to manage the bot.

What you need before starting

Step 1: Create the Slack app

  1. Go to api.slack.com/apps and click Create New App, then From scratch.
  2. Name it and pick your workspace.
  3. Under OAuth & Permissions, add these bot token scopes:
  1. Install the app to your workspace. Copy the Bot User OAuth Token (xoxb-...) — your server will use this to post replies.

Step 2: Turn on Event Subscriptions

In Event Subscriptions, enable events and set the Request URL to your server's endpoint (e.g. https://yourserver.com/slack/events). Slack will send a verification challenge first — your server needs to echo it back before the URL is accepted.

Subscribe to:

Step 3: Get a Claude API key

You have two options here:

Direct Anthropic API key — works fine for a single bot with light usage, but you're on your own for rate limit handling, usage tracking per channel/team, and key rotation.

SubToAPI application key — a sub_live_... key that proxies to Claude with the same request/response shape, but adds streaming support, per-request usage metadata (so you can log token counts per Slack workspace or channel), and team seats if more than one developer maintains the bot. Get a key from /signup and check /pricing for plans (Solo €9, Team €19/seat, Scale €49/seat).

Either way, store the key as an environment variable — never hardcode it.

Step 4: Write the bot server

Here's a minimal Express server using Slack's Bolt framework and the Claude API:

const { App } = require("@slack/bolt");

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

app.event("app_mention", async ({ event, say }) => {
  const userText = event.text.replace(/<@[^>]+>/, "").trim();

  const response = await fetch("https://api.subtoapi.app/v1/messages", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    },
    body: JSON.stringify({
      model: "claude-sonnet-4-5",
      max_tokens: 1024,
      messages: [{ role: "user", content: userText }],
    }),
  });

  const data = await response.json();
  const reply = data.content[0].text;

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

(async () => {
  await app.start(process.env.PORT || 3000);
  console.log("Slack bot running");
})();

A few things to note:

Step 5: Add streaming for longer responses

If your bot often generates long answers, streaming avoids the Slack message appearing all at once after a long pause. SubToAPI supports streaming responses — see /docs/streaming for the event format. You can post an initial placeholder message, then edit it with chat.update as chunks arrive, giving users a visible "typing" effect instead of silence.

Step 6: Deploy and verify

  1. Deploy your server somewhere with a stable HTTPS URL (a serverless function works, but watch for cold starts delaying the first response).
  2. Set the Event Subscriptions URL in the Slack app config to your live endpoint.
  3. Mention the bot in a test channel and confirm it replies in-thread.
  4. Check your API provider's dashboard to confirm requests are landing — if you're using SubToAPI, usage and token counts per request show up immediately, which is useful for figuring out which channels are driving cost.

Tool use and context

If you want the bot to do more than chat — look up a ticket, query a database, post a formatted card — wire up Claude's tool use feature instead of parsing free text yourself. See /docs/tools for the request format, and /docs/messages for the full message schema including system prompts, which are useful for giving the bot a consistent persona across every channel it's in.

Questions

Do I need a paid Slack plan to run a Claude bot? No. Event Subscriptions, bot tokens, and the scopes used here all work on Slack's free tier. You only need a paid Slack plan for other unrelated features.

Can one bot serve multiple Slack workspaces? Yes, but you need to implement OAuth installation flow (Slack's "distribute app" setup) and store a separate bot token per workspace. For a single internal team, the single-workspace setup above is enough.

How do I keep conversation context across messages in a thread? Store recent messages keyed by thread_ts in a lightweight store (Redis, a database table, or even in-memory for low traffic) and include them in the messages array on each Claude API call — the API itself is stateless between requests.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →