or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

app-commands.mdcommands-framework.mdcore-objects.mdevent-handling.mdindex.mduser-interface.mdutilities.mdvoice-audio.mdwebhooks.md

webhooks.mddocs/

0

# Webhooks

1

2

Discord webhook clients for sending messages without a bot presence. Discord.py provides both synchronous and asynchronous webhook implementations with support for embeds, files, thread management, and message editing.

3

4

## Capabilities

5

6

### Async Webhook Client

7

8

Asynchronous webhook client for sending messages with full Discord features.

9

10

```python { .api }

11

class Webhook:

12

"""

13

Asynchronous Discord webhook client.

14

"""

15

def __init__(self, url: str, *, session: Optional[aiohttp.ClientSession] = None): ...

16

17

# Webhook properties

18

id: int # Webhook ID

19

type: WebhookType # Webhook type

20

guild_id: Optional[int] # Guild ID if guild webhook

21

channel_id: Optional[int] # Channel ID if channel webhook

22

user: Optional[User] # User who created webhook

23

name: Optional[str] # Webhook name

24

avatar: Optional[str] # Webhook avatar hash

25

token: Optional[str] # Webhook token

26

application_id: Optional[int] # Application ID for application webhooks

27

source_guild: Optional[PartialWebhookGuild] # Source guild for follower webhooks

28

source_channel: Optional[PartialWebhookChannel] # Source channel for follower webhooks

29

url: str # Webhook URL

30

31

# Class methods for creation

32

@classmethod

33

def from_url(cls, url: str, *, session: Optional[aiohttp.ClientSession] = None) -> Webhook:

34

"""Create webhook from URL."""

35

36

@classmethod

37

async def from_state(

38

cls,

39

data: Dict[str, Any],

40

*,

41

session: Optional[aiohttp.ClientSession] = None

42

) -> Webhook:

43

"""Create webhook from Discord API data."""

44

45

# Message sending

46

async def send(

47

self,

48

content: Optional[str] = None,

49

*,

50

username: Optional[str] = None,

51

avatar_url: Optional[str] = None,

52

tts: bool = False,

53

ephemeral: bool = False,

54

file: Optional[File] = None,

55

files: Optional[List[File]] = None,

56

embed: Optional[Embed] = None,

57

embeds: Optional[List[Embed]] = None,

58

allowed_mentions: Optional[AllowedMentions] = None,

59

thread: Optional[Snowflake] = None,

60

thread_name: Optional[str] = None,

61

wait: bool = False,

62

suppress_embeds: bool = False

63

) -> Optional[WebhookMessage]:

64

"""

65

Send a message via webhook.

66

67

Parameters:

68

- content: Message content

69

- username: Override webhook username

70

- avatar_url: Override webhook avatar

71

- tts: Whether message is text-to-speech

72

- ephemeral: Whether message is ephemeral (interaction webhooks only)

73

- file: Single file to upload

74

- files: Multiple files to upload

75

- embed: Single embed to send

76

- embeds: Multiple embeds to send

77

- allowed_mentions: Mention settings

78

- thread: Thread to send message in

79

- thread_name: Create new thread with this name

80

- wait: Whether to wait for message confirmation

81

- suppress_embeds: Whether to suppress link embeds

82

83

Returns:

84

WebhookMessage if wait=True, None otherwise

85

"""

86

87

# Message management

88

async def fetch_message(self, id: int, *, thread: Optional[Snowflake] = None) -> WebhookMessage:

89

"""

90

Fetch a webhook message by ID.

91

92

Parameters:

93

- id: Message ID to fetch

94

- thread: Thread containing the message

95

96

Returns:

97

WebhookMessage object

98

"""

99

100

async def edit_message(

101

self,

102

message_id: int,

103

*,

104

content: Optional[str] = None,

105

embed: Optional[Embed] = None,

106

embeds: Optional[List[Embed]] = None,

107

file: Optional[File] = None,

108

files: Optional[List[File]] = None,

109

attachments: Optional[List[Attachment]] = None,

110

allowed_mentions: Optional[AllowedMentions] = None,

111

thread: Optional[Snowflake] = None

112

) -> WebhookMessage:

113

"""

114

Edit a webhook message.

115

116

Parameters:

117

- message_id: ID of message to edit

118

- content: New message content

119

- embed: New embed

120

- embeds: New embeds

121

- file: New file to upload

122

- files: New files to upload

123

- attachments: Attachments to keep

124

- allowed_mentions: Mention settings

125

- thread: Thread containing the message

126

127

Returns:

128

Edited WebhookMessage

129

"""

130

131

async def delete_message(self, message_id: int, *, thread: Optional[Snowflake] = None) -> None:

132

"""

133

Delete a webhook message.

134

135

Parameters:

136

- message_id: ID of message to delete

137

- thread: Thread containing the message

138

"""

139

140

# Webhook management

141

async def edit(

142

self,

143

*,

144

name: Optional[str] = None,

145

avatar: Optional[bytes] = None,

146

channel: Optional[TextChannel] = None,

147

reason: Optional[str] = None

148

) -> Webhook:

149

"""

150

Edit webhook properties.

151

152

Parameters:

153

- name: New webhook name

154

- avatar: New webhook avatar

155

- channel: New webhook channel

156

- reason: Reason for audit log

157

158

Returns:

159

Updated Webhook object

160

"""

161

162

async def delete(self, *, reason: Optional[str] = None) -> None:

163

"""

164

Delete the webhook.

165

166

Parameters:

167

- reason: Reason for audit log

168

"""

169

170

# Thread management

171

async def create_thread(

172

self,

173

*,

174

name: str,

175

message: Optional[WebhookMessage] = None,

176

auto_archive_duration: int = 1440,

177

rate_limit_per_user: Optional[int] = None,

178

reason: Optional[str] = None

179

) -> Thread:

180

"""

181

Create a thread via webhook.

182

183

Parameters:

184

- name: Thread name

185

- message: Message to start thread from

186

- auto_archive_duration: Auto-archive duration in minutes

187

- rate_limit_per_user: Slowmode delay in seconds

188

- reason: Reason for audit log

189

190

Returns:

191

Created Thread object

192

"""

193

194

class WebhookMessage:

195

"""

196

Represents a message sent by a webhook.

197

"""

198

def __init__(self, *, data: Dict[str, Any], state, webhook: Webhook): ...

199

200

# Message properties (similar to regular Message)

201

id: int # Message ID

202

webhook_id: int # Webhook ID

203

channel: PartialMessageable # Channel message was sent in

204

guild: Optional[Guild] # Guild if sent in guild channel

205

content: str # Message content

206

clean_content: str # Content with mentions resolved

207

created_at: datetime # Message creation timestamp

208

edited_at: Optional[datetime] # Last edit timestamp

209

tts: bool # Whether message is text-to-speech

210

mention_everyone: bool # Whether message mentions @everyone

211

mentions: List[User] # Mentioned users

212

channel_mentions: List[GuildChannel] # Mentioned channels

213

role_mentions: List[Role] # Mentioned roles

214

attachments: List[Attachment] # File attachments

215

embeds: List[Embed] # Rich embeds

216

reactions: List[Reaction] # Message reactions

217

pinned: bool # Whether message is pinned

218

type: MessageType # Message type

219

flags: MessageFlags # Message flags

220

thread: Optional[Thread] # Thread if message is in thread

221

components: List[Component] # UI components

222

223

# Message management

224

async def edit(

225

self,

226

*,

227

content: Optional[str] = None,

228

embed: Optional[Embed] = None,

229

embeds: Optional[List[Embed]] = None,

230

file: Optional[File] = None,

231

files: Optional[List[File]] = None,

232

attachments: Optional[List[Attachment]] = None,

233

allowed_mentions: Optional[AllowedMentions] = None

234

) -> WebhookMessage:

235

"""Edit the webhook message."""

236

237

async def delete(self, *, delay: Optional[float] = None) -> None:

238

"""Delete the webhook message."""

239

240

# Message interactions

241

async def add_reaction(self, emoji: Union[Emoji, Reaction, PartialEmoji, str]) -> None:

242

"""Add a reaction to the message."""

243

244

async def remove_reaction(self, emoji: Union[Emoji, Reaction, PartialEmoji, str], member: Member) -> None:

245

"""Remove a reaction from the message."""

246

247

async def clear_reactions(self) -> None:

248

"""Clear all reactions from the message."""

249

250

async def pin(self, *, reason: Optional[str] = None) -> None:

251

"""Pin the message."""

252

253

async def unpin(self, *, reason: Optional[str] = None) -> None:

254

"""Unpin the message."""

255

256

def to_reference(self) -> MessageReference:

257

"""Create a reference to this message for replies."""

258

259

class PartialWebhookGuild:

260

"""

261

Partial guild information from webhook data.

262

"""

263

def __init__(self, data: Dict[str, Any]): ...

264

265

id: int # Guild ID

266

name: str # Guild name

267

icon: Optional[str] # Guild icon hash

268

269

class PartialWebhookChannel:

270

"""

271

Partial channel information from webhook data.

272

"""

273

def __init__(self, data: Dict[str, Any]): ...

274

275

id: int # Channel ID

276

name: str # Channel name

277

type: ChannelType # Channel type

278

```

