This page contains all the concepts that are necessary to allow you to use the next-gen Slack features in Python.
This page contains all the concepts that are necessary to allow you to use the next-gen Slack features in Python.
Your project should contain a manifest.json
file that defines your app’s manifest. This is where you’ll configure your application name and scopes, declare the functions your app will use, and more.
Refer to the App Manifest and Manifest Property documentation to learn
about the available manifest configurations.
Notably, the App Manifest informs Slack of the definitions for:
manifest.json
is located at the top level of our example projects, along with a triggers
folder containing
*_trigger.json
files that define the triggers
for your app.
. ├── ... ├── manifest.json # app manifest definition ├── triggers # folder with trigger files │ ├── sample_trigger.json # trigger definition │ └── ... └── ...
Syntax and formatting checks are required to efficiently edit your manifest.json
. Multiple IDEs are able to support
this, namely: Visual Studio Code, Pycharm, Sublime Text (via LSP-json) and many more.
To get manifest prediction & validation in your IDE, include the following line in your manifest.json
file:
1
2
3
4
{
"$schema": "https://raw.githubusercontent.com/slackapi/manifest-schema/main/manifest.schema.json",
...
}
Using the Slack CLI you can validate your manifest.json
against the Slack API with:
1
slack manifest validate
Refer to our template project to view a full version of manifest.json
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"$schema": "https://raw.githubusercontent.com/slackapi/manifest-schema/main/manifest.schema.json",
"_metadata": {
"major_version": 2,
},
"display_information": {
"name": "Bolt Template App TEST"
},
"features": {
"app_home": {
"home_tab_enabled": false,
},
"bot_user": {
"display_name": "Bolt Template App TEST",
"always_online": false
}
},
"oauth_config": {
"scopes": {
"bot": [
"chat:write",
]
}
},
"settings": {
"socket_mode_enabled": true,
},
"functions": {},
"types": {},
"workflows": {},
"outgoing_domains": []
}
parameters |
object | |
---|---|---|
properties |
properties | defines the properties |
required |
list[string] | defines the properties required by the function |
properties |
dictionary | |
---|---|---|
key |
string | defines the property name |
value |
property | defines the property |
property |
object | |
---|---|---|
type |
string | defines the property type |
description |
string | defines the property description |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"$comment": "sample parameters object"
"*_parameters":{
"properties": {
"property_0_name": {
"type": "string",
"description": "this is my first property"
},
"property_1_name": {
"type": "integer",
"description": "this is my second property"
}
},
"required": [
"property_0_name"
]
}
Your app can invoke Functions defined and created by you (Custom Functions). In order for this to work, Slack must know they exist. Define them in your App Manifest also known as manifest.json
in your project. The next time you slack run
your app will inform Slack they exist.
functions |
dictionary | |
---|---|---|
key |
string | defines the function's callback_id
|
value |
function | defines the function |
function |
object | |
---|---|---|
title |
string | defines the title |
description |
string | defines the description |
input_parameters |
parameters | defines the inputs |
output_parameters |
parameters | defines the outputs |
Refer to our template project to view a full version of manifest.json
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"functions": {
"sample_function": {
"title": "Sample function",
"description": "A sample function",
"input_parameters": {
"properties": {
"message": {
"type": "string",
"description": "Message to be posted"
}
},
"required": [
"message"
]
},
"output_parameters": {
"properties": {
"updatedMsg": {
"type": "string",
"description": "Updated message to be posted"
}
},
"required": [
"updatedMsg"
]
}
}
}
Your app can use Functions by referencing them in Workflows. Your Custom Functions and the Built-in Functions can be used as steps in Workflow definitions.
Workflows are invoked by Triggers. You will need to set up a Trigger in order to use your defined workflows. Triggers, Workflows, and Functions work together in the following way:
Trigger → Workflow → Workflow Step → Function
Your App Manifest, found at manifest.json
, is where you will define your workflows.
workflows |
dictionary | |
---|---|---|
key |
string | defines the workflow's id
|
value |
workflow | defines the function |
workflow |
object | |
---|---|---|
title |
string | defines the title |
description |
string | defines the description |
input_parameters |
parameters | defines the inputs |
steps |
list[parameters] | defines the steps |
step |
object | |
---|---|---|
id |
string | defines the order of the steps |
function_id |
string | identifies the function to evoke |
inputs |
dict[string:string] | defines the inputs to provide to the function |
Refer to our template project to view a full version of manifest.json
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"workflows": {
"sample_workflow": {
"title": "Sample workflow",
"description": "A sample workflow",
"input_parameters": {
"properties": {
"channel": {
"type": "slack#/types/channel_id"
}
},
"required": [
"channel"
]
},
"steps": [
{
"id": "0",
"function_id": "#/functions/sample_function",
"inputs": {
"message": "{{inputs.channel}}"
}
},
{
"id": "1",
"function_id": "slack#/functions/send_message",
"inputs": {
"channel_id": "{{inputs.channel}}",
"message": "{{steps.0.updatedMsg}}"
}
}
]
}
}
Slack provides built-in functions that can be used by a Workflow to accomplish simple tasks. You can add these functions to your workflow steps in order to use them.
Refer to the built-in functions document to learn about the available built-in functions.
1
2
3
4
5
6
7
8
9
10
11
"$comment": "A step to post the user name to a channel"
"steps": [
{
"id": "0",
"function_id": "slack#/functions/send_message",
"inputs": {
"channel_id": "{{inputs.channel}}",
"message": "{{inputs.user_name}}"
}
}
]
Your app can use the function()
method to listen to incoming function requests. The method requires a function callback_id
of type str
. This callback_id
must also be defined in your Function definition. Functions must eventually be completed with the complete()
function to inform Slack that your app has processed the function request. complete()
requires one of two keyword arguments: outputs
or error
. There are two ways to complete a Function with complete()
:
outputs
of type dict
completes your function successfully and provides a dictionary containing the outputs of your function as defined in the app’s manifest.error
of type str
completes your function unsuccessfully and provides a message containing information regarding why your function was not successful.Refer to the module document to learn the available listener arguments.
1
2
3
4
5
6
7
8
9
10
11
12
13
# The sample function simply outputs an input
@app.function("sample_function")
def sample_func(event: dict, complete: Complete):
try:
message = event["inputs"]["message"]
complete(
outputs={
"updatedMsg": f":wave: You submitted the following message: \n\n>{message}"
}
)
except Exception as e:
complete(error=f"Cannot submit the message: {e}")
raise e
The function()
method returns a SlackFunction
decorator object. This object can be used by your app to set up interactive listeners such as actions and views. These listeners listen to events created during the handling of your function
event. Additionally, they will only be called when a user interacts with a block element that has the following attributes:
function
event.action_id
matches the interactive listeners action_id
.These listeners behave similarly to the ones assigned directly to your app. The notable difference is that complete()
must be called once your function is completed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Your listener will be called when your function "sample_function" is triggered from a workflow
# When triggered a message containing a button with an action_id "approve_button" is posted
@app.function("sample_function")
def sample_func(event: dict, complete: Complete):
try:
client.chat_postMessage(
channel="a-channel-id",
text="A new button appears",
blocks=[
{
"type": "actions",
"block_id": "approve-button",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click",
},
"action_id": "sample_action",
"style": "primary",
},
],
},
],
)
except Exception as e:
complete(error=f"Cannot post the message: {e}")
raise e
# Your listener will be called when a block element
# - Created by your "sample_func"
# - With the action_id "sample_action"
# is triggered
@sample_func.action("sample_action")
def update_message(ack, body, client, complete):
try:
ack()
if "container" in body and "message_ts" in body["container"]:
client.reactions_add(
name="white_check_mark",
channel=body["channel"]["id"],
timestamp=body["container"]["message_ts"],
)
complete()
except Exception as e:
logger.error(e)
complete(error=f"Cannot react to message: {e}")
raise e