LoopFour
IntegrationsCommunication

Slack

Team communication for messages, channels, and interactive workflows

Slack

Connect to Slack for team messaging, channel management, and interactive workflows.

Overview

Slack is a team collaboration platform. The integration supports:

  • Messages - Send, update, delete, and schedule messages
  • Channels - Create, manage, and list channels
  • Users - Look up and manage users
  • Files - Upload and manage files
  • Reactions - Add and remove emoji reactions
  • Modals - Open interactive modal views
  • Home Tab - Publish app home views

Prerequisites

  • Slack workspace
  • Slack app with required scopes
  • Bot token or OAuth credentials

Authentication

Slack uses OAuth 2.0 for authentication via Nango.

curl "http://localhost:3000/api/v1/connections/slack/auth-url" \
  -H "x-api-key: YOUR_API_KEY"

Required Scopes

ScopeDescription
chat:writeSend messages
channels:readList channels
channels:manageCreate/archive channels
users:readRead user info
files:writeUpload files
reactions:writeAdd reactions

Available Actions

Message Actions

sendMessage

Send a message to a channel or DM.

{
  "id": "notify-team",
  "type": "action",
  "action": "slack.sendMessage",
  "config": {
    "channel": "#finance",
    "text": "New invoice paid: {{input.amount}}",
    "blocks": [
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "*Invoice Paid*\nCustomer: {{input.customerName}}\nAmount: ${{input.amount}}"
        }
      },
      {
        "type": "actions",
        "elements": [
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "View Invoice" },
            "url": "{{input.invoiceUrl}}"
          }
        ]
      }
    ],
    "unfurlLinks": false
  }
}

Parameters:

FieldTypeRequiredDescription
channelstringYesChannel ID or name (#channel)
textstringConditionalMessage text (required if no blocks)
blocksarrayNoBlock Kit blocks
threadTsstringNoThread timestamp for replies
replyBroadcastbooleanNoAlso post to channel
unfurlLinksbooleanNoUnfurl URLs (default: true)
unfurlMediabooleanNoUnfurl media (default: true)
mrkdwnbooleanNoParse as mrkdwn (default: true)
attachmentsarrayNoLegacy attachments
metadataobjectNoMessage metadata

sendEphemeral

Send a message visible only to one user.

{
  "action": "slack.sendEphemeral",
  "config": {
    "channel": "{{input.channelId}}",
    "user": "{{input.userId}}",
    "text": "Your request has been submitted",
    "blocks": [
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "Request #{{input.requestId}} submitted successfully"
        }
      }
    ]
  }
}

scheduleMessage

Schedule a message for later.

{
  "action": "slack.scheduleMessage",
  "config": {
    "channel": "#announcements",
    "text": "Weekly team update",
    "postAt": "{{input.scheduledTime}}",
    "blocks": [...]
  }
}

Note: postAt can be a Unix timestamp or ISO date string.

updateMessage

Update an existing message.

{
  "action": "slack.updateMessage",
  "config": {
    "channel": "{{steps.send.output.channel}}",
    "ts": "{{steps.send.output.ts}}",
    "text": "Updated: {{input.newContent}}",
    "blocks": [...]
  }
}

deleteMessage

Delete a message.

{
  "action": "slack.deleteMessage",
  "config": {
    "channel": "{{input.channelId}}",
    "ts": "{{input.messageTs}}"
  }
}

Get a permanent link to a message.

{
  "action": "slack.getPermalink",
  "config": {
    "channel": "{{input.channelId}}",
    "messageTs": "{{input.ts}}"
  }
}

Reaction Actions

addReaction

Add an emoji reaction to a message.

{
  "action": "slack.addReaction",
  "config": {
    "channel": "{{input.channelId}}",
    "timestamp": "{{input.messageTs}}",
    "name": "white_check_mark"
  }
}

Note: Emoji name without colons (e.g., thumbsup not :thumbsup:).

removeReaction

Remove an emoji reaction.

{
  "action": "slack.removeReaction",
  "config": {
    "channel": "{{input.channelId}}",
    "timestamp": "{{input.messageTs}}",
    "name": "thumbsup"
  }
}

File Actions

uploadFile

Upload a file to Slack.