279

280

### Sync Webhook Client

281

282

Synchronous webhook client for use without async/await.

283

284

```python { .api }

285

class SyncWebhook:

286

"""

287

Synchronous Discord webhook client.

288

"""

289

def __init__(self, url: str, *, session: Optional[requests.Session] = None): ...

290

291

# Same properties as async Webhook

292

id: int

293

type: WebhookType

294

guild_id: Optional[int]

295

channel_id: Optional[int]

296

user: Optional[User]

297

name: Optional[str]

298

avatar: Optional[str]

299

token: Optional[str]

300

application_id: Optional[int]

301

source_guild: Optional[PartialWebhookGuild]

302

source_channel: Optional[PartialWebhookChannel]

303

url: str

304

305

# Class methods

306

@classmethod

307

def from_url(cls, url: str, *, session: Optional[requests.Session] = None) -> SyncWebhook:

308

"""Create sync webhook from URL."""

309

310

# Message sending (synchronous versions)

311

def send(

312

self,

313

content: Optional[str] = None,

314

*,

315

username: Optional[str] = None,

316

avatar_url: Optional[str] = None,

317

tts: bool = False,

318

file: Optional[File] = None,

319

files: Optional[List[File]] = None,

320

embed: Optional[Embed] = None,

321

embeds: Optional[List[Embed]] = None,

322

allowed_mentions: Optional[AllowedMentions] = None,

323

thread: Optional[Snowflake] = None,

324

wait: bool = False

325

) -> Optional[SyncWebhookMessage]:

326

"""Send a message via webhook (synchronous)."""

327

328

def fetch_message(self, id: int, *, thread: Optional[Snowflake] = None) -> SyncWebhookMessage:

329

"""Fetch a webhook message by ID (synchronous)."""

330

331

def edit_message(

332

self,

333

message_id: int,

334

*,

335

content: Optional[str] = None,

336

embed: Optional[Embed] = None,

337

embeds: Optional[List[Embed]] = None,

338

file: Optional[File] = None,

339

files: Optional[List[File]] = None,

340

attachments: Optional[List[Attachment]] = None,

341

allowed_mentions: Optional[AllowedMentions] = None,

342

thread: Optional[Snowflake] = None

343

) -> SyncWebhookMessage:

344

"""Edit a webhook message (synchronous)."""

345

346

def delete_message(self, message_id: int, *, thread: Optional[Snowflake] = None) -> None:

347

"""Delete a webhook message (synchronous)."""

348

349

def edit(

350

self,

351

*,

352

name: Optional[str] = None,

353

avatar: Optional[bytes] = None,

354

reason: Optional[str] = None

355

) -> SyncWebhook:

356

"""Edit webhook properties (synchronous)."""

357

358

def delete(self, *, reason: Optional[str] = None) -> None:

359

"""Delete the webhook (synchronous)."""

360

361

class SyncWebhookMessage:

362

"""

363

Synchronous version of WebhookMessage.

364

Same properties and methods as WebhookMessage but synchronous.

365

"""

366

def __init__(self, *, data: Dict[str, Any], state, webhook: SyncWebhook): ...

367

368

# Same properties as WebhookMessage

369

id: int

370

webhook_id: int

371

channel: PartialMessageable

372

guild: Optional[Guild]

373

content: str

374

clean_content: str

375

created_at: datetime

376

edited_at: Optional[datetime]

377

attachments: List[Attachment]

378

embeds: List[Embed]

379

# ... (all other properties)

380

381

# Synchronous methods

382

def edit(self, **kwargs) -> SyncWebhookMessage:

383

"""Edit the webhook message (synchronous)."""

384

385

def delete(self, *, delay: Optional[float] = None) -> None:

386

"""Delete the webhook message (synchronous)."""

387

388

def add_reaction(self, emoji: Union[Emoji, Reaction, PartialEmoji, str]) -> None:

389

"""Add a reaction to the message (synchronous)."""

390

391

def remove_reaction(self, emoji: Union[Emoji, Reaction, PartialEmoji, str], member: Member) -> None:

392

"""Remove a reaction from the message (synchronous)."""

393

394

def clear_reactions(self) -> None:

395

"""Clear all reactions from the message (synchronous)."""

396

397

def pin(self, *, reason: Optional[str] = None) -> None:

398

"""Pin the message (synchronous)."""

399

400

def unpin(self, *, reason: Optional[str] = None) -> None:

401

"""Unpin the message (synchronous)."""

402

```

