# Send Messages

> POST /v1/whatsapp/messages - send WhatsApp text, template, image, audio, video and document messages from your Edesy number, then list and fetch messages.

Source: https://edesy.in/docs/whatsapp-number/api/send-messages

`POST https://voice-api.edesy.in/v1/whatsapp/messages` sends a WhatsApp message from a connected Edesy number. Set `type` to `text`, `template`, `image`, `audio`, `video` or `document`, give the recipient in E.164 format, and authenticate with your API key. The response returns the stored message with its WhatsApp message ID and status.

## Facts

| Item | Detail |
|---|---|
| Base URL | `https://voice-api.edesy.in/v1/whatsapp` |
| Auth | `Authorization: Bearer sk_...` (create keys on the **API Keys** page) |
| Send | `POST /messages` |
| Message types | `text`, `template`, `image`, `audio`, `video`, `document` |
| Recipient | `to` in E.164, e.g. `+919876543210` |
| Free-form messages | Only within 24 hours of the customer's last message; otherwise use `template` |
| Status values | `queued`, `sent`, `delivered`, `read`, `failed` |
| Response | `201` with `data` and `meta` (`request_id`, `timestamp`) |

## Authentication

Create an API key on the **API Keys** page in wa-connect.edesy.in and send it on every request:

```
Authorization: Bearer sk_your_api_key_here
```

## How it works

1. **Find your number's ID.** `GET /v1/whatsapp/config` lists your connected numbers. Use the `phone_number_id` value (Edesy's UUID for the number).
2. **Send** with `POST /v1/whatsapp/messages`.
3. **Store** the returned `id` and `wamid`.
4. **Receive status updates** on your [webhook](https://edesy.in/docs/whatsapp-number/api/webhooks) as the message is sent, delivered and read.

## Request body

| Field | Type | Required | Description |
|---|---|---|---|
| `phone_number_id` | string (UUID) | yes | The Edesy number to send from. `channel_id` is accepted as an alias |
| `to` | string | yes | Recipient in E.164 |
| `type` | string | yes | `text`, `template`, `image`, `audio`, `video` or `document` |
| `text.body` | string | for `text` | Message text |
| `template.name` | string | for `template` | Approved template name |
| `template.language.code` | string | for `template` | e.g. `en_US`, `hi` |
| `template.components` | array | no | Values for template variables (header, body, button) |
| `media.link` | string | for media, or `media.id` | Public URL of the file |
| `media.id` | string | for media, or `media.link` | Meta media ID |
| `media.caption` | string | no | Caption |
| `media.filename` | string | no | File name for documents |
| `reply_to` | string | no | Message ID to reply to |

## Examples

### Text

```bash
curl -X POST https://voice-api.edesy.in/v1/whatsapp/messages \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number_id": "your-edesy-phone-number-uuid",
    "to": "+919876543210",
    "type": "text",
    "text": { "body": "Your order has been packed." }
  }'
```

### Template

```bash
curl -X POST https://voice-api.edesy.in/v1/whatsapp/messages \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number_id": "your-edesy-phone-number-uuid",
    "to": "+919876543210",
    "type": "template",
    "template": {
      "name": "order_update",
      "language": { "code": "en_US" },
      "components": [
        { "type": "body", "parameters": [ { "type": "text", "text": "Asha" }, { "type": "text", "text": "#1042" } ] }
      ]
    }
  }'
```

### Document

```json
{
  "phone_number_id": "your-edesy-phone-number-uuid",
  "to": "+919876543210",
  "type": "document",
  "media": { "link": "https://example.com/invoice-1042.pdf", "filename": "invoice-1042.pdf", "caption": "Your invoice" }
}
```

## Response `201`

```json
{
  "data": {
    "id": "5b1c2d3e-0000-4000-8000-000000000000",
    "conversation_id": "7d8e9f00-0000-4000-8000-000000000000",
    "wamid": "wamid.HBgM...",
    "direction": "outbound",
    "type": "text",
    "status": "sent",
    "from": "+911234567890",
    "to": "+919876543210",
    "content": "Your order has been packed.",
    "created_at": "2026-10-28T10:15:12Z"
  },
  "meta": { "request_id": "...", "timestamp": "2026-10-28T10:15:12Z" }
}
```

## Other message endpoints

| Method | Path | Description |
|---|---|---|
| `GET` | `/messages` | List. Query: `direction`, `status`, `type`, `from`, `to`, `conversation_id`, `page`, `per_page` (default 20) |
| `GET` | `/messages/{id}` | One message |
| `POST` | `/messages/text` | Text shortcut. Body: `phone_number_id`, `to`, `text`, `reply_to` |
| `POST` | `/messages/template` | Template shortcut. Body: `phone_number_id`, `to`, `template_name`, `language`, `components` |

## Errors

Errors return `{"error": {"code": "...", "message": "..."}}`.

| Code | Meaning |
|---|---|
| `VALIDATION_ERROR` | Missing or invalid field |
| `PHONE_NOT_WHATSAPP_ENABLED` | The number is not connected to WhatsApp, or messaging is off |
| `MESSAGING_WINDOW_EXPIRED` | More than 24 hours since the customer's last message; send a template |
| `TEMPLATE_NOT_FOUND` | No template with that name |
| `TEMPLATE_NOT_APPROVED` | The template is not approved yet |
| `RECIPIENT_BLOCKED` | The recipient has blocked the number |
| `META_API_ERROR` | Meta rejected the request |
| `RATE_LIMITED` | Too many requests; slow down and retry |
| `MESSAGE_NOT_FOUND` | No message with that ID |

## FAQ

### Which number does the message come from?
The Edesy number whose `phone_number_id` you send. Get the IDs from `GET /v1/whatsapp/config`.

### Can I message a customer who has never written to me?
Yes, with an approved template (`type: "template"`). Free-form text needs an open 24-hour window.

### What phone format does `to` use?
E.164, with the country code, e.g. `+919876543210`.

### Can I send PDFs and images?
Yes. Use `type` `document` or `image` with `media.link` (a public URL) or `media.id`.

### How do I know a message was delivered or read?
Subscribe to `message.status` on a [webhook](https://edesy.in/docs/whatsapp-number/api/webhooks), or call `GET /v1/whatsapp/messages/{id}` and check `status`, `delivered_at` and `read_at`.

### Are there official Node or Python SDKs?
No. The API is plain HTTPS and JSON, so any HTTP client works.

### Is there a test tool in the portal?
Yes. The **API Keys** page has a "Try it - send a test message" panel that also shows the equivalent API request.
