LoopFour

Slack Block

Send messages, manage channels, and interact with Slack

Slack Block

The Slack block provides comprehensive access to Slack messaging, channels, modals, and interactive components within your workflows.

Overview

Use the Slack block when you need to:

  • Send notifications to channels or users
  • Create approval workflows with interactive buttons
  • Build rich messages with Block Kit
  • Manage channels and users programmatically
  • Upload files and add reactions

Prerequisites

  • Slack Connection: Configure OAuth via Nango with slack provider
  • Bot Permissions: Bot must be added to target channels
  • Scopes Required: Varies by action (see action-specific requirements)

Configuration

Step Definition

{
  "id": "notify-team",
  "type": "slack",
  "name": "Send Team Notification",
  "config": {
    "action": "sendMessage",
    "channel": "#billing",
    "text": "Invoice {{input.invoice_number}} has been paid!"
  }
}

Configuration Fields

FieldTypeRequiredDescription
actionstringYesThe Slack action to execute
channelstringVariesChannel ID or name (e.g., #general, C1234567890)
textstringVariesMessage text (supports mrkdwn)
blocksarrayVariesBlock Kit blocks for rich layouts
userstringVariesUser ID for user-specific actions

Available Actions

Message Actions

sendMessage

Send a message to a channel or DM.

Required Scopes: chat:write, chat:write.public (for non-member channels)

{
  "id": "send-notification",
  "type": "slack",
  "config": {
    "action": "sendMessage",
    "channel": "#sales",
    "text": "New deal closed: {{input.deal_name}} for ${{input.amount}}",
    "threadTs": "{{input.parent_message_ts}}",
    "unfurlLinks": false,
    "mrkdwn": true
  }
}

Parameters:

FieldTypeDescription
channelstringChannel ID or name
textstringMessage text (required if no blocks)
blocksarrayBlock Kit blocks
threadTsstringReply to thread
replyBroadcastbooleanAlso post to channel when replying
unfurlLinksbooleanEnable link previews
unfurlMediabooleanEnable media previews
mrkdwnbooleanEnable mrkdwn formatting (default: true)
attachmentsarrayLegacy attachments
metadataobjectMessage metadata

Output:

{
  "ok": true,
  "channel": "C1234567890",
  "ts": "1234567890.123456",
  "message": {
    "text": "New deal closed...",
    "user": "U1234567890",
    "ts": "1234567890.123456"
  }
}

sendEphemeral

Send an ephemeral message (only visible to one user).

Required Scopes: chat:write

{
  "id": "private-hint",
  "type": "slack",
  "config": {
    "action": "sendEphemeral",
    "channel": "#general",
    "user": "{{input.user_id}}",
    "text": "Only you can see this message!"
  }
}

Parameters:

FieldTypeDescription
channelstringChannel ID
userstringUser ID to show message to
textstringMessage text
blocksarrayBlock Kit blocks
threadTsstringThread timestamp

scheduleMessage

Schedule a message to be sent later.

Required Scopes: chat:write

{
  "id": "schedule-reminder",
  "type": "slack",
  "config": {
    "action": "scheduleMessage",
    "channel": "#reminders",
    "text": "Don't forget: {{input.reminder_text}}",
    "postAt": "{{input.reminder_time}}"
  }
}

Parameters:

FieldTypeDescription
channelstringChannel ID
postAtnumber/stringUnix timestamp or ISO 8601 datetime
textstringMessage text
blocksarrayBlock Kit blocks

Output:

{
  "ok": true,
  "channel": "C1234567890",
  "scheduled_message_id": "Q1234567890",
  "post_at": 1234567890
}

updateMessage

Update an existing message.

Required Scopes: chat:write

{
  "id": "update-status",
  "type": "slack",
  "config": {
    "action": "updateMessage",
    "channel": "{{steps.send-message.output.channel}}",
    "ts": "{{steps.send-message.output.ts}}",
    "text": "Status: Completed!"
  }
}

Parameters:

FieldTypeDescription
channelstringChannel ID
tsstringMessage timestamp to update
textstringNew message text
blocksarrayNew Block Kit blocks

deleteMessage

Delete a message.

Required Scopes: chat:write

{
  "id": "cleanup-message",
  "type": "slack",
  "config": {
    "action": "deleteMessage",
    "channel": "{{input.channel_id}}",
    "ts": "{{input.message_ts}}"
  }
}

Get a permanent link to a message.

{
  "id": "get-link",
  "type": "slack",
  "config": {
    "action": "getPermalink",
    "channel": "{{input.channel_id}}",
    "messageTs": "{{input.message_ts}}"
  }
}

Output:

{
  "ok": true,
  "channel": "C1234567890",
  "permalink": "https://workspace.slack.com/archives/C1234567890/p1234567890123456"
}

Reaction Actions

addReaction

Add an emoji reaction to a message.

Required Scopes: reactions:write

{
  "id": "react-to-message",
  "type": "slack",
  "config": {
    "action": "addReaction",
    "channel": "{{input.channel_id}}",
    "timestamp": "{{input.message_ts}}",
    "name": "white_check_mark"
  }
}

Parameters:

FieldTypeDescription
channelstringChannel ID
timestampstringMessage timestamp
namestringEmoji name (without colons)

removeReaction

Remove an emoji reaction.

{
  "id": "remove-reaction",
  "type": "slack",
  "config": {
    "action": "removeReaction",
    "channel": "{{input.channel_id}}",
    "timestamp": "{{input.message_ts}}",
    "name": "eyes"
  }
}

File Actions

uploadFile

Upload a file to Slack.

Required Scopes: files:write

{
  "id": "upload-report",
  "type": "slack",
  "config": {
    "action": "uploadFile",
    "channels": ["#reports", "#finance"],
    "content": "{{input.csv_content}}",
    "filename": "report-{{input.date}}.csv",
    "title": "Monthly Report",
    "initialComment": "Here's the monthly report!"
  }
}

Parameters:

FieldTypeDescription
channelsstring/arrayChannel(s) to share file
contentstringText content for the file
filestringBase64 encoded file content
filenamestringName of the file
filetypestringFile type (e.g., csv, pdf)
titlestringTitle of the file
initialCommentstringComment to add with file
threadTsstringThread to upload to

getFile

Get file information.

{
  "id": "get-file-info",
  "type": "slack",
  "config": {
    "action": "getFile",
    "fileId": "{{input.file_id}}"
  }
}

deleteFile

Delete a file.

{
  "id": "delete-file",
  "type": "slack",
  "config": {
    "action": "deleteFile",
    "fileId": "{{input.file_id}}"
  }
}

Modal/View Actions

openModal

Open a modal view (requires trigger_id from interactive event).

Required Scopes: None (uses bot token)

{
  "id": "open-approval-modal",
  "type": "slack",
  "config": {
    "action": "openModal",
    "triggerId": "{{input.trigger_id}}",
    "view": {
      "type": "modal",
      "title": { "type": "plain_text", "text": "Approve Request" },
      "submit": { "type": "plain_text", "text": "Approve" },
      "close": { "type": "plain_text", "text": "Cancel" },
      "blocks": [
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "Approve invoice #{{input.invoice_number}}?"
          }
        },
        {
          "type": "input",
          "block_id": "notes_block",
          "element": {
            "type": "plain_text_input",
            "action_id": "notes_input",
            "multiline": true,
            "placeholder": { "type": "plain_text", "text": "Add notes..." }
          },
          "label": { "type": "plain_text", "text": "Notes" }
        }
      ]
    }
  }
}