403

404

### Webhook Types & Enums

405

406

```python { .api }

407

class WebhookType(Enum):

408

"""Webhook type enumeration."""

409

incoming = 1 # Incoming webhook

410

channel_follower = 2 # Channel follower webhook

411

application = 3 # Application webhook (for slash commands)

412

```

413

414

## Usage Examples

415

416

### Basic Webhook Usage

417

418

```python

419

import discord

420

import asyncio

421

import aiohttp

422

423

async def send_webhook_message():

424

"""Send a message via webhook."""

425

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

426

427

async with aiohttp.ClientSession() as session:

428

webhook = discord.Webhook.from_url(webhook_url, session=session)

429

430

# Send simple message

431

await webhook.send("Hello from webhook!")

432

433

# Send message with custom username and avatar

434

await webhook.send(

435

"Custom webhook message!",

436

username="Custom Bot",

437

avatar_url="https://example.com/avatar.png"

438

)

439

440

# Send message with embed

441

embed = discord.Embed(

442

title="Webhook Embed",

443

description="This is an embed sent via webhook",

444

color=0x00ff00

445

)

446

embed.add_field(name="Field 1", value="Value 1", inline=True)

447

embed.add_field(name="Field 2", value="Value 2", inline=True)

448

embed.set_footer(text="Sent via webhook")

449

450

await webhook.send(embed=embed)

451

452

# Run the async function

453

asyncio.run(send_webhook_message())

454

```

