Portal Community

channel/join

Makes the bot join a public Slack channel so it can post messages, read history, and manage membership. This is a bot-self-action — use channel/invite to add other users. Works only on public channels; private channels require invitation. Requires channels:join scope.

When to Use

Configuration

Connection

FieldTypeRequiredDescription
botTokenstringRequiredBot Token starting with xoxb-. Requires channels:join scope. Only works on public channels.

Operation Fields

FieldTypeRequiredDescription
channelIdstringRequiredThe public channel ID to join (starts with C). The bot cannot join private channels — it must be invited.
Public Channels Only: channel/join only works for public channels. To add the bot to a private channel, a workspace admin must invite it manually, or use channel/invite from an admin bot token with appropriate scopes.

Sample Configuration

{
  "operation": "channel/join",
  "connection": {
    "botToken": "{{credentials.slackBotToken}}"
  },
  "fields": {
    "channelId": "{{$json.channelId}}"
  }
}

Validation Errors

Error CodeCauseResolution
channel_not_foundThe channel ID does not exist or is a private channel.Verify the channel ID. For private channels, the join operation is not available — the bot must be invited.
missing_scopeBot token lacks channels:join scope.Re-authorize the Slack app with the channels:join scope.
is_archivedThe channel is archived and cannot be joined.Unarchive the channel first with channel/unarchive, then join.

Output

Success Port

FieldTypeDescription
channelIdstringThe channel the bot has joined.
statusstringsuccess or error.
errorCodestringSlack error code when status is error.
payloadobjectFull raw Slack API response including channel details post-join.

Error Port

On failure with Continue on Error enabled, routes to the error port with status: "error" and populated errorCode.

Sample Output

{
  "channelId": "C08AB3XYZ12",
  "status": "success",
  "errorCode": "",
  "payload": {
    "ok": true,
    "channel": {
      "id": "C08AB3XYZ12",
      "name": "monitoring-alerts",
      "is_member": true
    },
    "already_in_channel": false
  }
}

Expression Reference

ExpressionResult
{{$node["channel-join"].json.channelId}}The channel ID joined — pass to subsequent message/send or channel/getHistory nodes.
{{$node["channel-join"].json.status === "success"}}Boolean gate — confirm join before proceeding with channel operations.
{{$node["channel-join"].json.payload.already_in_channel}}True if the bot was already a member — use to skip redundant join notifications.

Node Policies & GuardRails

Policy AreaRecommendation
Scope requirementsRequires channels:join scope. This only works for public channels — private channel access requires an invitation.
Rate limitingTier 2 (20+ req/min). For workflows that join many channels, add delays between join calls to avoid rate limiting.
No hard-coded IDsAlways source channelId dynamically from upstream node output. Never hard-code channel IDs.
Idempotent joinsJoining a channel the bot is already in returns success with already_in_channel: true. This is safe to call repeatedly — use it as a guard before posting.
Archive before joinCheck isArchived using channel/get before joining. You cannot join an archived channel — unarchive first.
Channel proliferationAvoid joining every channel automatically. The bot should only join channels where it has a specific purpose to avoid cluttering member lists.

Examples

Example 1 — Ensure Bot Membership Before Alerting

A monitoring pipeline that joins the alert channel before posting — safe to call even if already a member.

// Node 1: channel/join (idempotent guard)
{ "channelId": "C08MONITORING" }

// Node 2: message/send (now guaranteed to succeed)
{
  "channelId": "C08MONITORING",
  "text": "ALERT: CPU usage at {{$json.cpuPercent}}% on {{$json.host}}"
}

Example 2 — Join All New Project Channels

Triggered by a project creation event — the project tool creates the Slack channel, then this workflow ensures the bot joins it.

// Trigger: webhook from project management tool
// $json.slackChannelId = newly created channel

// Check if archived first
{ "operation": "channel/get", "fields": { "channelId": "{{$json.slackChannelId}}" } }

// IF: isArchived === false
// True → channel/join
{ "operation": "channel/join", "fields": { "channelId": "{{$json.slackChannelId}}" } }

Example 3 — Bot Recovery After Removal

Health-check workflow that verifies the bot is a member of all required channels and rejoins any it was removed from.

// Required channels list from config
const requiredChannels = ["C08ALERTS01", "C08DEPLOYS01", "C08ANNOUNCE01"];

// channel/getMany to get current bot channels
// Code node: find channels bot is NOT in
const missing = requiredChannels.filter(
  id => !$node["bot-channels"].json.channels.some(c => c.channelId === id)
);
// Loop: channel/join for each missing channel