Parameters:

FieldTypeDescription
triggerIdstringTrigger ID from interactive event
viewobjectModal view definition

updateModal

Update an existing modal.

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

Parameters:

FieldTypeDescription
viewIdstringView ID to update
externalIdstringAlternative: external ID
viewobjectUpdated view definition
hashstringOptional hash for conflict detection

pushModal

Push a new view onto the modal stack.

{
  "id": "push-details",
  "type": "slack",
  "config": {
    "action": "pushModal",
    "triggerId": "{{input.trigger_id}}",
    "view": {
      "type": "modal",
      "title": { "type": "plain_text", "text": "Details" },
      "blocks": [...]
    }
  }
}

publishHomeTab

Publish content to a user's Home tab.

Required Scopes: None (uses bot token)

{
  "id": "update-home",
  "type": "slack",
  "config": {
    "action": "publishHomeTab",
    "userId": "{{input.user_id}}",
    "view": {
      "type": "home",
      "blocks": [
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "Welcome, *{{input.user_name}}*!"
          }
        },
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "You have {{input.pending_count}} pending approvals."
          }
        }
      ]
    }
  }
}

User Actions

getUser

Get user information.

Required Scopes: users:read

{
  "id": "get-user",
  "type": "slack",
  "config": {
    "action": "getUser",
    "userId": "{{input.user_id}}",
    "includeLocale": true
  }
}