455

456

### Webhook with File Upload

457

458

```python

459

async def send_webhook_with_file():

460

"""Send webhook message with file attachment."""

461

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

462

463

async with aiohttp.ClientSession() as session:

464

webhook = discord.Webhook.from_url(webhook_url, session=session)

465

466

# Send file from disk

467

with open('example.png', 'rb') as f:

468

file = discord.File(f, filename='example.png')

469

await webhook.send("Check out this image!", file=file)

470

471

# Send multiple files

472

files = [

473

discord.File('file1.txt'),

474

discord.File('file2.png', filename='renamed.png')

475

]

476

await webhook.send("Multiple files!", files=files)

477

478

# Send file with embed

479

embed = discord.Embed(title="File Upload")

480

embed.set_image(url="attachment://example.png")

481

482

with open('example.png', 'rb') as f:

483

file = discord.File(f, filename='example.png')

484

await webhook.send(embed=embed, file=file)

485

486

asyncio.run(send_webhook_with_file())

487

```

488

489

### Message Editing and Management

490

491

```python

492

async def manage_webhook_messages():

493

"""Demonstrate webhook message management."""

494

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

495

496

async with aiohttp.ClientSession() as session:

497

webhook = discord.Webhook.from_url(webhook_url, session=session)

498

499

# Send message and get response

500

message = await webhook.send("Initial message", wait=True)

501

print(f"Sent message with ID: {message.id}")

502

503

# Wait a bit

504

await asyncio.sleep(2)

505

506

# Edit the message

507

await webhook.edit_message(

508

message.id,

509

content="Edited message!",

510

embed=discord.Embed(title="Edited", color=0xff9900)

511

)

512

513

# Wait and delete

514

await asyncio.sleep(2)

515

await webhook.delete_message(message.id)

516

print("Message deleted")

517

518

asyncio.run(manage_webhook_messages())

519

```

