# Discord Messages

This page covers sending and deleting messages and uploading attachments and audio with `core/discord`.

Every method here sends through `ChannelMessageSendComplex` (or the matching REST call) with `discordgo.WithContext(ctx)`, and returns `channelID is required` for an empty channel ID. A non-empty `replyTo` attaches the message as a reply to that message ID in the same channel; `""` sends a standalone message.

## Text

```go
msg, err := bot.Send(ctx, channelID, replyTo, "**hello**")
```

Discord renders Markdown in every message, so there is no parse-mode option.

`Delete(ctx, channelID, messageID)` deletes one message; an empty `messageID` returns `messageID is required`, and API errors are wrapped as `Session.ChannelMessageDelete: ...`.

## Attachments

```go
msg, err := bot.SendFiles(ctx, channelID, replyTo, []string{"a.png", "b.pdf"}, "files")
```

| Rule | Behavior |
|---|---|
| Count | 1 to 10 paths, all in one message; otherwise `paths must be 1-10` |
| Empty path | Returns `path is required` |
| Upload | Each file is opened with `os.Open` and streamed; the name is `filepath.Base(path)`; Discord infers the type from the extension |
| Caption | The first `caption` string becomes the message text shared by all attachments |

## Audio

```go
msg, err := bot.SendVoice(ctx, channelID, replyTo, "./reply.ogg", "caption")
```

`SendVoice` uploads an existing file as one attachment with content type `audio/ogg`. Discord shows it as an audio attachment with a player, not as a waveform voice message: discordgo v0.29.0 cannot send the `duration_secs` and `waveform` fields that the voice-message flag requires. An empty path returns `path is required`.

Code written for v0.4.x, `SendVoice(ctx, channelID, replyTo, text, apiKey)`, still compiles against v0.5.0 but uploads `text` as a file path and posts `apiKey` as the caption. See [Removed APIs](/removed-apis).

## Related pages

- [Discord Interactions](/discord-interactions)
- [Saving Media](/media-save)
- [Discord API](/api-reference-discord)
