0
# Event Listeners & Request Handling
1
2
Decorator-based event handling for all Slack event types including messages, slash commands, interactive components, shortcuts, and view submissions. Supports event filtering, custom matchers, and argument injection.
3
4
## Capabilities
5
6
### Message Events
7
8
Listen for message events in channels, direct messages, and threads.
9
10
```python { .api }
11
def message(self, keyword=None, *matchers):
12
"""
13
Listen for message events.
14
15
Args:
16
keyword (str, optional): Text pattern to match in messages
17
*matchers: Additional listener matcher instances
18
19
Returns:
20
Decorator function for message handlers
21
"""
22
23
# Usage examples:
24
@app.message("hello") # Match messages containing "hello"
25
@app.message(re.compile(r"hi")) # Match with regex
26
@app.message() # Match all messages
27
28
def handle_message(message, say, client, logger):
29
"""
30
Message handler function.
31
32
Args:
33
message (dict): Message event data
34
say (callable): Function to send message to same channel
35
client (WebClient): Slack API client
36
logger (Logger): App logger instance
37
"""
38
```
39
40
### Slash Commands
41
42
Handle slash command invocations.
43
44
```python { .api }
45
def command(self, command, *matchers):
46
"""
47
Listen for slash command events.
48
49
Args:
50
command (str): Command name (e.g., "/weather", "/help")
51
*matchers: Additional listener matcher instances
52
53
Returns:
54
Decorator function for command handlers
55
"""
56
57
# Usage:
58
@app.command("/weather")
59
def handle_weather_command(ack, respond, command, logger):
60
"""
61
Command handler function.
62
63
Args:
64
ack (callable): Function to acknowledge the command (required)
65
respond (callable): Function to send response to user
66
command (dict): Command payload data
67
logger (Logger): App logger instance
68
"""
69
ack() # Must acknowledge within 3 seconds
70
location = command.get('text', 'San Francisco')
71
respond(f"Weather in {location}: Sunny ☀️")
72
```
73
74
### Generic Events
75
76
Listen for any Slack event type from the Events API.
77
78
```python { .api }
79
def event(self, event_type, *matchers):
80
"""
81
Listen for Events API events.
82
83
Args:
84
event_type (str): Slack event type (e.g., "app_mention", "team_join")
85
*matchers: Additional listener matcher instances
86
87
Returns:
88
Decorator function for event handlers
89
"""
90
91
# Usage examples:
92
@app.event("app_mention")
93
@app.event("team_join")
94
@app.event("reaction_added")
95
96
def handle_app_mention(event, say, client):
97
"""
98
Event handler function.
99
100
Args:
101
event (dict): Event data from Slack
102
say (callable): Function to send message to event channel
103
client (WebClient): Slack API client
104
"""
105
```
106
107
### Interactive Component Actions
108
109
Handle clicks on buttons, select menus, and other interactive components.
110
111
```python { .api }
112
def action(self, action_id, *matchers):
113
"""
114
Listen for interactive component actions.
115
116
Args:
117
action_id (str): Action ID of the interactive component
118
*matchers: Additional listener matcher instances
119
120
Returns:
121
Decorator function for action handlers
122
"""
123
124
def block_action(self, action_id, *matchers):
125
"""
126
Listen for Block Kit element actions (alias for action).
127
128
Args:
129
action_id (str): Action ID of the block element
130
*matchers: Additional listener matcher instances
131
"""
132
133
def attachment_action(self, callback_id, *matchers):
134
"""
135
Listen for legacy attachment actions.
136
137
Args:
138
callback_id (str): Callback ID of the attachment action
139
*matchers: Additional listener matcher instances
140
"""
141
142
# Usage:
143
@app.action("approve_button")
144
@app.action("user_select")
145
@app.block_action("priority_select")
146
147
def handle_button_click(ack, body, respond, client):
148
"""
149
Action handler function.
150
151
Args:
152
ack (callable): Function to acknowledge the action (required)
153
body (dict): Full request body
154
respond (callable): Function to update/respond to the interaction
155
client (WebClient): Slack API client
156
"""
157
ack() # Must acknowledge within 3 seconds
158
```
159
160
### Shortcuts
161
162
Handle global shortcuts and message shortcuts.
163
164
```python { .api }
165
def shortcut(self, callback_id, *matchers):
166
"""
167
Listen for shortcuts (both global and message shortcuts).
168
169
Args:
170
callback_id (str): Callback ID of the shortcut
171
*matchers: Additional listener matcher instances
172
"""
173
174
def global_shortcut(self, callback_id, *matchers):
175
"""
176
Listen specifically for global shortcuts.
177
178
Args:
179
callback_id (str): Callback ID of the global shortcut
180
*matchers: Additional listener matcher instances
181
"""
182
183
def message_shortcut(self, callback_id, *matchers):
184
"""
185
Listen specifically for message shortcuts.
186
187
Args:
188
callback_id (str): Callback ID of the message shortcut
189
*matchers: Additional listener matcher instances
190
"""
191
192
# Usage:
193
@app.global_shortcut("create_task")
194
@app.message_shortcut("save_message")
195
196
def handle_shortcut(ack, shortcut, client):
197
"""
198
Shortcut handler function.
199
200
Args:
201
ack (callable): Function to acknowledge the shortcut
202
shortcut (dict): Shortcut payload data
203
client (WebClient): Slack API client
204
"""
205
```
206
207
### Modal Views
208
209
Handle modal view submissions, closures, and interactions.
210
211
```python { .api }
212
def view(self, callback_id, *matchers):
213
"""
214
Listen for view events (submissions and closures).
215
216
Args:
217
callback_id (str): Callback ID of the view
218
*matchers: Additional listener matcher instances
219
"""
220
221
def view_submission(self, callback_id, *matchers):
222
"""
223
Listen specifically for view submissions.
224
225
Args:
226
callback_id (str): Callback ID of the view
227
*matchers: Additional listener matcher instances
228
"""
229
230
def view_closed(self, callback_id, *matchers):
231
"""
232
Listen specifically for view closures.
233
234
Args:
235
callback_id (str): Callback ID of the view
236
*matchers: Additional listener matcher instances
237
"""
238
239
# Usage:
240
@app.view_submission("task_modal")
241
@app.view_closed("survey_modal")
242
243
def handle_view_submission(ack, body, view, client):
244
"""
245
View handler function.
246
247
Args:
248
ack (callable): Function to acknowledge the submission
249
body (dict): Full request body
250
view (dict): View payload data
251
client (WebClient): Slack API client
252
"""
253
```
254
255
### Options Loading
256
257
Handle dynamic option loading for select menus.
258
259
```python { .api }
260
def options(self, action_id, *matchers):
261
"""
262
Listen for options loading requests.
263
264
Args:
265
action_id (str): Action ID of the select menu
266
*matchers: Additional listener matcher instances
267
"""
268
269
def block_suggestion(self, action_id, *matchers):
270
"""
271
Listen for block element suggestions (alias for options).
272
273
Args:
274
action_id (str): Action ID of the block element
275
*matchers: Additional listener matcher instances
276
"""
277
278
# Usage:
279
@app.options("user_select")
280
def load_user_options(ack, options, client):
281
"""
282
Options handler function.
283
284
Args:
285
ack (callable): Function to acknowledge with options
286
options (dict): Options request data
287
client (WebClient): Slack API client
288
"""
289
# Return options to populate the select menu
290
ack(options=[
291
{"text": {"type": "plain_text", "text": "Option 1"}, "value": "option1"},
292
{"text": {"type": "plain_text", "text": "Option 2"}, "value": "option2"}
293
])
294
```
295
296
### Legacy Dialog Support
297
298
Handle legacy dialog interactions (deprecated, use modals instead).
299
300
```python { .api }
301
def dialog_submission(self, callback_id, *matchers):
302
"""
303
Listen for dialog submissions (legacy).
304
305
Args:
306
callback_id (str): Callback ID of the dialog
307
*matchers: Additional listener matcher instances
308
"""
309
310
def dialog_cancellation(self, callback_id, *matchers):
311
"""
312
Listen for dialog cancellations (legacy).
313
314
Args:
315
callback_id (str): Callback ID of the dialog
316
*matchers: Additional listener matcher instances
317
"""
318
319
def dialog_suggestion(self, action_id, *matchers):
320
"""
321
Listen for dialog option suggestions (legacy).
322
323
Args:
324
action_id (str): Action ID of the dialog element
325
*matchers: Additional listener matcher instances
326
"""
327
```
328
329
### Custom Functions
330
331
Handle custom function calls (Slack platform functions).
332
333
```python { .api }
334
def function(self, callback_id, *matchers):
335
"""
336
Listen for custom function calls.
337
338
Args:
339
callback_id (str): Function callback ID
340
*matchers: Additional listener matcher instances
341
"""
342
343
# Usage:
344
@app.function("process_data")
345
def handle_function_call(ack, inputs, complete, fail, logger):
346
"""
347
Function handler.
348
349
Args:
350
ack (callable): Function to acknowledge the call
351
inputs (dict): Function input parameters
352
complete (callable): Function to mark completion with outputs
353
fail (callable): Function to mark failure with error
354
logger (Logger): App logger instance
355
"""
356
```
357
358
### Workflow Steps
359
360
Handle workflow step interactions.
361
362
```python { .api }
363
def step(self, step):
364
"""
365
Add a workflow step to the app.
366
367
Args:
368
step: WorkflowStep instance
369
"""
370
371
# Usage with WorkflowStep:
372
from slack_bolt.workflows.step import WorkflowStep
373
374
def edit_step(ack, step, configure):
375
ack()
376
configure(blocks=[...]) # Configure step UI
377
378
def execute_step(step, complete, fail):
379
# Step execution logic
380
complete(outputs={"result": "success"})
381
382
ws = WorkflowStep(
383
callback_id="my_step",
384
edit=edit_step,
385
save=lambda ack, view: ack(),
386
execute=execute_step
387
)
388
389
app.step(ws)
390
```
391
392
## Listener Matchers
393
394
### Built-in Matchers
395
396
Custom matching logic for fine-grained event filtering:
397
398
```python { .api }
399
from slack_bolt.listener_matcher import CustomListenerMatcher
400
401
def custom_matcher(body):
402
"""
403
Custom matcher function.
404
405
Args:
406
body (dict): Request body
407
408
Returns:
409
bool: True if listener should handle this request
410
"""
411
return body.get("event", {}).get("channel_type") == "im"
412
413
# Usage:
414
@app.message(CustomListenerMatcher(custom_matcher))
415
def handle_dm_only(message, say):
416
say("This only responds to direct messages!")
417
```
418
419
### Combining Matchers
420
421
Combine multiple matchers for complex filtering:
422
423
```python
424
@app.message("hello", CustomListenerMatcher(lambda body: not body.get("event", {}).get("bot_id")))
425
def handle_human_hello(message, say):
426
say("Hello, human!")
427
```
428
429
## Argument Injection
430
431
### Available Arguments
432
433
All listener functions support argument injection with these available parameters:
434
435
```python { .api }
436
class Args:
437
"""Available argument names for dependency injection in listeners."""
438
439
# Core objects
440
logger: Logger
441
client: WebClient
442
context: BoltContext
443
body: dict
444
payload: dict
445
446
# Utility functions
447
ack: Ack
448
say: Say
449
respond: Respond
450
complete: Complete
451
fail: Fail
452
453
# Event-specific data
454
event: dict
455
message: dict
456
command: dict
457
action: dict
458
shortcut: dict
459
view: dict
460
options: dict
461
462
# Request metadata
463
request: BoltRequest
464
response: BoltResponse
465
466
# Multi-workspace data
467
enterprise_id: str
468
team_id: str
469
user_id: str
470
channel_id: str
471
472
# AI Assistant utilities
473
set_status: SetStatus
474
set_title: SetTitle
475
set_suggested_prompts: SetSuggestedPrompts
476
save_thread_context: SaveThreadContext
477
```
478
479
### Function Signature Examples
480
481
Listeners can use any combination of available arguments:
482
483
```python
484
# Minimal signature
485
@app.message("hello")
486
def simple_handler(say):
487
say("Hello!")
488
489
# Full signature with all common arguments
490
@app.command("/complex")
491
def complex_handler(ack, body, command, respond, client, logger, context):
492
ack()
493
logger.info(f"Command received: {command}")
494
# Complex logic here...
495
496
# Event-specific arguments
497
@app.event("app_mention")
498
def mention_handler(event, say, user_id, channel_id):
499
say(f"Thanks for the mention in <#{channel_id}>, <@{user_id}>!")
500
```
501
502
## Usage Examples
503
504
### Message Pattern Matching
505
506
```python
507
import re
508
509
# Exact text match
510
@app.message("help")
511
def show_help(say):
512
say("Here's how to use this bot...")
513
514
# Regex pattern
515
@app.message(re.compile(r"weather in (\w+)"))
516
def weather_query(message, say):
517
city = re.search(r"weather in (\w+)", message['text']).group(1)
518
say(f"The weather in {city} is sunny!")
519
520
# Multiple patterns
521
@app.message("hello")
522
@app.message("hi")
523
@app.message("hey")
524
def greet_user(message, say):
525
say(f"Hello <@{message['user']}>!")
526
```
527
528
### Command with Sub-commands
529
530
```python
531
@app.command("/todo")
532
def todo_command(ack, respond, command):
533
ack()
534
535
text = command.get('text', '').strip()
536
parts = text.split(' ', 1)
537
subcommand = parts[0].lower() if parts else 'help'
538
539
if subcommand == 'add':
540
task = parts[1] if len(parts) > 1 else ''
541
respond(f"Added task: {task}")
542
elif subcommand == 'list':
543
respond("Here are your tasks: ...")
544
else:
545
respond("Usage: /todo [add|list] [task]")
546
```
547
548
### Modal Workflow
549
550
```python
551
@app.action("open_modal")
552
def open_modal(ack, body, client):
553
ack()
554
555
client.views_open(
556
trigger_id=body["trigger_id"],
557
view={
558
"type": "modal",
559
"callback_id": "task_modal",
560
"title": {"type": "plain_text", "text": "Create Task"},
561
"blocks": [
562
{
563
"type": "input",
564
"block_id": "task_input",
565
"element": {
566
"type": "plain_text_input",
567
"action_id": "task_text"
568
},
569
"label": {"type": "plain_text", "text": "Task Description"}
570
}
571
],
572
"submit": {"type": "plain_text", "text": "Create"}
573
}
574
)
575
576
@app.view_submission("task_modal")
577
def handle_task_submission(ack, body, view, logger):
578
# Extract form data
579
task_text = view["state"]["values"]["task_input"]["task_text"]["value"]
580
581
# Process the task...
582
logger.info(f"Creating task: {task_text}")
583
584
# Acknowledge and close modal
585
ack()
586
```
587
588
## Related Topics
589
590
- [Context Objects & Utilities](./context-and-utilities.md) - Details on say, respond, ack, and other utilities
591
- [OAuth & Multi-Workspace Installation](./oauth-and-installation.md) - Multi-workspace event handling patterns