0
# Commands & Interactions
1
2
Create slash commands, context menus, and handle all interaction types with modern Discord bot functionality.
3
4
## Slash Commands
5
6
### Basic Slash Command
7
8
```python
9
from interactions import slash_command, SlashContext
10
11
@slash_command(name="hello", description="Say hello to someone!")
12
async def hello_command(ctx: SlashContext):
13
await ctx.send("Hello World!")
14
```
15
16
### Slash Command with Options
17
18
```python
19
from interactions import slash_command, slash_option, SlashContext, OptionType
20
21
@slash_command(name="greet", description="Greet a user")
22
@slash_option(
23
name="user",
24
description="User to greet",
25
required=True,
26
opt_type=OptionType.USER
27
)
28
@slash_option(
29
name="message",
30
description="Custom message",
31
required=False,
32
opt_type=OptionType.STRING
33
)
34
async def greet_command(ctx: SlashContext, user: Member, message: str = "Hello"):
35
await ctx.send(f"{message}, {user.mention}!")
36
```
37
38
### Type-Specific Option Decorators
39
40
```python
41
from interactions import (
42
slash_command, slash_str_option, slash_int_option,
43
slash_bool_option, slash_user_option, slash_channel_option,
44
slash_role_option, slash_mentionable_option, slash_attachment_option,
45
slash_float_option, SlashContext
46
)
47
48
@slash_command(name="complex", description="Complex command with multiple option types")
49
@slash_str_option(name="text", description="Text input", required=True, max_length=100)
50
@slash_int_option(name="number", description="Number input", min_value=1, max_value=100)
51
@slash_bool_option(name="flag", description="Boolean flag")
52
@slash_user_option(name="target", description="Target user")
53
@slash_channel_option(name="destination", description="Target channel")
54
@slash_role_option(name="role", description="Role to assign")
55
@slash_attachment_option(name="file", description="File to process")
56
@slash_float_option(name="rating", description="Rating", min_value=0.0, max_value=5.0)
57
async def complex_command(
58
ctx: SlashContext,
59
text: str,
60
number: int = 50,
61
flag: bool = False,
62
target: Member = None,
63
destination: GuildChannel = None,
64
role: Role = None,
65
file: Attachment = None,
66
rating: float = 0.0
67
):
68
await ctx.send(f"Processing: {text} with number {number}")
69
```
70
71
### Slash Command Choices
72
73
```python
74
from interactions import slash_command, slash_option, SlashCommandChoice, SlashContext, OptionType
75
76
@slash_command(name="color", description="Choose a color")
77
@slash_option(
78
name="color_choice",
79
description="Pick your favorite color",
80
required=True,
81
opt_type=OptionType.STRING,
82
choices=[
83
SlashCommandChoice(name="Red", value="red"),
84
SlashCommandChoice(name="Blue", value="blue"),
85
SlashCommandChoice(name="Green", value="green"),
86
SlashCommandChoice(name="Yellow", value="yellow")
87
]
88
)
89
async def color_command(ctx: SlashContext, color_choice: str):
90
await ctx.send(f"You chose: {color_choice}")
91
```
92
93
### Subcommands
94
95
```python
96
from interactions import SlashCommand, subcommand, SlashContext
97
98
# Create base command group
99
base_cmd = SlashCommand(name="admin", description="Admin commands", group_name="administration")
100
101
@subcommand(base=base_cmd, name="ban", description="Ban a user")
102
@slash_option(name="user", description="User to ban", required=True, opt_type=OptionType.USER)
103
@slash_option(name="reason", description="Ban reason", required=False, opt_type=OptionType.STRING)
104
async def admin_ban(ctx: SlashContext, user: Member, reason: str = "No reason provided"):
105
await user.ban(reason=reason)
106
await ctx.send(f"Banned {user.mention} for: {reason}")
107
108
@subcommand(base=base_cmd, name="kick", description="Kick a user")
109
@slash_option(name="user", description="User to kick", required=True, opt_type=OptionType.USER)
110
async def admin_kick(ctx: SlashContext, user: Member):
111
await user.kick()
112
await ctx.send(f"Kicked {user.mention}")
113
```
114
115
### Slash Command Permissions
116
117
```python
118
from interactions import slash_command, slash_default_member_permission, Permissions
119
120
@slash_command(name="mod_only", description="Moderator only command")
121
@slash_default_member_permission(Permissions.MANAGE_MESSAGES)
122
async def mod_only_command(ctx: SlashContext):
123
await ctx.send("You have moderation permissions!")
124
```
125
126
## Context Menu Commands
127
128
### User Context Menu
129
130
```python
131
from interactions import context_menu, ContextMenuContext, CommandType
132
133
@context_menu(name="Get User Info", context_type=CommandType.USER)
134
async def user_info_menu(ctx: ContextMenuContext):
135
user = ctx.target # The user that was right-clicked
136
embed = Embed(
137
title=f"User Info: {user.username}",
138
description=f"ID: {user.id}\nCreated: {user.created_at}",
139
color=0x00ff00
140
)
141
await ctx.send(embed=embed, ephemeral=True)
142
```
143
144
### Message Context Menu
145
146
```python
147
from interactions import context_menu, ContextMenuContext, CommandType
148
149
@context_menu(name="Quote Message", context_type=CommandType.MESSAGE)
150
async def quote_menu(ctx: ContextMenuContext):
151
message = ctx.target # The message that was right-clicked
152
quote_embed = Embed(
153
description=message.content,
154
color=0x0099ff
155
)
156
quote_embed.set_author(
157
name=message.author.username,
158
icon_url=message.author.avatar.url if message.author.avatar else None
159
)
160
await ctx.send(f"Quote from {message.author.mention}:", embed=quote_embed)
161
```
162
163
### Generic Context Menu
164
165
```python
166
from interactions import context_menu, CommandType, ContextMenuContext
167
168
@context_menu(name="Custom Action", context_type=CommandType.USER)
169
async def custom_menu(ctx: ContextMenuContext):
170
if ctx.context_type == CommandType.USER:
171
target = ctx.target
172
await ctx.send(f"Action performed on user: {target.username}")
173
elif ctx.context_type == CommandType.MESSAGE:
174
target = ctx.target
175
await ctx.send(f"Action performed on message from: {target.author.username}")
176
```
177
178
## Command Context Classes
179
180
### Base Context
181
182
```python
183
class BaseContext:
184
bot: Client
185
author: Union[User, Member]
186
channel: MessageableChannel
187
guild: Optional[Guild]
188
message: Optional[Message]
189
created_at: datetime
190
```
191
192
### Interaction Context
193
194
```python
195
class InteractionContext(BaseContext):
196
interaction_id: Snowflake
197
token: str
198
application_id: Snowflake
199
type: InteractionType
200
data: dict
201
locale: str
202
guild_locale: Optional[str]
203
responded: bool
204
deferred: bool
205
ephemeral: bool
206
```
207
208
**Key Methods**:
209
- `send(content=None, **kwargs)` { .api } - Send response/followup
210
- `defer(ephemeral=False)` { .api } - Defer the interaction
211
- `edit(content=None, **kwargs)` { .api } - Edit original response
212
- `delete()` { .api } - Delete original response
213
- `followup(content=None, **kwargs)` { .api } - Send followup message
214
215
### Slash Context
216
217
```python
218
class SlashContext(InteractionContext):
219
command: SlashCommand
220
args: List[Any]
221
kwargs: Dict[str, Any]
222
options: List[dict]
223
focused_option: Optional[str] # For autocomplete
224
```
225
226
### Component Context
227
228
```python
229
class ComponentContext(InteractionContext):
230
component: BaseComponent
231
custom_id: str
232
component_type: ComponentType
233
values: List[str] # For select menus
234
```
235
236
### Modal Context
237
238
```python
239
class ModalContext(InteractionContext):
240
custom_id: str
241
components: List[dict]
242
values: Dict[str, str] # component_id -> value mapping
243
```
244
245
### Context Menu Context
246
247
```python
248
class ContextMenuContext(InteractionContext):
249
command_type: CommandType
250
target: Union[User, Member, Message]
251
target_id: Snowflake
252
```
253
254
**Properties**:
255
- `target_user` { .api } - Target user (if USER command)
256
- `target_message` { .api } - Target message (if MESSAGE command)
257
258
## Autocomplete
259
260
### Basic Autocomplete
261
262
```python
263
from interactions import slash_command, slash_option, AutocompleteContext, OptionType
264
265
@slash_command(name="search", description="Search for something")
266
@slash_option(
267
name="query",
268
description="Search query",
269
required=True,
270
opt_type=OptionType.STRING,
271
autocomplete=True
272
)
273
async def search_command(ctx: SlashContext, query: str):
274
await ctx.send(f"Searching for: {query}")
275
276
@search_command.autocomplete("query")
277
async def search_autocomplete(ctx: AutocompleteContext):
278
# Get user's current input
279
user_input = ctx.input_text
280
281
# Generate suggestions based on input
282
suggestions = [
283
{"name": f"Search: {user_input}", "value": user_input},
284
{"name": f"Advanced: {user_input}", "value": f"advanced:{user_input}"},
285
{"name": f"Exact: {user_input}", "value": f'"{user_input}"'}
286
]
287
288
# Return up to 25 suggestions
289
await ctx.send(suggestions[:25])
290
```
291
292
### Global Autocomplete
293
294
```python
295
from interactions import global_autocomplete, OptionType
296
297
@global_autocomplete("color")
298
async def color_autocomplete(ctx: AutocompleteContext):
299
"""Global autocomplete for any 'color' option"""
300
colors = ["red", "blue", "green", "yellow", "purple", "orange", "pink"]
301
user_input = ctx.input_text.lower()
302
303
# Filter colors based on user input
304
matching_colors = [c for c in colors if user_input in c.lower()]
305
306
suggestions = [{"name": color.title(), "value": color} for color in matching_colors]
307
await ctx.send(suggestions[:25])
308
```
309
310
## Response Types
311
312
### Basic Responses
313
314
```python
315
# Send simple message
316
await ctx.send("Hello World!")
317
318
# Send ephemeral message (only visible to user)
319
await ctx.send("Secret message!", ephemeral=True)
320
321
# Send with embed
322
embed = Embed(title="Title", description="Description", color=0x00ff00)
323
await ctx.send(embed=embed)
324
325
# Send with file
326
file = File("path/to/image.png")
327
await ctx.send("Here's an image:", file=file)
328
```
329
330
### Advanced Responses
331
332
```python
333
from interactions import Button, ActionRow, ButtonStyle
334
335
# Send with components
336
button = Button(
337
style=ButtonStyle.PRIMARY,
338
label="Click Me!",
339
custom_id="my_button"
340
)
341
action_row = ActionRow(button)
342
await ctx.send("Click the button below:", components=[action_row])
343
344
# Send with multiple embeds
345
embed1 = Embed(title="First", description="First embed")
346
embed2 = Embed(title="Second", description="Second embed")
347
await ctx.send(embeds=[embed1, embed2])
348
349
# Send with allowed mentions control
350
from interactions import AllowedMentions
351
mentions = AllowedMentions(users=False, roles=False, everyone=False)
352
await ctx.send("@everyone This won't ping!", allowed_mentions=mentions)
353
```
354
355
### Deferred Responses
356
357
```python
358
# Defer for long operations
359
@slash_command(name="slow", description="A slow command")
360
async def slow_command(ctx: SlashContext):
361
await ctx.defer() # Shows "Bot is thinking..."
362
363
# Do slow work here
364
await asyncio.sleep(5)
365
366
# Send the actual response
367
await ctx.send("Done with slow operation!")
368
369
# Defer ephemeral
370
@slash_command(name="secret_slow", description="A slow secret command")
371
async def secret_slow_command(ctx: SlashContext):
372
await ctx.defer(ephemeral=True)
373
374
# Do work...
375
await asyncio.sleep(3)
376
377
await ctx.send("Secret result!", ephemeral=True)
378
```
379
380
### Edit Responses
381
382
```python
383
@slash_command(name="countdown", description="Count down from 5")
384
async def countdown_command(ctx: SlashContext):
385
# Send initial response
386
await ctx.send("5...")
387
388
# Edit the response multiple times
389
for i in range(4, 0, -1):
390
await asyncio.sleep(1)
391
await ctx.edit(f"{i}...")
392
393
await asyncio.sleep(1)
394
await ctx.edit("🎉 Done!")
395
```
396
397
### Followup Messages
398
399
```python
400
@slash_command(name="multi", description="Send multiple messages")
401
async def multi_command(ctx: SlashContext):
402
# Initial response
403
await ctx.send("First message!")
404
405
# Additional messages via followup
406
await ctx.followup("Second message!")
407
await ctx.followup("Third message!", ephemeral=True)
408
409
# Followups return Message objects
410
msg = await ctx.followup("Fourth message - I can edit this!")
411
await asyncio.sleep(2)
412
await msg.edit("Edited the fourth message!")
413
```
414
415
## Command Classes
416
417
### Slash Command Class
418
419
```python
420
class SlashCommand:
421
name: str
422
description: str
423
options: List[SlashCommandOption]
424
callback: Callable
425
group_name: Optional[str]
426
sub_cmd_name: Optional[str]
427
dm_permission: bool
428
default_member_permissions: Optional[Permissions]
429
nsfw: bool
430
```
431
432
### Context Menu Class
433
434
```python
435
class ContextMenu:
436
name: str
437
type: CommandType
438
callback: Callable
439
dm_permission: bool
440
default_member_permissions: Optional[Permissions]
441
nsfw: bool
442
```
443
444
### Command Options
445
446
```python
447
class SlashCommandOption:
448
name: str
449
description: str
450
type: OptionType
451
required: bool
452
choices: Optional[List[SlashCommandChoice]]
453
options: Optional[List[SlashCommandOption]] # For subcommands
454
channel_types: Optional[List[ChannelType]]
455
min_value: Optional[Union[int, float]]
456
max_value: Optional[Union[int, float]]
457
min_length: Optional[int]
458
max_length: Optional[int]
459
autocomplete: bool
460
461
class SlashCommandChoice:
462
name: str
463
value: Union[str, int, float]
464
name_localizations: Optional[Dict[str, str]]
465
```
466
467
### Option Types
468
469
```python
470
from interactions import OptionType
471
472
OptionType.STRING # Text input
473
OptionType.INTEGER # Whole number
474
OptionType.BOOLEAN # True/False
475
OptionType.USER # Discord user
476
OptionType.CHANNEL # Discord channel
477
OptionType.ROLE # Discord role
478
OptionType.MENTIONABLE # User or role
479
OptionType.NUMBER # Decimal number
480
OptionType.ATTACHMENT # File attachment
481
```
482
483
## Advanced Features
484
485
### Command Localization
486
487
```python
488
from interactions import LocalizedName, LocalizedDesc
489
490
@slash_command(
491
name=LocalizedName(default="hello", **{"es-ES": "hola", "fr": "bonjour"}),
492
description=LocalizedDesc(default="Say hello", **{"es-ES": "Di hola", "fr": "Dire bonjour"})
493
)
494
async def localized_command(ctx: SlashContext):
495
await ctx.send("Hello! / ¡Hola! / Bonjour!")
496
```
497
498
### Command Synchronization
499
500
```python
501
# Check if commands need syncing
502
if interactions.sync_needed(bot.interactions):
503
await bot.sync_interactions()
504
505
# Convert commands to dict format
506
commands_dict = interactions.application_commands_to_dict(bot.interactions)
507
```
508
509
### Command Groups
510
511
```python
512
# Create command group
513
admin_group = SlashCommand(
514
name="admin",
515
description="Admin commands",
516
group_name="administration"
517
)
518
519
# Commands with same base form a group
520
@subcommand(base=admin_group, name="users", description="Manage users")
521
async def admin_users(ctx: SlashContext):
522
pass
523
524
@subcommand(base=admin_group, name="channels", description="Manage channels")
525
async def admin_channels(ctx: SlashContext):
526
pass
527
```