520

521

### Thread Support

522

523

```python

524

async def webhook_with_threads():

525

"""Use webhooks with Discord threads."""

526

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

527

528

async with aiohttp.ClientSession() as session:

529

webhook = discord.Webhook.from_url(webhook_url, session=session)

530

531

# Send message and create thread

532

message = await webhook.send("Starting a discussion!", wait=True)

533

534

# Create thread from message

535

thread = await webhook.create_thread(

536

name="Discussion Thread",

537

message=message,

538

auto_archive_duration=1440, # 24 hours

539

reason="Starting discussion"

540

)

541

542

# Send messages in the thread

543

await webhook.send(

544

"This is in the thread!",

545

thread=thread.id

546

)

547

548

await webhook.send(

549

"Another thread message with embed!",

550

thread=thread.id,

551

embed=discord.Embed(

552

title="Thread Message",

553

description="This message is in a thread",

554

color=0x9932cc

555

)

556

)

557

558

asyncio.run(webhook_with_threads())

559

```

560

561

### Synchronous Webhook Usage

562

563

```python

564

import discord

565

import requests

566

567

def sync_webhook_example():

568

"""Example using synchronous webhook client."""

569

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

570

571

# Create synchronous webhook

572

webhook = discord.SyncWebhook.from_url(webhook_url)

573

574

# Send simple message

575

webhook.send("Hello from sync webhook!")

576

577

# Send with embed

578

embed = discord.Embed(

579

title="Sync Webhook",

580

description="This was sent synchronously!",

581

color=0x00ff00

582

)

583

584

message = webhook.send(embed=embed, wait=True)

585

print(f"Sent message: {message.id}")

586

587

# Edit the message

588

webhook.edit_message(

589

message.id,

590

content="Edited sync message!",

591

embed=discord.Embed(title="Edited", color=0xff0000)

592

)

593

594

# Call synchronous function

595

sync_webhook_example()

596

```

597

598

### Webhook Error Handling

599

600

```python

601

import discord

602

import aiohttp

603

import asyncio

604

605

async def webhook_with_error_handling():

606

"""Demonstrate proper webhook error handling."""

607

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

608

609

async with aiohttp.ClientSession() as session:

610

webhook = discord.Webhook.from_url(webhook_url, session=session)

611

612

try:

613

# Try to send a message

614

await webhook.send("Test message")

615

print("Message sent successfully")

616

617

except discord.HTTPException as e:

618

if e.status == 404:

619

print("Webhook not found - check URL")

620

elif e.status == 429:

621

print(f"Rate limited - retry after {e.retry_after} seconds")

622

else:

623

print(f"HTTP error: {e.status} - {e.text}")

624

625

except discord.InvalidArgument as e:

626

print(f"Invalid argument: {e}")

627

628

except Exception as e:

629

print(f"Unexpected error: {e}")

630

631

# Validate webhook before using

632

try:

633

# Fetch webhook info to validate

634

webhook_info = await webhook.fetch()

635

print(f"Using webhook: {webhook_info.name}")

636

637

except discord.NotFound:

638

print("Webhook does not exist")

639

return

640

except discord.Forbidden:

641

print("No permission to access webhook")

642

return

643

644

# Send message with validation

645

if len("Very long message content" * 100) > 2000:

646

print("Message too long, truncating...")

647

content = ("Very long message content" * 100)[:1997] + "..."

648

else:

649

content = "Normal message"

650

651

await webhook.send(content)

652

653

asyncio.run(webhook_with_error_handling())

654

```

655

656

### Advanced Webhook Bot

657

658

