# Send a message

Source: https://docs.vlayers.ai/reference/messages/send-message

`POST /v1/messages` · scope `messages:send`

Sends a text or media message on any channel your workspace has connected: SMS, WhatsApp, Telegram, Discord or email. Use it to start a conversation or to message an address directly; to answer someone, `POST /v1/conversations/{id}/messages` is simpler.

The answer is `202 Accepted`: the message is queued, not delivered yet. Delivery arrives as `message.sent`, `message.delivered` or `message.failed` events. Send an `Idempotency-Key` so a retry never sends twice.

Requires an API key with the `messages:send` scope.

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `idempotency-key` | header | string | no | A unique value (a UUID works) that makes a retry safe: sending the same key again returns the first result instead of acting twice. 1–255 printable characters. Example: `"7f3c9a2e-5b1d-4c8e-9f0a-2d6b8e4c1a37"` |
| `channel` | body | string | yes | The channel to send on: `sms`, `mms`, `whatsapp`, `telegram`, `discord` or `email`. `GET /v1/channels` lists what your workspace can use. |
| `from` | body | object | no | Which of your senders to use: `{ "phoneNumberId" }` for SMS and MMS, `{ "bindingId" }` for WhatsApp, Telegram and Discord, `{ "mailboxId" }` for email. Leave it out when you have one sender on the channel. |
| `to` | body | string \| object | yes | Who receives it: a phone number in E.164 format (`+14155550123`), the person's address on an app channel, an email address, or `{ "conversationId" }` to answer an existing conversation. |
| `content` | body | object | yes | What to send: `{ "type": "text", "text" }`, `{ "type": "media", "media": [{ "url" }], "caption" }` (MMS). `{ "type": "template", "template" }` is reserved for message templates, which are not available yet: it is refused with `422 operation_not_supported`. |
| `subject` | body | string | no | Email only: the subject of a new email. A reply keeps its thread's subject. |
| `split` | body | "auto" \| "refuse" | no | `auto` (the default) sends a text longer than the channel allows as several messages, each billed. `refuse` answers `422 content_too_long` instead. |
| `metadata` | body | object | no | Your own key/value pairs, up to 4 KB of JSON. Stored with the message and repeated in its events, so you can match an event to your records. |

## Request

cURL:

```bash
curl -X POST https://api.vlayers.ai/v1/messages \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "to": "+15550123",
    "content": {
      "type": "text",
      "text": "Your table for two is booked for 7pm."
    }
  }'
```

TypeScript:

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

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

const { data } = await sendMessage({
  client,
  body: {
    channel: 'sms',
    to: '+15550123',
    content: {
      type: 'text',
      text: 'Your table for two is booked for 7pm.'
    }
  }
});
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.MessagesApi(client)
    result = api.send_message(
        send_message_request=voicelayer.SendMessageRequest.from_dict({
            "channel": "sms",
            "to": "+15550123",
            "content": {
                "type": "text",
                "text": "Your table for two is booked for 7pm.",
            },
        }),
    )
    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": "Your table for two is booked for 7pm.",
    "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"
      }
    ]
  }
}
```
