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
| Scope | Description |
|---|---|
chat:write | Send messages |
channels:read | List channels |
channels:manage | Create/archive channels |
users:read | Read user info |
files:write | Upload files |
reactions:write | Add 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:
| Field | Type | Required | Description |
|---|---|---|---|
channel | string | Yes | Channel ID or name (#channel) |
text | string | Conditional | Message text (required if no blocks) |
blocks | array | No | Block Kit blocks |
threadTs | string | No | Thread timestamp for replies |
replyBroadcast | boolean | No | Also post to channel |
unfurlLinks | boolean | No | Unfurl URLs (default: true) |
unfurlMedia | boolean | No | Unfurl media (default: true) |
mrkdwn | boolean | No | Parse as mrkdwn (default: true) |
attachments | array | No | Legacy attachments |
metadata | object | No | Message 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}}"
}
}getPermalink
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:
| Field | Type | Required | Description |
|---|---|---|---|
channels | string/array | No | Channels to share to |
content | string | Conditional | Text content |
file | string | Conditional | Base64 encoded file |
filename | string | No | File name |
filetype | string | No | File type (csv, pdf, etc.) |
title | string | No | File title |
initialComment | string | No | Comment with file |
threadTs | string | No | Thread timestamp |
getFile
Get file information.
{
"action": "slack.getFile",
"config": {
"fileId": "{{input.fileId}}"
}
}deleteFile
Delete a file.
{
"action": "slack.deleteFile",
"config": {
"fileId": "{{input.fileId}}"
}
}Modal Actions
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:
| Event | Description |
|---|---|
message | Message in channel/DM |
app_mention | Bot @mentioned |
reaction_added | Emoji reaction added |
channel_created | New channel created |
member_joined_channel | User joined channel |
file_shared | File 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
| Limit | Value |
|---|---|
| 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 webhooks | 1 req/sec |
Troubleshooting
Common Errors
| Error | Cause | Solution |
|---|---|---|
channel_not_found | Invalid channel ID | Verify channel exists and bot has access |
not_in_channel | Bot not in channel | Invite bot to channel |
invalid_blocks | Malformed Block Kit | Validate with Block Kit Builder |
message_not_found | Invalid message ts | Verify timestamp is correct |
ratelimited | Too many requests | Implement backoff, check Retry-After |