{
  "action": "slack.uploadFile",
  "config": {
    "channels": ["#finance", "#leadership"],
    "content": "{{steps.report.output.csvContent}}",
    "filename": "monthly-report.csv",
    "filetype": "csv",
    "title": "Monthly Financial Report",
    "initialComment": "Here's the latest report"
  }
}

Parameters:

FieldTypeRequiredDescription
channelsstring/arrayNoChannels to share to
contentstringConditionalText content
filestringConditionalBase64 encoded file
filenamestringNoFile name
filetypestringNoFile type (csv, pdf, etc.)
titlestringNoFile title
initialCommentstringNoComment with file
threadTsstringNoThread timestamp

getFile

Get file information.

{
  "action": "slack.getFile",
  "config": {
    "fileId": "{{input.fileId}}"
  }
}

deleteFile

Delete a file.

{
  "action": "slack.deleteFile",
  "config": {
    "fileId": "{{input.fileId}}"
  }
}

openModal

Open a modal view (requires trigger_id from interaction).

{
  "action": "slack.openModal",
  "config": {
    "triggerId": "{{input.trigger_id}}",
    "view": {
      "type": "modal",
      "callback_id": "approval-modal",
      "title": { "type": "plain_text", "text": "Approve Request" },
      "submit": { "type": "plain_text", "text": "Approve" },
      "close": { "type": "plain_text", "text": "Cancel" },
      "blocks": [
        {
          "type": "input",
          "block_id": "comment",
          "element": {
            "type": "plain_text_input",
            "action_id": "comment_input",
            "multiline": true
          },
          "label": { "type": "plain_text", "text": "Comment" }
        }
      ]
    }
  }
}

updateModal

Update an existing modal.

{
  "action": "slack.updateModal",
  "config": {
    "viewId": "{{input.view.id}}",
    "view": {
      "type": "modal",
      "callback_id": "updated-modal",
      "title": { "type": "plain_text", "text": "Updated" },
      "blocks": [...]
    }
  }
}

pushModal

Push a new view onto the modal stack.

{
  "action": "slack.pushModal",
  "config": {
    "triggerId": "{{input.trigger_id}}",
    "view": {...}
  }
}

publishHomeTab

Publish a view to the app Home tab.

{
  "action": "slack.publishHomeTab",
  "config": {
    "userId": "{{input.userId}}",
    "view": {
      "type": "home",
      "blocks": [
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "Welcome to Workflows! You have *{{input.pendingCount}}* pending approvals."
          }
        },
        {
          "type": "actions",
          "elements": [
            {
              "type": "button",
              "text": { "type": "plain_text", "text": "View Approvals" },
              "action_id": "view_approvals"
            }
          ]
        }
      ]
    }
  }
}

User Actions

getUser

Get user information.

{
  "action": "slack.getUser",
  "config": {
    "userId": "U12345678",
    "includeLocale": true
  }
}

listUsers

List workspace users.

{
  "action": "slack.listUsers",
  "config": {
    "limit": 200,
    "cursor": "{{steps.previous.output.response_metadata.next_cursor}}",
    "includeLocale": true
  }
}

lookupUserByEmail

Find a user by email address.

{
  "action": "slack.lookupUserByEmail",
  "config": {
    "email": "{{input.email}}"
  }
}

Channel Actions

getChannel

Get channel information.

{
  "action": "slack.getChannel",
  "config": {
    "channelId": "C12345678",
    "includeNumMembers": true
  }
}

listChannels

List workspace channels.

{
  "action": "slack.listChannels",
  "config": {
    "types": "public_channel,private_channel",
    "excludeArchived": true,
    "limit": 200
  }
}

createChannel

Create a new channel.

{
  "action": "slack.createChannel",
  "config": {
    "name": "project-{{input.projectName | slugify}}",
    "isPrivate": false
  }
}

inviteToChannel

Invite users to a channel.

{
  "action": "slack.inviteToChannel",
  "config": {
    "channelId": "{{steps.create-channel.output.channel.id}}",
    "users": ["U12345678", "U87654321"]
  }
}

archiveChannel

Archive a channel.

{
  "action": "slack.archiveChannel",
  "config": {
    "channelId": "{{input.channelId}}"
  }
}

setChannelTopic

Set the channel topic.

