Invoke a workflow from a public channel in Slack
Link triggers are an interactive type of trigger. To invoke one, click on a special "shortcut URL" associated with the trigger. A link trigger will unfurl into a button when posted in a channel. When a link trigger is invoked in a channel, it will be placed in a bookmarked "workflows" folder in that same channel.
Triggers can be added to workflows in two ways:
You can add triggers with the CLI. These static triggers are created only once. You create them with the Slack CLI, attach them to your app's workflow, and that's that. The trigger is typically defined within a trigger file, although you can create a basic link trigger without one.
You can add triggers at runtime. These dynamic triggers are created at any step of a workflow so they can incorporate data acquired from other workflow steps. The trigger is defined within a function file.
Once you've instructed Slack just how to create your link trigger using the CLI, it will respond with the special "shortcut URL" you can then copy and paste into a Slack channel or bookmarks bar. The result will be a handy, portable way to activate your workflow.
When the commands below are successful, the CLI's response looks something like:
⚡ Trigger created
Trigger ID: Ft0123ABC456
Trigger Type: shortcut
Trigger Name: Train markovbot with words
URL: https://slack.com/shortcuts/Ft0123ABC456/6d948ddf69a9d352d9a8ddfd8ca687ea
That string after URL:
is what's most important to you, though that "Trigger ID" comes in handy when you need to modify, remove, or otherwise maintain the triggers you're creating.
Let's talk more about how to create these things with the CLI.
Slack CLI built-in documentation
You can use slack trigger --help
to easily access information on the trigger
command's flags and subcommands.
The triggers you create when running locally (with the slack run
command) will not work when you deploy your app in production (with the slack deploy
command). You'll need to create
any triggers again with the CLI.
If your workflow doesn't need any parameters mapped from the trigger, such as interactivity
, then you can create a trigger using the trigger create
command:
slack trigger create --workflow "#/workflows/your_workflow"
Use the --interactivity
flag to create a trigger that does provide the interactivity
parameter:
slack trigger create --workflow "#/workflows/your_workflow" --interactivity
You can, of course, still create a link trigger using a trigger file. The trigger file contains the payload you used to define your trigger.
Create a TypeScript trigger file within your app's folder with the following form:
import { Trigger} from "deno-slack-api/types.ts";
import { ExampleWorkflow } from "../workflows/example_workflow.ts";
const trigger : Trigger<typeof ExampleWorkflow.definition> = {
// your TypeScript payload
}
export default trigger;
Your TypeScript payload consists of the parameters needed for your own use case; below is an example payload:
{
type: "shortcut",
name: "Reverse a String",
description: "Starts the workflow to test reversing a string",
// The "test_reverse" below must be a valid callback_id in a workflow's definition
workflow: "#/workflows/test_reverse",
inputs: {
interactivity: {
value: "{{data.interactivity}}",
},
channel: {
value: "{{data.channel_id}}",
},
},
};
Once you have created a trigger file, use the trigger create
command to create the link trigger by pointing to a trigger file:
slack trigger create --trigger-def "path/to/trigger.ts"
If you have not used slack triggers create
to create a trigger prior to running slack run
, you will receive a prompt in the CLI to do so.
Your app needs to have the triggers:write
scope to use a trigger at runtime. Include the scope within your app's manifest.
The logic of a runtime trigger lies within a function's TypeScript code. Within your functions
folder, you'll have the functions that are the steps making up your workflow. Within this folder is where you can create a trigger within the relevant <function>.ts
file.
When you create a runtime trigger, you can leverage inputs
acquired from functions within the workflow. Provide the workflow definition to get additional typing for the workflow and inputs fields.
Create a link trigger at runtime using the client.workflows.triggers.create
method within the relevant function file.
const triggerResponse = await client.workflows.triggers.create<typeof ExampleWorkflow.definition>({
// your TypeScript payload
});
Your TypeScript payload consists of the parameters needed for your own use case. Here's a function file with an example TypeScript payload for a link trigger:
// functions/example_function.ts
import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";
import { ExampleWorkflow } from "../workflows/example_workflow.ts";
export const ExampleFunctionDefinition = DefineFunction({
callback_id: "example_function_def",
title: "Example function",
source_file: "functions/example_function.ts",
});
export default SlackFunction(
ExampleFunctionDefinition,
({ inputs, client }) => {
const triggerResponse = await client.workflows.triggers.create<typeof ExampleWorkflow.definition>({
type: "shortcut",
name: "My Trigger",
workflow: `#/workflows/${ExampleWorkflow.definition.callback_id}`,
inputs: {
input_name: {
value: "value",
}
}
});
// ...
Field | Description | Required |
---|---|---|
type |
The type of trigger: shortcut |
Required |
name |
The name of the trigger | Required |
workflow |
Path to workflow that the trigger initiates | Required |
description |
The description of the trigger | |
inputs |
The inputs provided to the workflow. See the inputs object below |
|
shortcut |
Contains button_text , if desired |
|
shortcut.button_text |
The text of the shortcut button |
inputs
object The inputs
of a trigger map to the inputs of a workflow. You can pass any value as an input.
There are also a specific set of input values that contain information about the trigger. Pass any of these values to provide trigger information to your workflows!
Field | Type | Description |
---|---|---|
data.action_id |
string | A unique identifier for the action that invoked the trigger. See Block Kit interactivity |
data.block_id |
string | A unique identifier for the block where the trigger was invoked. See Block Kit interactivity |
data.bookmark_id |
string | A unique identifier for the bookmark where the trigger was invoked |
data.channel_id |
string | A unique identifier for the channel where the trigger was invoked |
data.interactivity |
object | See Block Kit interactivity |
data.location |
string | Where the trigger was invoked. Can be message or bookmark |
data.message_ts |
string | A unique UNIX timestamp in seconds indicating when the trigger-invoking message was sent |
data.user |
object | An object containing a user_id and a secret that can be used to identify and validate the specific user who invoked the trigger |
data.user_id |
string | A unique identifier for the Slack user who invoked the trigger |
The following snippet shows a channel_id
input being set with a value of data.channel_id
, which is a unique identifier for the channel where the trigger was invoked.
...
inputs: {
channel_id: {
value: "{{data.channel_id}}"
}
},
...
The response will have a property called ok
. If true
, then the trigger was created, and the trigger
property will be populated.
Your response will include a trigger.id
; be sure to store it! You use that to update
or delete
the trigger if need be. Perhaps consider storing it in a datastore.
{
// If ok == true, the trigger was created
ok: true,
// The newly created trigger's details are here
trigger: {
// Your trigger's unique ID
id: "Ft12345",
// inputs will contain a summary of your inputs as defined in the trigger file
inputs: {},
// since this is a link trigger, `outputs` will automatically contain:
// {{event_timestamp}}: time when the workflow started
// {{data.user_id}}: The user ID of the person who invoked the trigger
// (by clicking the shortcut link or run button in Slack)
// {{data.channel_id}}: The channel where the shortcut was run
// {{data.interactivity}}: The trigger's interactivity context
outputs: {
"{{event_timestamp}}": {
type: "string",
name: "event_timestamp",
title: "Time when workflow started",
is_required: false,
description: "Time when workflow started"
},
"{{data.user_id}}": {
type: "slack#/types/user_id",
name: "user_id",
title: "Person who ran this shortcut",
is_required: true,
description: "Person who clicked the shortcut link or run button in Slack"
},
"{{data.channel_id}}": {
type: "slack#/types/channel_id",
name: "channel_id",
title: "Channel where the shortcut was run",
is_required: false,
description: "Channel where the shortcut was run, if available"
},
"{{data.interactivity}}": {
type: "slack#/types/interactivity",
name: "interactivity",
title: "Interactivity context",
is_required: true,
description: "Interactivity context",
is_hidden: true
}
},
// Trigger-specific information
date_created: 1661894315,
date_updated: 1661894315,
type: "shortcut",
name: "Submit a ticket to our work management system",
description: "",
// The shortcut URL that will activate this trigger and invoke the underlying workflow
shortcut_url: "https://slack.com/shortcuts/Ft12345/caef7d773d611ddd1da81fd85de08a78",
// Details about the workflow associated with this trigger
workflow: {
id: "Fn1234567890",
callback_id: "handle_new_tickets_workflow",
title: "Handle new tickets",
description: "Handles a new ticket and updates the submitting user",
type: "workflow",
// Any workflow inputs will be included here
input_parameters: [],
// Any of the workflow's outputs will be included here
output_parameters: [],
app_id: "A1234567890",
// App-specific details
app: {
id: "A1234567890",
name: "ticket-management-app",
icons: [Object],
is_workflow_app: false
},
date_created: 1661889787,
date_updated: 1661894304,
date_deleted: 0,
workflow_id: "Wf01234567890"
}
}
}
A newly created trigger is accessible to anyone inside the workspace by default. You can manage who can access the trigger using the access
Slack CLI command.
Required Flag | Description | Example Argument |
---|---|---|
--grant |
A switch to grant access | |
--trigger-id |
The trigger_id of the desired trigger |
Ft123ABC |
Set one of the following flags to grant access to different groups. If no flag is selected you will be prompted to select a group within the Slack CLI.
Flag | Description | Example Argument |
---|---|---|
--app-collaborators |
A switch to grant access to all app collaborators | |
--channels |
The channel IDs of channels to be granted access | C123ABC, C456DEF |
--everyone |
A switch to grant access to all workspace members | |
--organizations |
The enterprise IDs of organizations to be granted access | E123ABC, E456DEF |
--users |
The user ID of users to be granted access | U123ABC, U456DEF |
--workspaces |
The team IDs of workspaces to be granted access | T123ABC, T456DEF |
You can combine types of named entities (channels, organizations, users, and workspaces) in a single command. For example, the following command grants access to the trigger FtABC123
for channel C123ABC
, organization E123ABC
, user U123ABC
and workspace T123ABC
:
slack trigger access --trigger-id Ft123ABC --channels C123ABC --organizations E123ABC --users U123ABC --workspaces T123ABC --grant
Required Flag | Description | Example Argument |
---|---|---|
--revoke |
A switch to revoke access | |
--trigger-id |
The trigger_id of the desired trigger |
Ft123ABC |
Set one of the following flags to revoke access to different groups. If no flag is selected you will be prompted to select a group within the Slack CLI.
Flag | Description | Example Argument |
---|---|---|
--channels |
The channel IDs of channels whose access will be revoked | C123ABC, C456DEF |
--organizations |
The enterprise IDs of organizations whose access will be revoked | E123ABC, E456DEF |
--users |
The user IDs of users whose access will be revoked | U123ABC, U456DEF |
--workspaces |
The team IDs of workspaces whose access will be revoked | T123ABC, T456DEF |
The following example command revokes access to the trigger FtABC123
for users U123ABC
and U456DEF
and channels C123ABC
and C456DEF
.
slack trigger access --trigger-id FtABC123 --users U123ABC, U456DEF --channels C123ABC, C456DEF --revoke
Make an update to a pre-existing trigger with the CLI by using the slack trigger update
command. Provide the same payload you used to create the trigger in its entirety, in addition to the trigger ID.
slack trigger update --trigger-id Ft123ABC --trigger-def "path/to/trigger.ts"
You can update a runtime trigger, but the trigger must be updated in its entirety. Use the same structure as client.workflows.triggers.create()
but for client.workflows.triggers.update
with the additional trigger_id
parameter.
const triggerId = "FtABC123";
const response = await client.workflows.triggers.update<typeof ExampleWorkflow.definition>({
trigger_id: triggerId,
type: "<specific-trigger-type>",
name: "My trigger",
workflow: "#/workflows/myworkflow",
inputs: {
input_name: {
value: "value",
}
}
});
// Error handling example in your custom function
if (response.error) {
const error = `Failed to update a trigger (id: ${triggerId}) due to ${repsonse.error}`;
return { error };
}
You can delete a trigger with the slack trigger delete
command.
slack trigger delete --trigger-id FtABC123
Deleting a runtime trigger deletes that specific trigger created in one instance of the workflow. This means that you'll need to have stored the trigger_id
created for that instance. Your app will continue to be able to create triggers until you remove the relevant code.
You can delete a runtime trigger by using client.workflows.triggers.delete()
.
const response = await client.workflows.triggers.delete({
trigger_id: "FtABC123"
});
// Error handling example in your custom function
if (response.error) {
const error = `Failed to delete a trigger due to ${response.error}`;
return { error };
}