Slack triggers
Start a workflow from Slack events, slash commands or interactions, and read the payload each Slack trigger passes into the workflow run.
A Slack trigger starts a run when something happens in a Slack workspace your company has connected: a message is posted, someone runs a slash command, or someone clicks a button. There are three trigger types:
| Type | Starts a run when |
|---|---|
slack_event | Slack sends an Events API event, such as message or app_mention |
slack_slash_command | Someone runs a slash command, such as /invoice |
slack_interactive | Someone clicks a button, submits or closes a modal, or uses a shortcut |
Connect Slack first. Loopfour finds the company for an incoming request by the Slack workspace ID (team_id) on your Slack connection. A request from a workspace with no connection starts nothing.
Slack events
Configuration
{
"trigger": {
"type": "slack_event",
"eventType": "message",
"channelTypes": ["channel"],
"keywords": ["invoice", "refund"]
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "slack_event" | Yes | |
eventType | string | Yes | The Slack event to listen for. See the list below |
channelTypes | array of channel, group, im, mpim | No | Only events from these kinds of conversation |
userIds | string array | No | Only events from these Slack user IDs, such as U01234567 |
keywords | string array | No | The message text must contain at least one of these. Case is ignored |
regex | string | No | The message text must match this JavaScript regular expression. Case matters |
filter | object | No | Extra conditions on the Slack request body. See Filters |
eventType is one of: message, app_mention, reaction_added, reaction_removed, channel_created, channel_archive, channel_unarchive, channel_rename, member_joined_channel, member_left_channel, file_shared, file_created, app_home_opened, link_shared, or * for any of them.
In Studio, add a Slack block and switch it to trigger mode. The block shows Event, Channel Types, User IDs, Keywords (for message and app mention events) and Filter (JSON). Studio does not offer * or regex; set those through the API.
How filters apply
channelTypesanduserIdsonly filter events that carry a channel type or a user. An event without one passes.keywordsandregexonly filter events that have text. An event with no text passes.- An invalid
regexis skipped, not treated as a failure. - Every condition you set must pass.
Events that are skipped
- Messages from bots, including Loopfour's own Slack app. This stops a workflow that posts to Slack from triggering itself.
- For
messageand*triggers, housekeeping message subtypes:message_deleted,message_changed,channel_join,channel_leave,channel_topic,channel_purpose,channel_name,channel_archive,channel_unarchive,pinned_itemandunpinned_item. File uploads (file_share) and thread replies sent to the channel (thread_broadcast) still start runs.
Slash commands
{
"trigger": {
"type": "slack_slash_command",
"command": "/invoice",
"usageHint": "[customer] [amount]"
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "slack_slash_command" | Yes | |
command | string | Yes | The command, including the /. Must match exactly |
description | string | No | A note for people reading the workflow. Not used for matching |
usageHint | string | No | A note on the arguments. Not used for matching |
Slack only sends a command that is set up in the Slack app. command matches a command that arrives; it does not create one in Slack.
The person who runs the command sees a private reply, Processing /invoice..., straight away. The run starts after that. Whatever they typed after the command is in text.
The slash command trigger has no Studio block. Set it in the definition through the API.
Interactions
{
"trigger": {
"type": "slack_interactive",
"interactionType": "block_actions",
"actionId": "start_month_end_close"
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
type | "slack_interactive" | Yes | |
interactionType | block_actions, view_submission, view_closed, shortcut, message_action or * | Yes | The kind of interaction |
actionId | string | No | For block_actions only: one of the clicked actions must have this action_id |
callbackId | string | No | The modal's callback_id, or the shortcut's callback_id, must equal this |
filter | object | No | Extra conditions on the interaction payload. See Filters |
Clicks on the buttons of a Loopfour approval step are handled as approval decisions. They do not start runs.
The interactive trigger has no Studio block. Set it in the definition through the API.
What the run receives
Every Slack trigger puts the request into input.slackEvent. The run is recorded with triggerType: "webhook".
| Field | Meaning |
|---|---|
input.slackEvent.id | Loopfour's ID for this delivery |
input.slackEvent.source | events_api, slash_command or interactive |
input.slackEvent.payload | The Slack request body |
What sits in payload depends on the source:
| Source | Useful fields |
|---|---|
events_api | team_id, event_id, and event with type, user, text, channel, channel_type, ts and, for uploads, files |
slash_command | command, text, user_id, user_name, channel_id, channel_name, team_id, response_url, trigger_id |
interactive | Slack's interaction payload, such as type, user, team, actions, view and callback_id |
For example, a step reads the message text as {{input.slackEvent.payload.event.text}} and the slash command arguments as {{input.slackEvent.payload.text}}. See Variable references.
Filters
filter is a JSON object. Each key is a dot path into the Slack request body, and each value is either a plain value (must be equal) or an operator object with $eq, $ne, $in or $exists. All keys must pass.
{ "event.channel": { "$eq": "C01234567" } }For slack_event, paths start at the Events API body, so the message fields are under event.. For slack_interactive, paths start at the interaction payload.
Endpoints
Loopfour's Slack app sends requests to these routes. You do not call them yourself.
| Route | Receives |
|---|---|
POST /api/v1/slack/events | Events API requests, including Slack's url_verification challenge, which is echoed back |
POST /api/v1/slack/commands | Slash commands |
POST /api/v1/slack/interactive | Button clicks, modal submissions and shortcuts |
Each request must carry a valid Slack signature (x-slack-signature, version v0, HMAC-SHA256 over v0:<timestamp>:<raw body>) and an x-slack-request-timestamp within five minutes. Otherwise it gets 401. The routes use the webhook rate limit of 10,000 requests per minute per IP address.
Loopfour answers Slack straight away and matches workflows afterwards, so Slack's three-second limit is met even when many workflows listen.
Repeated deliveries
Slack resends a request it thinks failed. Loopfour remembers each Events API event_id, and the trigger_id of each slash command or interaction for one hour and ignores a repeat in that time. A repeated slash command gets the private reply Command already processed.
Test without Slack
Start the workflow by hand with a sample request as input:
curl -X POST "https://workflow.loopfour.ai/api/v1/workflows/$WORKFLOW_ID/run" \
-H "x-api-key: $LOOPFOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"slackEvent": {
"id": "test-1",
"source": "events_api",
"payload": {
"team_id": "T01234567",
"event": { "type": "message", "user": "U01234567", "text": "Invoice for Acme, 4200 USD", "channel": "C01234567", "channel_type": "channel" }
}
}
}
}'See API trigger for the response.
App event triggers
Reference for the HubSpot and Airwallex event triggers, the event names a workflow can listen for and the payload each event delivers.
Block reference
Reference for the block types in a workflow definition, with the type name, purpose and a link to the configuration page for each block.
Loopfour