Channels

Slack free

Slack connects as an app installed into a workspace. There are three ways to do it, and they trade setup time for control: a one-click shared app, your own branded app, or a distributed app you push into your customers' workspaces. All three land on the same on_message handler.

Slack is free: no signup, no paid credit. An anonymous sandbox key is enough. See the Quickstart if you don't have a key yet.

Which option?

OptionSetupApp to createBest for
Quickone clicknone (uses Caspian's shared app)getting into your own workspace fast, still under your name and icon
Branded~5 minyour own Slack appowning the app name and the @mention in your workspace
Distribute~10 min onceyour own published appinstalling into many customer workspaces, one link each

In every case the agent replies only when it is @-mentioned in a channel, or in a direct message. It stays quiet on ordinary channel chatter.

a) Quick: the shared app

Call install_slack() with the name (and optional icon) your agent should post under. It installs Caspian's shared Slack app into a workspace, but every message goes out under your name and icon; the plumbing stays invisible. Nothing to build on api.slack.com.

agent.py
from caspian_sdk import CommClient

client = CommClient()

result = client.install_slack(
    display_name="Acme Support",
    icon_url="https://acme.com/bot.png",   # optional
)
print("Add to Slack:", result["authorize_url"])

@client.on_message
def handle(message):
    message.reply(f"You said: {message.text}")

client.listen()
agent.ts
import { CommClient } from "caspian-sdk";

const client = new CommClient();

const result = await client.installSlack({
  displayName: "Acme Support",
  iconUrl: "https://acme.com/bot.png",   // optional
});
console.log("Add to Slack:", result.authorize_url);

client.onMessage(async (message) => {
  await message.reply(`You said: ${message.text}`);
});

await client.listen();

Open the returned authorize_url ("Add to Slack"), pick your workspace, and authorize. The connection flips to active on its own once the install completes, and messages in that workspace start reaching your handler.

!

If install_slack() returns a 400, the shared app isn't configured on this gateway. Fall back to the branded option below with your own Slack app.

b) Branded: your own app in your workspace

Create a Slack app you own, then hand its credentials to connect_slack(). You control the app name and the @mention. This is a one-time ~5 minute setup at api.slack.com/apps.

Create the app

Go to api.slack.com/apps → Create New App → From scratch, then:

  1. OAuth & Permissions → Redirect URLs. Add the redirect URL and save:
    https://api.trycaspianai.com/v1/oauth/slack/callback
  2. OAuth & Permissions → Bot Token Scopes. Add:
    chat:write
    chat:write.customize
    channels:history
    im:history
    app_mentions:read
  3. Event Subscriptions. Toggle On and set the Request URL (it verifies instantly):
    https://api.trycaspianai.com/internal/providers/slack/webhooks
    Then under Subscribe to bot events add and save:
    message.channels
    message.im
    app_mention
  4. Basic Information → App Credentials. Copy the Client ID, Client Secret, and Signing Secret.

Connect it

agent.py
result = client.connect_slack(
    slack_client_id="1234567890.1234567890",
    slack_client_secret="xxxxxxxxxxxxxxxxxxxxxxxx",
    slack_signing_secret="xxxxxxxxxxxxxxxxxxxxxxxx",
)
print("Add to Slack:", result["authorize_url"])
agent.ts
const result = await client.connectSlack({
  slackClientId: "1234567890.1234567890",
  slackClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
  slackSigningSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
});
console.log("Add to Slack:", result.authorize_url);

Open the returned authorize_url, pick your workspace, and Allow. The connection goes active and inbound messages route to the same handler.

c) Distribute: install into your customers' workspaces

Same app as (b), but you also turn on public distribution so it can install into other workspaces, the same way Caspian ships its shared app. Then you call connect_slack() once per customer to get one "Add to Slack" link per workspace.

Do everything in (b), then add one step before copying credentials:

Now call connect_slack() with the same app credentials but a different customer_id per customer. Each call returns its own authorize_url:

agent.py
APP = dict(
    slack_client_id="1234567890.1234567890",
    slack_client_secret="xxxxxxxxxxxxxxxxxxxxxxxx",
    slack_signing_secret="xxxxxxxxxxxxxxxxxxxxxxxx",
)

for customer in ("acme-inc", "globex", "initech"):
    result = client.connect_slack(customer_id=customer, **APP)
    print(customer, "->", result["authorize_url"])
agent.ts
const APP = {
  slackClientId: "1234567890.1234567890",
  slackClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
  slackSigningSecret: "xxxxxxxxxxxxxxxxxxxxxxxx",
};

for (const customer of ["acme-inc", "globex", "initech"]) {
  const result = await client.connectSlack({ customerId: customer, ...APP });
  console.log(customer, "->", result.authorize_url);
}

Send each customer their own link; they pick their workspace and Allow. Every customer's workspace routes back to the same on_message handler, isolated by customer_id. Inbound from all of them shares the one Event Subscriptions URL; the gateway routes each message by app and team automatically.

Change the name or icon the agent posts under any time after connecting (no re-install) with update_branding(connection_id, display_name=..., icon_url=...) (Python) / updateBranding(connectionId, { displayName, iconUrl }) (JS). It takes effect on the next message.

How replies behave

Slack is noisy, so the agent is deliberately quiet. It fires on_message and replies only in two cases:

Everything else in a channel is ignored. Reply with message.reply() and it lands back in the same Slack thread; the channels:history and im:history scopes let the agent read surrounding context. See Behavior guides for Slack-specific etiquette to inject into your agent's prompt.

Next steps

Discord →
Shared bot or your own bot token.
Behavior guides →
Teach your agent each platform's etiquette.