Output:

{
  "ok": true,
  "user": {
    "id": "U1234567890",
    "name": "johndoe",
    "real_name": "John Doe",
    "profile": {
      "email": "john@example.com",
      "display_name": "John"
    }
  }
}

listUsers

List workspace users.

Required Scopes: users:read

{
  "id": "list-users",
  "type": "slack",
  "config": {
    "action": "listUsers",
    "limit": 100,
    "includeLocale": false
  }
}

lookupUserByEmail

Find a user by email address.

Required Scopes: users:read.email

{
  "id": "find-user",
  "type": "slack",
  "config": {
    "action": "lookupUserByEmail",
    "email": "{{input.email}}"
  }
}

Channel Actions

getChannel

Get channel information.

Required Scopes: channels:read, groups:read

{
  "id": "get-channel",
  "type": "slack",
  "config": {
    "action": "getChannel",
    "channelId": "{{input.channel_id}}",
    "includeNumMembers": true
  }
}

listChannels

List channels.

Required Scopes: channels:read, groups:read

{
  "id": "list-channels",
  "type": "slack",
  "config": {
    "action": "listChannels",
    "types": "public_channel,private_channel",
    "excludeArchived": true,
    "limit": 100
  }
}

Parameters:

FieldTypeDescription
typesstringChannel types (public_channel, private_channel, mpim, im)
excludeArchivedbooleanExclude archived channels (default: true)
limitnumberMax results (default: 100)
cursorstringPagination cursor

createChannel

Create a new channel.

Required Scopes: channels:manage, groups:write

{
  "id": "create-project-channel",
  "type": "slack",
  "config": {
    "action": "createChannel",
    "name": "proj-{{input.project_slug}}",
    "isPrivate": false
  }
}

inviteToChannel

Invite users to a channel.

Required Scopes: channels:manage, groups:write

{
  "id": "invite-team",
  "type": "slack",
  "config": {
    "action": "inviteToChannel",
    "channelId": "{{steps.create-channel.output.channel.id}}",
    "users": ["U111111", "U222222", "U333333"]
  }
}

archiveChannel

Archive a channel.

{
  "id": "archive-channel",
  "type": "slack",
  "config": {
    "action": "archiveChannel",
    "channelId": "{{input.channel_id}}"
  }
}

setChannelTopic

Set channel topic.

{
  "id": "set-topic",
  "type": "slack",
  "config": {
    "action": "setChannelTopic",
    "channelId": "{{input.channel_id}}",
    "topic": "Project: {{input.project_name}} | Status: {{input.status}}"
  }
}

getChannelHistory

Get channel message history.

Required Scopes: channels:history, groups:history

{
  "id": "get-history",
  "type": "slack",
  "config": {
    "action": "getChannelHistory",
    "channelId": "{{input.channel_id}}",
    "limit": 50,
    "oldest": "{{input.since_timestamp}}"
  }
}

Bookmark Actions

addBookmark

Add a bookmark to a channel.

Required Scopes: bookmarks:write

{
  "id": "add-bookmark",
  "type": "slack",
  "config": {
    "action": "addBookmark",
    "channelId": "{{input.channel_id}}",
    "title": "Project Dashboard",
    "type": "link",
    "link": "https://dashboard.example.com/{{input.project_id}}"
  }
}

Block Kit Examples

Rich Notification with Buttons

