# Send on Discord

> Answer people who talk to your Discord bot, from your code.

Source: https://docs.vlayers.ai/developers/send/discord

Kind: How-to guide

## What you'll build

Code that replies to a person who wrote to your Discord bot.

## How Discord differs

People talk to your bot in a Discord server where it is installed, for example with its slash command. Each of those opens a conversation you can reply in. Your bot does not message people out of the blue. A Discord message is up to 2,000 characters; longer texts are split.

## Prerequisites

- A secret API key with `messages:send` and `messages:read`. See [Authentication and API keys](https://docs.vlayers.ai/get-started/authentication).
- A Discord bot connected in the dashboard under **Channels** and installed in your server. It is a [Binding](https://docs.vlayers.ai/get-started/concepts#binding), your sender on Discord.
- A conversation someone started with your bot. Its id comes from a `message.received` event ([webhooks](https://docs.vlayers.ai/developers/receive/webhooks) or the [event stream](https://docs.vlayers.ai/developers/receive/event-stream)) or from `GET /v1/conversations`.
- curl, Node.js 18 or later with `@voicelayer/api`, or Python 3.9 or later with `voicelayer`.

```bash
export CONVERSATION_ID=<the conversation's id>
```

## Step 1: Read what they wrote

`GET /v1/conversations/{id}/messages` returns the conversation's messages, newest page first with `before=end`.

cURL:

```bash
curl "https://api.vlayers.ai/v1/conversations/$CONVERSATION_ID/messages?before=end&limit=20" \
  -H "Authorization: Bearer $VOICELAYER_API_KEY"
```

TypeScript:

```ts
import { createVoiceLayerClient, listConversationMessages } from '@voicelayer/api';

const client = createVoiceLayerClient({ apiKey: process.env.VOICELAYER_API_KEY!, throwOnError: true });

const { data } = await listConversationMessages({
  client,
  path: {
    id: process.env.CONVERSATION_ID!
  },
  query: {
    before: 'end',
    limit: 20
  }
});
console.log(data.messages);
```

Python:

```python
import os
import voicelayer

config = voicelayer.Configuration(access_token=os.environ["VOICELAYER_API_KEY"])
with voicelayer.ApiClient(config) as client:
    api = voicelayer.ConversationsApi(client)
    result = api.list_conversation_messages(
        id=os.environ["CONVERSATION_ID"],
        before="end",
        limit=20,
    )
    print(result.messages)
```

## Step 2: Reply

`POST /v1/conversations/{id}/messages` replies in the conversation.

cURL:

```bash
curl -X POST "https://api.vlayers.ai/v1/conversations/$CONVERSATION_ID/messages" \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": {
      "type": "text",
      "text": "Yes, we have a table at 7pm. Shall I book it?"
    }
  }'
```

TypeScript:

```ts
import { createVoiceLayerClient, replyToConversation } from '@voicelayer/api';

const client = createVoiceLayerClient({ apiKey: process.env.VOICELAYER_API_KEY!, throwOnError: true });

const { data } = await replyToConversation({
  client,
  path: {
    id: process.env.CONVERSATION_ID!
  },
  body: {
    content: {
      type: 'text',
      text: 'Yes, we have a table at 7pm. Shall I book it?'
    }
  }
});
console.log(data.message.id);
```

Python:

```python
import os
import voicelayer

config = voicelayer.Configuration(access_token=os.environ["VOICELAYER_API_KEY"])
with voicelayer.ApiClient(config) as client:
    api = voicelayer.ConversationsApi(client)
    result = api.reply_to_conversation(
        id=os.environ["CONVERSATION_ID"],
        reply_to_conversation_request=voicelayer.ReplyToConversationRequest.from_dict({
            "content": {
                "type": "text",
                "text": "Yes, we have a table at 7pm. Shall I book it?",
            },
        }),
    )
    print(result.message.id)
```

Response `202`:

```json
{
  "message": {
    "id": "0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32",
    "conversationId": "0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21",
    "channel": "sms",
    "direction": "outbound",
    "status": "queued",
    "text": "Yes, we have a table at 7pm. Shall I book it?",
    "media": [],
    "from": "+14155550100",
    "to": "+15550123",
    "bindingId": null,
    "metadata": {},
    "error": null,
    "createdAt": "2026-10-20T15:04:05.000Z",
    "parts": [
      {
        "id": "0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32",
        "status": "queued"
      }
    ]
  }
}
```

## Test it

In test mode, `test-1`, `test-2` and so on play people writing to your bot. Your workspace needs a connected Discord bot to receive the simulated message on:

cURL:

```bash
curl -X POST https://api.vlayers.ai/v1/test/inbound \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "discord",
    "from": "test-2",
    "text": "Is the server down?"
  }'
```

TypeScript:

```ts
import { createVoiceLayerClient, createTestInbound } from '@voicelayer/api';

const client = createVoiceLayerClient({ apiKey: process.env.VOICELAYER_API_KEY!, throwOnError: true });

const { data } = await createTestInbound({
  client,
  body: {
    channel: 'discord',
    from: 'test-2',
    text: 'Is the server down?'
  }
});
console.log(data.conversationId);
```

Python:

```python
import os
import voicelayer

config = voicelayer.Configuration(access_token=os.environ["VOICELAYER_API_KEY"])
with voicelayer.ApiClient(config) as client:
    api = voicelayer.TestApi(client)
    result = api.create_test_inbound(
        create_test_inbound_request=voicelayer.CreateTestInboundRequest.from_dict({
            "channel": "discord",
            "from": "test-2",
            "text": "Is the server down?",
        }),
    )
    print(result.conversation_id)
```

Save the returned `conversationId` as `CONVERSATION_ID` and run Steps 1 and 2. See [Test mode](https://docs.vlayers.ai/developers/test-mode).

## Common errors

| Error | Status | How to fix |
|---|---|---|
| [`not_found`](https://docs.vlayers.ai/errors/not_found) | 404 | Check the id, and that the key belongs to the workspace (and covers the channel) that owns it. |
| [`no_sender`](https://docs.vlayers.ai/errors/no_sender) | 409 | Connect a sender for the channel in the dashboard (for email, create a mailbox), or name one in `from`. |
| [`capability_not_ready`](https://docs.vlayers.ai/errors/capability_not_ready) | 409 | Fix the connection in the dashboard (Channels) using `details.remediation` when present, then send again. |
| [`content_too_long`](https://docs.vlayers.ai/errors/content_too_long) | 422 | Shorten the text, or send it with `split: "auto"` where it fits the part limit. |
| [`plugin_suspended`](https://docs.vlayers.ai/errors/plugin_suspended) | 409 | Contact support; the channel works again once the suspension is lifted. |

## Next steps

- [Send an email](https://docs.vlayers.ai/developers/send/email).
- [Conversations and handoff](https://docs.vlayers.ai/developers/handoff).
- [Receive with webhooks](https://docs.vlayers.ai/developers/receive/webhooks).