```python

659

import discord

660

import aiohttp

661

import asyncio

662

from datetime import datetime, timezone

663

664

class WebhookBot:

665

"""Advanced webhook bot with multiple features."""

666

667

def __init__(self, webhook_url: str):

668

self.webhook_url = webhook_url

669

self.session = None

670

self.webhook = None

671

672

async def __aenter__(self):

673

self.session = aiohttp.ClientSession()

674

self.webhook = discord.Webhook.from_url(self.webhook_url, session=self.session)

675

return self

676

677

async def __aexit__(self, exc_type, exc_val, exc_tb):

678

if self.session:

679

await self.session.close()

680

681

async def send_notification(self, title: str, message: str, color: int = 0x0099ff):

682

"""Send a notification embed."""

683

embed = discord.Embed(

684

title=title,

685

description=message,

686

color=color,

687

timestamp=datetime.now(timezone.utc)

688

)

689

embed.set_footer(text="Notification System")

690

691

return await self.webhook.send(embed=embed, wait=True)

692

693

async def send_status_update(self, service: str, status: str, details: str = None):

694

"""Send a service status update."""

695

status_colors = {

696

"online": 0x00ff00,

697

"warning": 0xffaa00,

698

"offline": 0xff0000

699

}

700

701

embed = discord.Embed(

702

title=f"πŸ”§ {service} Status Update",

703

color=status_colors.get(status.lower(), 0x666666),

704

timestamp=datetime.now(timezone.utc)

705

)

706

707

embed.add_field(name="Status", value=status.title(), inline=True)

708

embed.add_field(name="Service", value=service, inline=True)

709

embed.add_field(name="Time", value=f"<t:{int(datetime.now().timestamp())}:R>", inline=True)

710

711

if details:

712

embed.add_field(name="Details", value=details, inline=False)

713

714

return await self.webhook.send(embed=embed, wait=True)

715

716

async def send_log_message(self, level: str, message: str, extra_data: dict = None):

717

"""Send a log message with formatting."""

718

level_colors = {

719

"debug": 0x666666,

720

"info": 0x0099ff,

721

"warning": 0xffaa00,

722

"error": 0xff0000,

723

"critical": 0x990000

724

}

725

726

level_emojis = {

727

"debug": "πŸ›",

728

"info": "ℹ️",

729

"warning": "⚠️",

730

"error": "❌",

731

"critical": "🚨"

732

}

733

734

embed = discord.Embed(

735

title=f"{level_emojis.get(level.lower(), 'πŸ“')} {level.upper()}",

736

description=f"```\n{message}\n```",

737

color=level_colors.get(level.lower(), 0x666666),

738

timestamp=datetime.now(timezone.utc)

739

)

740

741

if extra_data:

742

for key, value in extra_data.items():

743

embed.add_field(name=key.title(), value=str(value), inline=True)

744

745

return await self.webhook.send(embed=embed, wait=True)

746

747

async def send_metrics(self, metrics: dict):

748

"""Send system metrics."""

749

embed = discord.Embed(

750

title="πŸ“Š System Metrics",

751

color=0x9932cc,

752

timestamp=datetime.now(timezone.utc)

753

)

754

755

for metric, value in metrics.items():

756

embed.add_field(name=metric.replace('_', ' ').title(), value=value, inline=True)

757

758

return await self.webhook.send(embed=embed, wait=True)

759

760

# Usage example

761

async def main():

762

webhook_url = "https://discord.com/api/webhooks/YOUR_WEBHOOK_URL"

763

764

async with WebhookBot(webhook_url) as bot:

765

# Send various types of messages

766

await bot.send_notification(

767

"System Alert",

768

"Database connection restored",

769

color=0x00ff00

770

)

771

772

await bot.send_status_update(

773

"Web Server",

774

"online",

775

"All systems operational"

776

)

777

778

await bot.send_log_message(

779

"error",

780

"Failed to process user request",

781

{"user_id": 12345, "endpoint": "/api/users", "error_code": 500}

782

)

783

784

await bot.send_metrics({

785

"cpu_usage": "45%",

786

"memory_usage": "2.1GB / 8GB",

787

"active_users": 1234,

788

"requests_per_minute": 89

789

})

790

791

if __name__ == "__main__":

792

asyncio.run(main())

793

```