{
  "id": "approval-request",
  "type": "slack",
  "config": {
    "action": "sendMessage",
    "channel": "#approvals",
    "text": "New approval request",
    "blocks": [
      {
        "type": "header",
        "text": { "type": "plain_text", "text": "Invoice Approval Required" }
      },
      {
        "type": "section",
        "fields": [
          { "type": "mrkdwn", "text": "*Invoice:*\n#{{input.invoice_number}}" },
          { "type": "mrkdwn", "text": "*Amount:*\n${{input.amount}}" },
          { "type": "mrkdwn", "text": "*Vendor:*\n{{input.vendor_name}}" },
          { "type": "mrkdwn", "text": "*Due Date:*\n{{input.due_date}}" }
        ]
      },
      {
        "type": "actions",
        "block_id": "approval_actions",
        "elements": [
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "Approve" },
            "action_id": "approve_invoice",
            "style": "primary",
            "value": "{{input.invoice_id}}"
          },
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "Reject" },
            "action_id": "reject_invoice",
            "style": "danger",
            "value": "{{input.invoice_id}}"
          },
          {
            "type": "button",
            "text": { "type": "plain_text", "text": "View Details" },
            "action_id": "view_invoice",
            "url": "https://app.example.com/invoices/{{input.invoice_id}}"
          }
        ]
      }
    ]
  }
}

Status Update with Context

{
  "id": "pipeline-status",
  "type": "slack",
  "config": {
    "action": "sendMessage",
    "channel": "#deployments",
    "blocks": [
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "{{#if input.success}}:white_check_mark:{{else}}:x:{{/if}} *Build {{input.build_number}}* {{input.status}}"
        }
      },
      {
        "type": "context",
        "elements": [
          { "type": "mrkdwn", "text": "Branch: `{{input.branch}}`" },
          { "type": "mrkdwn", "text": "Commit: `{{input.commit_sha}}`" },
          { "type": "mrkdwn", "text": "Duration: {{input.duration}}s" }
        ]
      }
    ]
  }
}

Template Variables

Access workflow data in your Slack configuration:

VariableDescription
{{input.field}}Workflow trigger input
{{steps.stepId.output.field}}Previous step output
{{variables.name}}Workflow variables
{{env.VAR}}Environment variables

Error Handling

Common Errors

ErrorCauseSolution
channel_not_foundInvalid channel ID/nameVerify channel exists and bot has access
not_in_channelBot not in channelInvite bot to channel or use chat:write.public
invalid_blocksMalformed Block KitValidate blocks with Block Kit Builder
trigger_expiredStale trigger_idTrigger IDs expire in 3 seconds
missing_scopeInsufficient permissionsAdd required OAuth scopes
rate_limitedToo many requestsImplement backoff, respect retry-after

Error Response

{
  "ok": false,
  "error": "channel_not_found",
  "response_metadata": {
    "messages": ["Channel not found or bot not a member"]
  }
}

Rate Limits

TierLimitDescription
Tier 11/minLow-frequency methods
Tier 220/minMost methods
Tier 350/minHigh-frequency methods
Tier 4100/minVery high-frequency
SpecialVarieschat.postMessage: ~1/sec per channel

Slack returns 429 Too Many Requests with Retry-After header when limits are exceeded.

Example Workflow

Complete approval workflow with Slack:

{
  "name": "Invoice Approval Workflow",
  "trigger": {
    "type": "webhook",
    "provider": "quickbooks",
    "events": ["invoice.created"]
  },
  "steps": [
    {
      "id": "check-amount",
      "type": "condition",
      "config": {
        "conditions": {
          "left": "{{input.payload.TotalAmt}}",
          "operator": "gt",
          "right": 1000
        },
        "then": ["request-approval"],
        "else": ["auto-approve"]
      }
    },
    {
      "id": "request-approval",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#finance-approvals",
        "text": "Invoice requires approval",
        "blocks": [
          {
            "type": "section",
            "text": {
              "type": "mrkdwn",
              "text": "*New Invoice Requires Approval*\n\nAmount: ${{input.payload.TotalAmt}}\nVendor: {{input.payload.CustomerRef.name}}"
            }
          },
          {
            "type": "actions",
            "elements": [
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Approve" },
                "action_id": "approve_{{input.payload.Id}}",
                "style": "primary"
              },
              {
                "type": "button",
                "text": { "type": "plain_text", "text": "Reject" },
                "action_id": "reject_{{input.payload.Id}}",
                "style": "danger"
              }
            ]
          }
        ]
      }
    },
    {
      "id": "auto-approve",
      "type": "slack",
      "config": {
        "action": "sendMessage",
        "channel": "#finance-log",
        "text": ":white_check_mark: Auto-approved invoice #{{input.payload.DocNumber}} for ${{input.payload.TotalAmt}}"
      }
    }
  ]
}