or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-configuration.mdcontext-and-utilities.mdevent-listeners.mdframework-integration.mdindex.mdoauth-and-installation.md

event-listeners.mddocs/

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