{
  "action": "slack.setChannelTopic",
  "config": {
    "channelId": "{{input.channelId}}",
    "topic": "Q1 Planning - Updated {{now | date: 'MMM D'}}"
  }
}

getChannelHistory

Get channel message history.

{
  "action": "slack.getChannelHistory",
  "config": {
    "channelId": "{{input.channelId}}",
    "limit": 100,
    "oldest": "{{input.startTimestamp}}",
    "latest": "{{input.endTimestamp}}"
  }
}

Bookmark Actions

addBookmark

Add a bookmark to a channel.

{
  "action": "slack.addBookmark",
  "config": {
    "channelId": "{{input.channelId}}",
    "title": "Project Dashboard",
    "type": "link",
    "link": "{{input.dashboardUrl}}"
  }
}

Slack Triggers

Slack events can trigger workflows via the Events API.

Event Trigger

{
  "trigger": {
    "type": "slack_event",
    "eventType": "message",
    "keywords": ["invoice", "payment"]
  }
}

Event Types:

EventDescription
messageMessage in channel/DM
app_mentionBot @mentioned
reaction_addedEmoji reaction added
channel_createdNew channel created
member_joined_channelUser joined channel
file_sharedFile uploaded

Slash Command Trigger

{
  "trigger": {
    "type": "slack_slash_command",
    "command": "/invoice"
  }
}

Interactive Trigger

{
  "trigger": {
    "type": "slack_interactive",
    "interactionType": "block_actions",
    "actionId": "approve_button"
  }
}

Block Kit

Slack uses Block Kit for rich message layouts.

Common Block Types

{
  "blocks": [
    {
      "type": "header",
      "text": { "type": "plain_text", "text": "Invoice Notification" }
    },
    {
      "type": "section",
      "text": { "type": "mrkdwn", "text": "*Amount:* ${{input.amount}}" },
      "accessory": {
        "type": "button",
        "text": { "type": "plain_text", "text": "View" },
        "url": "{{input.invoiceUrl}}"
      }
    },
    {
      "type": "divider"
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": { "type": "plain_text", "text": "Approve" },
          "style": "primary",
          "action_id": "approve",
          "value": "{{input.invoiceId}}"
        },
        {
          "type": "button",
          "text": { "type": "plain_text", "text": "Reject" },
          "style": "danger",
          "action_id": "reject",
          "value": "{{input.invoiceId}}"
        }
      ]
    },
    {
      "type": "context",
      "elements": [
        { "type": "mrkdwn", "text": "Submitted by <@{{input.userId}}>" }
      ]
    }
  ]
}

Example Workflow

Approval workflow with Slack interaction:

{
  "name": "Expense Approval",
  "trigger": {
    "type": "api"
  },
  "steps": [
    {
      "id": "send-approval",
      "type": "action",
      "action": "slack.sendMessage",
      "config": {
        "channel": "#approvals",
        "text": "New expense request from {{input.requester}}",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "*Expense Request*\n*Amount:* ${{input.amount}}\n*Category:* {{input.category}}\n*Description:* {{input.description}}"
            }
          },
          {
            "type": "actions",
            "block_id": "approval_actions",
            "elements": [
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Approve" },
                "style": "primary",
                "action_id": "approve_expense",
                "value": "{{input.expenseId}}"
              },
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Reject" },
                "style": "danger",
                "action_id": "reject_expense",
                "value": "{{input.expenseId}}"
              }
            ]
          }
        ]
      }
    },
    {
      "id": "add-reaction",
      "type": "action",
      "action": "slack.addReaction",
      "config": {
        "channel": "{{steps.send-approval.output.channel}}",
        "timestamp": "{{steps.send-approval.output.ts}}",
        "name": "hourglass"
      }
    }
  ]
}

Rate Limits

LimitValue
Web API (Tier 1)1 req/sec
Web API (Tier 2)20 req/min
Web API (Tier 3)50 req/min
Web API (Tier 4)100 req/min
Incoming webhooks1 req/sec

Troubleshooting

Common Errors

ErrorCauseSolution
channel_not_foundInvalid channel IDVerify channel exists and bot has access
not_in_channelBot not in channelInvite bot to channel
invalid_blocksMalformed Block KitValidate with Block Kit Builder
message_not_foundInvalid message tsVerify timestamp is correct
ratelimitedToo many requestsImplement backoff, check Retry-After