Skip to content

Slack actions

Who this is for: people and AI assistants who write workflow steps that tell a team in Slack about something, for example a failed run, a new customer or an access review that is due.

Before you start: you need a Slack connection. See Connect Slack.

These actions are part of our curated platform library. Use them in any workflow as uses: library/slack.<name>@v1. Each action uses one connection slot, slack, which takes a connection made from the Slack template. You find the same actions in the app under Library, and your AI assistant reads their full contracts with the MCP tool get_action.

Action What it does Bot token scope
library/slack.post-message@v1 Posts one message to a channel or a person (changes data) chat:write, and chat:write.public to post in a public channel without joining
library/slack.find-user-by-email@v1 Finds one person by email address (only reads) users:read and users:read.email
library/slack.list-conversations@v1 Lists channels and conversations (only reads) channels:read, groups:read, mpim:read or im:read, by type
library/slack.list-members@v1 Lists the members of one channel (only reads) channels:read, or groups:read for a private channel
library/slack.join-conversation@v1 Lets the app join one public channel (changes data) channels:join
library/slack.open-dm@v1 Opens a direct message with one person (changes data) im:write

Add only the scopes for the actions you use, see Give the app only the scopes it needs.

  • Only what the workflow needs. Slack answers with much more than the actions return. A person lookup returns the user ID and a few flags, and names only when you ask for them. A channel list returns IDs, names and flags, not topics or descriptions.
  • Pages, with a limit. Slack returns long lists a page at a time. The list actions read the pages for you, up to max_pages pages and max_items items. When more was left, the output says truncated: true.
  • When Slack slows you down. If Slack answers 429 Too Many Requests with a wait time of up to a minute, Liitora waits and tries again, within the step’s timeout. A throttled request was not carried out, so a message is never posted twice this way. If it keeps happening, the step fails and says so.
  • Errors. Slack can answer a refusal with a success status, so every action checks Slack’s ok field. A failed step says what it tried to do, Slack’s error code, and what to check, such as a missing scope or an app that isn’t in the channel. Slack’s own error text is left out.
  • Dry runs and test runs change nothing. In a dry run, Liitora holds back the actions that change data and logs them as “would have sent”. The step succeeds with dry_run: true and status: dry_run. A test run that uses a production connection holds them back the same way. The actions that only read still run for real.
  • A person approves it first. Like every workflow, a version that uses these actions runs for real only after an admin approves it. See Approve a workflow.

Posts one message to a channel, a direct message or a person. Each run posts a new message.

Input Required What it is
channel yes Where to post: a channel ID like C024BE91L, a direct message ID (D...), a user ID (U...) for the app’s Messages tab with that person, or a public channel name like general.
text yes The message text, at most 40,000 characters. Slack advises at most 4,000. With blocks, it is what Slack shows in notifications and reads to screen readers.
text_format no plain (default): the text is shown as written. &, < and > are escaped, so run data can’t form links or mentions. mrkdwn: Slack’s formatting is applied, including links and mentions written in the text.
blocks no Block Kit blocks, at most 50. They are sent as given, so escape run data in them yourself.
thread_ts no The ts of a message, to reply in its thread.
reply_broadcast no With thread_ts: also show the reply in the channel (default false).
unfurl_links no Let Slack show previews of web pages linked in the message (default false).
unfurl_media no Let Slack show previews of images, video and audio linked in the message (default false).

Outputs: status (posted or dry_run), changed (true when the message was posted), dry_run, channel (the ID of the conversation the message went to) and ts (the message’s timestamp, which identifies it).

Needs chat:write. The app can post only in channels it is a member of, unless it also has chat:write.public, which lets it post in any public channel. If Slack answers with an internal error or a timeout, the message may have been posted anyway, so the step fails and says so. Check the channel before you retry the step, or you may post twice.

- id: tell
name: Tell the team
uses: library/slack.post-message@v1
connections:
slack: slack
with:
channel: C024BE91L
text: "Invoice ${{ trigger.body.number }} failed to sync."

Finds one person in your Slack workspace by email address.

Input Required What it is
email yes The person’s email address. It is sent as given.
include_names no Also return real_name and display_name (default false: only the ID and flags).

Outputs: found (true or false) and user (id, team_id, deleted and is_bot, and the names with include_names, or null).

Needs users:read and users:read.email. A person Slack doesn’t know, or who was deactivated, gives found: false, not an error.

Lists the conversations the app can see.

Input Required What it is
types no Which conversations to list: public_channel (default), private_channel, mpim (group messages) and im (direct messages).
exclude_archived no Leave archived channels out (default true).
page_size no Conversations per page, 1 to 1000 (default 200).
max_pages no Pages to read at most, 1 to 100 (default 10).
max_items no Conversations to return at most, 1 to 10000 (default 1000).

Outputs: conversations (each with id, name, is_private, is_archived, is_member, is_im, is_mpim, and user for a direct message), pages and truncated.

Each type needs its own scope: channels:read, groups:read, mpim:read or im:read. Private channels, group messages and direct messages are listed only when the app is in them.

Lists the user IDs of the members of one conversation.

Input Required What it is
channel yes The conversation’s ID, like C024BE91L.
page_size no Members per page, 1 to 1000 (default 200).
max_pages no Pages to read at most, 1 to 100 (default 10).
max_items no Members to return at most, 1 to 10000 (default 1000).

Outputs: members (the user IDs), pages and truncated.

Needs channels:read, or groups:read for a private channel the app is in.

Lets the app join one public channel, so it can post there.

Input Required What it is
channel yes The public channel’s ID, like C024BE91L.

Outputs: status (joined, already_member or dry_run), changed (true when this step made the app join), dry_run and channel.

Needs channels:join. When the app is in the channel already, the step succeeds with status: already_member. The app can’t join a private channel this way: someone in it has to invite the app.

Opens the direct message between the app and one person, or returns the one that is already open.

Input Required What it is
user yes The person’s user ID, like U024BE91L. Find it with slack.find-user-by-email.

Outputs: status (opened or dry_run), dry_run and channel (the direct message’s ID, to post to with slack.post-message).

Needs im:write. To post to a person you can also pass their user ID straight to slack.post-message.

- id: who
name: Find the new joiner in Slack
uses: library/slack.find-user-by-email@v1
connections:
slack: slack
with:
email: ${{ trigger.body.email }}
- id: dm
name: Open a direct message
if: ${{ steps.who.outputs.found }}
uses: library/slack.open-dm@v1
connections:
slack: slack
with:
user: ${{ steps.who.outputs.user.id }}

Written from Slack’s own documentation: