Appearance
$io.slack
Server API reference.
Functions
- $io.slack.deleteMessage
- $io.slack.deleteScheduledMessage
- $io.slack.getChannelByName
- $io.slack.getConversationHistory
- $io.slack.getConversationInfo
- $io.slack.getConversationMembers
- $io.slack.getPermalink
- $io.slack.getThreadReplies
- $io.slack.getUserInfo
- $io.slack.listConversations
- $io.slack.listFiles
- $io.slack.listScheduledMessages
- $io.slack.listUsers
- $io.slack.postEphemeral
- $io.slack.postMessage
- $io.slack.processInboundWebhook
- $io.slack.scheduleMessage
$io.slack.deleteMessage
Delete a specific Slack message using its channel ID and message timestamp (ts).
Usage
js
$io.slack.deleteMessage(connectionName, channel, ts, customRequestProperties)Description
Wraps Slack's chat.delete to remove a normal (persistent) message from a conversation. Provide the channel ID and the exact message timestamp (ts) returned by Slack when the message was created.
Important details
- The pair (channel, ts) uniquely identifies a message in Slack; there is no separate message ID.
- With a bot token, you can typically delete messages posted by your app.
- With a user token (BYO Custom OAuth2), deleting is limited to messages posted by that user, subject to workspace policies.
- Ephemeral messages (from
chat.postEphemeral) cannot be deleted because they are not stored in history.
Scopes
- Requires
chat:write. Additional admin restrictions may apply depending on workspace settings.
Usage Scenarios
- Clean up automated notifications after a delay
- Implement undo/rollback flows for bot posts
- Remove outdated status messages from a channel
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Channel ID (e.g., 'C0123456789').
ts
Type: String | Date | moment
Required: Yes
Exact Slack timestamp of the message to delete (e.g., '1757613097.379449'). If Date/moment is provided, it is normalized to epoch seconds, but deletion should use the precise ts string returned by Slack.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' } to choose bearer.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.channel: channel ID\n- data.ts: timestamp of the deleted message
Related Functions
$io.slack.postMessage$io.system.delay$io.slack.postEphemeral$io.slack.getConversationHistory$io.slack.getPermalink
$io.slack.deleteScheduledMessage
Delete a scheduled Slack message before it is posted.
Usage
js
$io.slack.deleteScheduledMessage(connectionName, channel, scheduledMessageId, customRequestProperties)Description
Wraps Slack's chat.deleteScheduledMessage to cancel a scheduled post. Provide the channel ID and the scheduled message ID as returned by scheduleMessage or listScheduledMessages.
Token & scope notes
- Requires
chat:write.
Behavior
- If the scheduled time has already passed, or the ID is invalid, Slack returns
invalid_scheduled_message_id. - Scheduled messages are uniquely identified by
scheduled_message_idplus thechannel. - Once deleted, the message will never be posted.
Common flow
- Use after
listScheduledMessagesto bulk-cancel future posts.
Usage Scenarios
- Cancel a scheduled announcement that is no longer needed
- Allow users to reschedule posts by deleting the old one
- Clean up scheduled jobs in admin dashboards
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Channel ID where the scheduled message is queued.
scheduledMessageId
Type: String
Required: Yes
The scheduled message ID, returned by scheduleMessage or listScheduledMessages.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true
Related Functions
$io.slack.scheduleMessage$io.slack.listScheduledMessages$io.slack.postMessage$io.slack.deleteMessage
$io.slack.getChannelByName
Lookup a Slack channel by its name and return its details.
Usage
js
$io.slack.getChannelByName(connectionName, channelName, options, customRequestProperties)Description
This function provides a convenience wrapper around conversations.list to locate a Slack channel by its name (without the leading "#"). It automatically paginates through channels until a match is found or the maximum page limit is reached.
Channel names are unique per Slack workspace (public or private). Archived channels also reserve their names, so at most one channel will match.
If found, the function returns a channel object with fields such as id, name, is_archived, is_private, and num_members. If no channel is found, data will be null.
The options parameter controls pagination and whether to include archived channels.
Usage Scenarios
- Resolve a channel ID from its human-readable name
- Validate whether a given channel exists before posting a message
- Fetch archived channel details by name for auditing
Parameters
connectionName
Type: String
Required: Yes
The name of the Slack connection configured in the ioLoop app.
channelName
Type: String
Required: Yes
The Slack channel name (without leading '#'). Case-insensitive.
options
Type: Object
Required: No
Options to control lookup behavior.
customRequestProperties
Type: Object
Required: No
Advanced axios configuration overrides, headers, or actor selection. Normally null.
Output
Type: Promise
Returns a Promise resolving to an object with:
- status: true if call succeeded
- data: the channel object if found, or null if not
- err: error message if failed
Related Functions
$io.slack.getConversationHistory
Retrieve message history for a conversation (newest first), with optional time range and pagination.
Usage
js
$io.slack.getConversationHistory(connectionName, channel, oldest, latest, inclusive, limit, cursor, customRequestProperties)Description
Wraps Slack's conversations.history. Returns messages for a conversation (channel, group, IM, MPIM) in reverse chronological order (newest first). Supports time range filtering (oldest, latest), inclusivity, page size, and cursor-based pagination.
Token rules:
- With a bot token, Slack only returns history for conversations the bot is a member of.
- For public/private channels where the bot is not a member, use a user token via a Custom OAuth2 profile with appropriate scopes (e.g.,
channels:history,groups:history). Pass{ actor: 'user' }viacustomRequestProperties.
Time parameters:
- If you already have a Slack ts (e.g., "1741882130.123456"), pass it as-is.
- Dates provided as Date or moment objects are normalized to epoch seconds ('X') before calling Slack.
Usage Scenarios
- Load the most recent messages from a channel before posting a summary
- Fetch messages within a time window for analytics or archival
- Page backwards through older history using Slack cursors
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Conversation ID (e.g., 'C0123456789').
oldest
Type: String | Number | Date | moment
Required: No
Start of range. Accepts Slack ts string or a Date/moment/epoch value; Dates/moment are converted to epoch seconds.
latest
Type: String | Number | Date | moment
Required: No
End of range. Accepts Slack ts string or a Date/moment/epoch value; Dates/moment are converted to epoch seconds.
inclusive
Type: Boolean
Required: No
If true, include messages whose ts equals oldest or latest.
limit
Type: Number
Required: No
Max messages per page (Slack caps apply; commonly up to 1000).
cursor
Type: String
Required: No
Pagination cursor from a previous response (use data.response_metadata.next_cursor).
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). May include { actor: 'bot' | 'user' } in BYO mode to select bearer.
Output
Type: Promise
Resolves to { status: true, data, err }. On success:
- data.ok: true
- data.messages: Array of message objects (ts, text, user, thread_ts, blocks, etc.) in newest-first order
- data.has_more: boolean (when provided by Slack)
- data.response_metadata.next_cursor: string for pagination
Related Functions
$io.slack.getConversationInfo$io.slack.getThreadReplies$io.slack.listConversations$io.slack.postMessage$io.slack.listUsers$io.slack.getPermalink
$io.slack.getConversationInfo
Get detailed information about a single conversation (channel, group, IM, or MPIM).
Usage
js
$io.slack.getConversationInfo(connectionName, channel, customRequestProperties)Description
This function wraps Slack's conversations.info to return metadata about a specific conversation, such as id, name, is_private, is_archived, purpose, and topic.
By default the bot token is used (scopes like channels:read, groups:read, im:read, mpim:read). In BYO (Custom OAuth2) profiles, you may pass { actor: 'user' } via customRequestProperties to force a user token.
Usage Scenarios
- Show channel metadata (name, privacy, archived status) before posting
- Verify a channel ID obtained from user input or prior search
- Fetch topic, purpose, and member-related flags to drive UI
Parameters
connectionName
Type: String
Required: Yes
The name of the Slack connection configured in ioLoop.
channel
Type: String
Required: Yes
The conversation ID (e.g., 'C0123456789').
customRequestProperties
Type: Object
Required: No
Advanced options passed through to the request. May include { actor: 'bot' | 'user' } in BYO mode.
Output
Type: Promise
Resolves to { status: true, data, err }. On success:
- data.ok: true
- data.channel: Object with fields such as id, name, is_private, is_archived, is_general, is_shared, num_members (when available), purpose, topic, and other Slack attributes.
Related Functions
$io.slack.listConversations$io.slack.getConversationMembers$io.slack.getConversationHistory$io.slack.postMessage$io.slack.getPermalink$io.slack.listUsers
$io.slack.getConversationMembers
Retrieve the list of member user IDs for a given conversation (channel, group, IM, or MPIM).
Usage
js
$io.slack.getConversationMembers(connectionName, channel, limit, cursor, customRequestProperties)Description
Wraps Slack's conversations.members API. Returns a paginated list of user IDs belonging to the specified conversation.
Token rules:
- With a bot token, Slack only returns members for conversations the bot is a member of. Use
conversations.joinor invite the app to the channel. - In BYO (Custom OAuth2) profiles, you can pass
{ actor: 'user' }incustomRequestPropertiesto use a user token withchannels:read/groups:readscopes.
Use the response_metadata.next_cursor to paginate through large channels.
Usage Scenarios
- Fetch all members of a channel before sending bulk DMs
- Check whether a specific user is part of a channel
- Paginate through large member lists to build a roster
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Conversation ID (e.g., 'C0123456789').
limit
Type: Number
Required: No
Maximum number of members to return per page. Slack supports up to 1000.
cursor
Type: String
Required: No
Pagination cursor from a previous response. Use data.response_metadata.next_cursor.
customRequestProperties
Type: Object
Required: No
Advanced request options. May include { actor: 'bot' | 'user' } in BYO mode to control which token is used.
Output
Type: Promise
Resolves to { status: true, data, err }. On success:
- data.ok: true
- data.members: Array of user IDs (strings)
- data.response_metadata.next_cursor: cursor string for pagination
Related Functions
$io.slack.listConversations$io.slack.getConversationInfo$io.slack.getConversationHistory$io.slack.listUsers$io.slack.getUserInfo$io.slack.lookupUserByEmail
$io.slack.getPermalink
Retrieve a permanent link (permalink) to a specific Slack message in a channel.
Usage
js
$io.slack.getPermalink(connectionName, channel, messageTs, customRequestProperties)Description
Wraps Slack's chat.getPermalink to obtain a permanent URL for a message in a channel. Provide the channel ID and the exact message timestamp (ts) returned by Slack when the message was posted.
Key details
- Permalinks are stable, shareable URLs that point directly to the message in Slack.
- They remain valid even if the message is later deleted (but will show an error if the message no longer exists).
- Requires
chat:writeorchannels:read/equivalent read scopes, depending on the channel type. - Typically used together with
postMessage(to create) anddeleteMessage(to clean up).
Example flow
- Post a message with
postMessage. - Call
getPermalinkto capture the URL. - Optionally delete the message while keeping the permalink for reference.
Usage Scenarios
- Generate a shareable link to a message for reference outside Slack
- Fetch a permalink before deleting or archiving the message
- Store a direct pointer to a message for audit or logging purposes
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Channel ID (e.g., 'C0123456789').
messageTs
Type: String | Date | moment
Required: Yes
Message timestamp of the message to link (e.g., '1757613097.379449'). If Date/moment is provided, it is normalized to epoch seconds, but best practice is to use the exact ts string returned by Slack.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' } to select bearer.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.channel: channel ID\n- data.permalink: the permanent URL pointing to the message.
Related Functions
$io.slack.postMessage$io.slack.deleteMessage$io.slack.getConversationHistory$io.slack.getThreadReplies
$io.slack.getThreadReplies
Retrieve all messages in a specific Slack thread (root + replies), with cursor pagination.
Usage
js
$io.slack.getThreadReplies(connectionName, channel, threadTs, limit, cursor, customRequestProperties)Description
Wraps Slack's conversations.replies to return the thread root and its replies in reverse chronological order (newest first). You must provide the root message's thread_ts. A convenient way to find one is to call $io.slack.getConversationHistory and look for a message where m.thread_ts && m.ts === m.thread_ts (root). Replies have m.thread_ts pointing back to that root.
Token & access rules:
- With a bot token, the app must be a member of the conversation.
- For many public/private channel threads, Slack may require a user token with
channels:history/groups:history. In BYO (Custom OAuth2), pass{ actor: 'user' }viacustomRequestProperties. - IM/MPIM threads generally work with bot tokens if you have
im:history/mpim:history.
Notes:
- Pagination uses
response_metadata.next_cursor. - If you want oldest→newest order, reverse the returned array client-side.
Usage Scenarios
- Expand a thread to summarize or analyze the discussion
- Fetch replies for moderation or escalation workflows
- Build a UI that shows threaded conversations on demand
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Conversation ID (e.g., 'C0123456789').
threadTs
Type: String | Date | moment
Required: Yes
Root message timestamp (Slack ts). If a Date/moment is provided, it is normalized to epoch seconds.
limit
Type: Number
Required: No
Max messages per page (Slack caps apply).
cursor
Type: String
Required: No
Pagination cursor from a previous response (use data.response_metadata.next_cursor).
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' } to select bearer.
Output
Type: Promise
Resolves to { status: true, data, err }. On success:
- data.ok: true
- data.messages: Array with the thread root and its replies (fields like ts, thread_ts, user, text, blocks, etc.), newest first
- data.response_metadata.next_cursor: string for pagination
Related Functions
$io.slack.getConversationHistory$io.slack.getConversationInfo$io.slack.postMessage$io.slack.getPermalink$io.slack.listUsers
$io.slack.getUserInfo
Fetch detailed profile information for a specific Slack user.
Usage
js
$io.slack.getUserInfo(connectionName, user, customRequestProperties)Description
Wraps Slack's users.info to retrieve a single user's profile and status by user ID (e.g., 'U0123456789').
Token & scope notes
- Requires
users:read. - Email in
user.profile.emailrequiresusers:read.email.
Typical fields returned
id,team_id,name,deleted,is_botprofile(e.g.,real_name,display_name,email,image_*)
Usage Scenarios
- Display a user’s full profile in a people panel
- Resolve a user ID to email / real name
- Check if a user is deactivated or a bot
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
user
Type: String
Required: Yes
Slack user ID to fetch (e.g., 'U0123456789').
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.user: the full user object
Related Functions
$io.slack.listUsers$io.slack.lookupUserByEmail$io.slack.getConversationMembers$io.slack.postEphemeral
$io.slack.listConversations
List conversations (channels, groups, IMs, MPIMs) visible to the connection.
Usage
js
$io.slack.listConversations(connectionName, types, limit, cursor, excludeArchived, customRequestProperties)Description
This function wraps the Slack conversations.list API. It returns channels, groups, IMs, and MPIMs based on the provided types.
By default, the connection uses the bot token (with scopes channels:read, groups:read, im:read, mpim:read). If the profile is BYO (Custom OAuth2), you may specify { actor: 'user' } in customRequestProperties to use a user token.
Results include channel metadata such as id, name, is_private, is_archived, num_members, purpose, topic, and more. Pagination is supported via Slack's response_metadata.next_cursor.
Usage Scenarios
- Fetch a list of public and private channels in the workspace
- Enumerate IMs or MPIMs for direct messaging use cases
- Build a channel picker UI for posting or searching
Parameters
connectionName
Type: String
Required: Yes
The name of the Slack connection configured in ioLoop.
types
Type: String | Array<String>
Required: No
Conversation types to include. Allowed values: public_channel, private_channel, im, mpim. Accepts comma-separated string or array. Default: all types.
limit
Type: Number
Required: No
Maximum number of conversations to return per page. Slack supports up to 1000. Default is server-defined.
cursor
Type: String
Required: No
Pagination cursor from a previous response. Use response_metadata.next_cursor from the prior call.
excludeArchived
Type: Boolean
Required: No
If true, exclude archived conversations. Default is false.
customRequestProperties
Type: Object
Required: No
Advanced options passed through to the request. May include { actor: 'bot' | 'user' } to control which token is used (BYO mode only).
Output
Type: Promise
Resolves to { status: true, data, err }.
- data.ok: true if Slack succeeded
- data.channels: Array of conversation objects (id, name, is_private, num_members, purpose, topic, etc.)
- data.response_metadata.next_cursor: cursor string for pagination
Related Functions
$io.slack.getConversationInfo$io.slack.getConversationMembers$io.slack.getConversationHistory$io.slack.postMessage$io.slack.listUsers$io.slack.getUserInfo
$io.slack.listFiles
List files in Slack with optional filters for user, channel, time range, and types; supports pagination.
Usage
js
$io.slack.listFiles(connectionName, user, channel, tsFrom, tsTo, types, limit, cursor, customRequestProperties)Description
Wraps Slack's files.list to retrieve files visible to the token, with optional filters:
Filters
user: only files uploaded by a specific user (e.g., 'U0123456789')channel: only files shared in a specific channel (e.g., 'C0123456789')tsFrom/tsTo: inclusive time range; accepts Unix epoch seconds or Date/moment (normalized automatically)types: one or more categories (comma-separated or array), e.g. 'images,spaces,pdfs,snippets,zip'
Scopes
- Requires
files:read.
Pagination
- Use
limitand pass backresponse_metadata.next_cursorascursorto fetch subsequent pages.
Usage Scenarios
- Browse recent uploads in a specific channel
- Audit files shared by a particular user
- Find PDFs/images within a date range
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
user
Type: String
Required: No
Filter by uploader's user ID (e.g., 'U0123456789').
channel
Type: String
Required: No
Filter by channel ID where the file was shared (e.g., 'C0123456789').
tsFrom
Type: String | Number | Date | moment
Required: No
Oldest timestamp (inclusive). Unix epoch seconds preferred; Date/moment accepted.
tsTo
Type: String | Number | Date | moment
Required: No
Newest timestamp (inclusive). Unix epoch seconds preferred; Date/moment accepted.
types
Type: String | Array
Required: No
Comma-separated list or array of file categories (e.g., 'images,spaces,pdfs').
limit
Type: Number
Required: No
Max results per page (Slack caps apply).
cursor
Type: String
Required: No
Pagination cursor from a previous call's response_metadata.next_cursor.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.files: Array of file objects (id, name, mimetype, filetype, user, permalink, timestamp, etc.)\n- data.response_metadata.next_cursor: use for pagination
Related Functions
$io.slack.getFileInfo$io.slack.getConversationHistory$io.slack.listConversations$io.slack.listUsers
$io.slack.listScheduledMessages
List scheduled messages in a Slack channel (or across all channels).
Usage
js
$io.slack.listScheduledMessages(connectionName, channel, limit, cursor, customRequestProperties)Description
Wraps Slack's chat.scheduledMessages.list to retrieve pending scheduled messages. Can return messages across all channels accessible to the token, or filtered to a single channel.
Token & scope notes
- Requires
chat:write(andchat:write.publicif posting into public channels where the bot is not a member).
Pagination
- Slack responses include
response_metadata.next_cursor. - Pass that cursor back to fetch additional pages.
Common flow
- Call after
scheduleMessageto confirm scheduling. - Iterate pages until no
next_cursorremains.
Usage Scenarios
- View pending scheduled posts for a specific channel
- Audit all scheduled messages across a workspace
- Implement a scheduler UI to manage upcoming messages
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: No
Channel ID to filter by (e.g., 'C0123456789'). Leave null to list across all channels.
limit
Type: Number
Required: No
Maximum number of results per page. Slack may cap this internally.
cursor
Type: String
Required: No
Pagination cursor from a previous call.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.scheduled_messages: Array of { id, channel_id, post_at, text, ... }\n- data.response_metadata.next_cursor: for pagination
Related Functions
$io.slack.scheduleMessage$io.slack.deleteScheduledMessage$io.slack.postMessage$io.slack.getConversationHistory
$io.slack.listUsers
List workspace users with basic profile details; supports pagination.
Usage
js
$io.slack.listUsers(connectionName, limit, cursor, customRequestProperties)Description
Wraps Slack's users.list to retrieve members of the workspace. Returns an array of members with user objects (id, name, profile, deleted, is_bot, etc.).
Token & scope notes
- Requires
users:read. - To include email addresses in
profile.email, the token must haveusers:read.email.
Pagination
- Slack responses include
response_metadata.next_cursor. - Pass that cursor back via the
cursorparameter to fetch the next page.
Usage Scenarios
- Build a people picker or mention autocomplete
- Audit active vs. deactivated users
- Fetch user IDs and emails for mapping to internal accounts
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
limit
Type: Number
Required: No
Max users per page (Slack caps apply).
cursor
Type: String
Required: No
Pagination cursor from a previous call's response_metadata.next_cursor.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.members: Array of user objects (id, name, profile.real_name, profile.email, etc.)\n- data.response_metadata.next_cursor: for pagination
Related Functions
$io.slack.getUserInfo$io.slack.lookupUserByEmail$io.slack.listConversations$io.slack.getConversationMembers
$io.slack.postEphemeral
Send an ephemeral (private, non-persistent) message to a specific user in a Slack channel.
Usage
js
$io.slack.postEphemeral(connectionName, channel, user, text, blocks, attachments, customRequestProperties)Description
Wraps Slack's chat.postEphemeral to send a temporary, private message in a channel, visible only to the specified user. Ephemeral messages do not persist in history and disappear when the user refreshes Slack or leaves the channel.
Token & scope notes
- Requires
chat:write. - Ephemeral messages cannot be sent into public channels the app is not a member of;
chat:write.publicis not applicable. - In BYO (Custom OAuth2) profiles, you may use a user token by passing
{ actor: 'user' }viacustomRequestProperties.
Limitations
- Ephemeral messages are always standalone (no
thread_ts,reply_broadcast, ormetadata). - The
usermust be present in the target channel context.
Usage Scenarios
- Provide just-in-time tips or onboarding hints only visible to a single user
- Send contextual error or validation feedback without cluttering the channel
- Notify a user about something privately while keeping the conversation clean
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Channel ID (e.g., 'C0123456789'). Must be a channel where the app is a member.
user
Type: String
Required: Yes
Slack user ID (e.g., 'U12345678') of the user who should see the ephemeral message.
text
Type: String
Required: No
Fallback and accessibility text. Recommended even when blocks are provided.
blocks
Type: Array | Object
Required: No
Block Kit payload for rich message layout.
attachments
Type: Array
Required: No
Legacy message attachments (not recommended; prefer blocks).
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):
- data.ok: true
- data.message_ts: ephemeral message timestamp (ephemeral only; not persisted)
- data.channel: channel ID
- data.user: user ID the message was shown to
Related Functions
$io.slack.postMessage
Post a message to a Slack conversation (channel, group, IM) with optional Block Kit, threading, broadcast, and metadata.
Usage
js
$io.slack.postMessage(connectionName, channel, text, blocks, threadTs, replyBroadcast, metadata, customRequestProperties)Description
Wraps Slack's chat.postMessage to send a persistent message visible to everyone in the target conversation. You can include plain text, Block Kit blocks, post as a threaded reply via threadTs, optionally broadcast a threaded reply to the channel with replyBroadcast, and attach metadata ({ event_type, event_payload }) for app-defined context.
Token & scope notes
- Requires
chat:write. - To post to public channels the bot is not a member of, the token also needs
chat:write.public. - In BYO (Custom OAuth2) profiles, you may use a user token by passing
{ actor: 'user' }viacustomRequestProperties(ensure user token has appropriate permissions).
Threading
- Provide the root thread timestamp as
threadTs(Slack ts). If a Date/moment is supplied, it is converted to epoch seconds; Slack ts strings pass through unchanged. - Set
replyBroadcast=trueto also broadcast a thread reply back into the channel timeline.
Usage Scenarios
- Send announcements or alerts into a channel
- Post a threaded reply to keep discussions organized
- Attach Block Kit content and custom app metadata for downstream processing
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Conversation ID (e.g., 'C0123456789').
text
Type: String
Required: No
Fallback and accessibility text. Recommended even when blocks is provided.
blocks
Type: Array | Object
Required: No
Block Kit payload describing rich message layout. Optional if text adequately represents content.
threadTs
Type: String | Date | moment
Required: No
Root thread timestamp (Slack ts). If Date/moment is provided, it is normalized to epoch seconds. Slack ts strings are passed through as-is.
replyBroadcast
Type: Boolean
Required: No
If true and posting in a thread, also broadcast the reply to the channel.
metadata
Type: Object
Required: No
Optional app metadata: { event_type: String (<=32 chars), event_payload: Object (<= ~8 KB JSON) }.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' } to select bearer.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):
- data.ok: true
- data.channel: channel ID
- data.ts: message timestamp (Slack ts)
- data.message: full message object (text, blocks, user/bot info, thread_ts when applicable)
Related Functions
$io.slack.postEphemeral$io.slack.getPermalink$io.slack.getConversationHistory$io.slack.getThreadReplies$io.slack.listConversations$io.slack.getConversationInfo
$io.slack.processInboundWebhook
Verify, parse, and optionally enrich incoming Slack webhooks (Events API, Interactivity, Slash Commands).
Usage
js
$io.slack.processInboundWebhook(connectionName, headers, rawBody, opts)Description
This helper verifies the Slack signature, parses the inbound body (JSON or application/x-www-form-urlencoded), handles URL verification, and returns a normalized envelope plus a convenient info object. When opts.enrich is `true), it will optionally enrich the info with user, channel, and (for IMs) the DM counterparty via Web API calls.
What it handles
- Events API:
type: "event_callback"(e.g.,message,app_mention). It surfaceschannelId,userId,text,ts,threadTs,channelType, mentions, files, etc. - Interactivity: Button/select/modals POSTs with form-encoded
payloadJSON. - Slash Commands: Form-encoded submissions including
command,text,channel_id,user_id.
Signature verification
- Uses Slack's signing secret and
v0HMAC scheme. Requires the exact raw request body bytes (not parsed JSON) and the request headersx-slack-signatureandx-slack-request-timestamp. - Rejects stale requests older than
opts.maxAgeSec(default 300s).
URL verification
- If the payload is
{"type":"url_verification","challenge": "..."}, the function returnsisChallenge: trueand thechallengevalue so you can echo it back to Slack.
Normalized output
envelope: canonicalized view of the payload:- Events API →
{ type: "event_callback", event, payload, raw } - Interactivity →
{ type: "<interaction_type>", event:null, payload, raw } - Slash Command → handled as form; details surfaced on
info
- Events API →
info: quick-access fields commonly needed by handlers:source:"event_callback" | "interaction" | "slash_command" | "json" | "form"teamIdchannelIdchannelType(when available or after enrichment):"channel" | "group" | "im" | "mpim"userId,botIdtext,blocksts,threadTsfiles(if present on message events)mentions: extracted<@U...>mentions fromtext- Slash:
command,commandText,responseUrl
Optional enrichment (if opts.enrich === true)
enrichment.user: result ofusers.infoforinfo.userIdenrichment.channel: result ofconversations.infoforinfo.channelIdenrichment.dmOtherUserIdandenrichment.dmOtherUserfor IMs, viaconversations.members(+ optionalusers.info)
Typical handler flow
- Call this function with
headers, rawbody, andopts.signingSecret. - If
data.isChallenge→ respond withdata.challenge(plain text). - Else, inspect
data.info+data.envelopeto decide how to respond. - Optionally use
$io.slack.postMessage/postEphemeral/ etc.
Example
js
const headers = $io.system.getWebHookRequestHeaders(hookCtxt);
const rawBody = hookCtxt.znCfCtxt.reqInfo.rawBody;
const p = await $io.slack.processInboundWebhook('my-slack-conn', headers, rawBody, {
signingSecret: process.env.SLACK_SIGNING_SECRET,
maxAgeSec: 300,
enrich: true,
enrichFlags: { user: true, channel: true, dmCounterpart: true }
});
if(!p.status) {
// 401 Unauthorized
}
if(p.data.isChallenge) {
// 200 text/plain with p.data.challenge
}
const { info, enrichment, envelope } = p.data;
if(envelope.type === 'event_callback' && envelope.event?.type === 'app_mention') {
await $io.slack.postMessage('my-slack-conn', info.channelId, `Hi <@${info.userId}>`, null, info.threadTs || info.ts);
}Usage Scenarios
- Receive Slack Events API messages and route by channel/user/thread
- Handle Interactivity payloads (buttons, selects, modals) with verified requests
- Process Slash Commands and respond in-channel or ephemerally
- Normalize diverse Slack webhook bodies into a single shape for business logic
Parameters
connectionName
Type: String
Required: Yes
Name of the Slack connection configured in the ioLoop app.
headers
Type: Object
Required: Yes
Raw HTTP headers from the inbound webhook request. Must include Slack's 'x-slack-signature' and 'x-slack-request-timestamp'.
rawBody
Type: Buffer | String
Required: Yes
The exact raw request body as received (BEFORE parsing). Required for HMAC verification.
opts
Type: Object
Required: No
Options for verification and enrichment.
Output
Type: Promise
Resolves to an object: \n- status: true on success\n- data: {\n verified: true,\n isChallenge: boolean,\n challenge?: string,\n source: string,\n envelope: { type?: string, event?: Object, payload?: Object, raw: any },\n info: { source: string, teamId?: string, channelId?: string, channelType?: string, userId?: string, botId?: string, text?: string, blocks?: any, ts?: string, threadTs?: string, files?: any, mentions: string[], command?: string, commandText?: string, responseUrl?: string },\n enrichment?: { user?: Object, channel?: Object, dmOtherUserId?: string, dmOtherUser?: Object, err?: string }\n}\n- err: Error message if failed (e.g., signature verification failure, stale timestamp).
Related Functions
$io.slack.execApiRequest$io.slack.getUserInfo$io.slack.getConversationInfo$io.slack.getConversationMembers$io.slack.postMessage$io.slack.postEphemeral$io.slack.getPermalink$io.slack.getConversationHistory$io.slack.getThreadReplies$io.slack.listConversations$io.slack.listUsers
$io.slack.scheduleMessage
Schedule a Slack message to be posted at a future time.
Usage
js
$io.slack.scheduleMessage(connectionName, channel, text, postAt, blocks, threadTs, customRequestProperties)Description
Wraps Slack's chat.scheduleMessage to queue a message for delivery at a future time. Provide a channel, the message content (text and/or blocks), and a postAt time in the future.
Token & scope notes
- Requires
chat:write. - To schedule messages into public channels where the bot is not a member, the token also needs
chat:write.public.
Scheduling rules
postAtmust be a time in the future, expressed as Unix epoch seconds.- Dates or moment objects are normalized automatically.
- Optional: supply a
threadTsto schedule a threaded reply instead of a new top-level message.
Limitations
- Maximum scheduled time is ~120 days in the future.
- Scheduled messages count toward per-workspace limits.
Usage Scenarios
- Schedule an announcement for later in the day
- Queue reminders or notifications without running a separate job
- Post a threaded reply at a specific time
Parameters
connectionName
Type: String
Required: Yes
Slack connection name configured in ioLoop.
channel
Type: String
Required: Yes
Channel ID (e.g., 'C0123456789').
text
Type: String
Required: No
Fallback and accessibility text. Recommended even when blocks are provided.
postAt
Type: String | Number | Date | moment
Required: Yes
When to post. Slack expects Unix epoch seconds, but Date or moment objects are also accepted.
blocks
Type: Array | Object
Required: No
Block Kit payload describing rich message layout.
threadTs
Type: String | Date | moment
Required: No
Root thread timestamp (Slack ts). If provided, schedules the message as a thread reply.
customRequestProperties
Type: Object
Required: No
Advanced request options (pass-through). In BYO mode, may include { actor: 'bot' | 'user' }.
Output
Type: Promise
Resolves to { status: true, data, err }. On success (Slack response):\n- data.ok: true\n- data.channel: channel ID\n- data.scheduled_message_id: ID of the scheduled message\n- data.post_at: Unix epoch seconds when the message will post

