---
title: "Send messages"
description: "Send SMS and WhatsApp messages, one to each person, up to 100 at a time."
url: "https://docs.goomzo.africa/docs/developers/messages/send"
docs_index: /llms.txt
lastUpdated: 2026-11-12
section: "Messages"
related:
  - /docs/developers/messages
  - /docs/developers/messages/templates
  - /docs/developers/messages/broadcasts
---

> For an index of all documentation, see [/llms.txt](https://docs.goomzo.africa/llms.txt). Any page is also available as Markdown by adding .md to its URL.

# Send messages

> Send SMS and WhatsApp messages, one to each person, up to 100 at a time.

Send one message to each person, by SMS or WhatsApp, now or at a time you choose. Send up to 100 in one request:
they're queued all or none.

## Requirements

- An API key with the `messages.send` permission.
- For SMS, enough SMS on your account. For WhatsApp, your number connected.

## Requests

```text
POST /v1/messages
```

### Request syntax

```json
{
  "messages": [
    {
      "to": "<PHONE_NUMBER>",
      "customerId": "<CUSTOMER_ID>",
      "channel": "<CHANNEL>",
      "from": "<SENDER>",
      "content": { "text": "<TEXT>" },
      "template": "<TEMPLATE_NAME>",
      "variables": { "<KEY>": "<VALUE>" },
      "sendAt": "<TIME>",
      "replyTo": "<RECEIVED_MESSAGE_ID>"
    }
  ]
}
```

| Placeholder             | Description                                                                                               | Sample value           |
| ----------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------- |
| `<PHONE_NUMBER>`        | _String._ Who it's to, with the country code. Use `to` or `customerId`, not both.                         | `+255712345678`        |
| `<CUSTOMER_ID>`         | _String._ One of your customers. Their phone is used.                                                     | `cus_4hq2v9n1c8x0t6pk` |
| `<CHANNEL>`             | _String._ `sms` or `whatsapp`. Optional with a template, which has its own.                               | `sms`                  |
| `<SENDER>`              | _String. Optional._ An SMS sender ID from `GET /v1/messaging/senders`. Left out, yours or the shared one. | `DUKA AMINA`           |
| `<TEXT>`                | _String._ What it says. SMS: up to 6 parts. WhatsApp: up to 4,096 characters. Leave out with a template.  | `Your order is ready.` |
| `<TEMPLATE_NAME>`       | _String._ A saved template's name or id. See [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai).       | `auth_1`               |
| `<KEY>`, `<VALUE>`      | _Object of strings._ The template's `{{data.x}}` and `{{secret.x}}` values.                               | `{ "code": "482913" }` |
| `<TIME>`                | _String. Optional._ When to send it, within a year. Left out, now. WhatsApp text always goes now.         | `2026-11-13T07:00:00Z` |
| `<RECEIVED_MESSAGE_ID>` | _String. Optional._ WhatsApp only: a message the customer sent, which this reply quotes.                  | `rcv_8f2k1m0p9x3a7q2z` |

### Example request

```bash
curl https://api.goomzo.africa/v1/messages \
  -H "Authorization: Bearer $GOOMZO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042-ready" \
  -d '{
    "messages": [
      { "to": "+255712345678", "channel": "sms", "content": { "text": "Amina, order #1042 is ready." } }
    ]
  }'
```

## Responses

The answer is `201` with the messages, in the order you sent them.

```json
{
  "items": [
    {
      "id": "msg_7c1x9v2b4n6m8q0w",
      "customerId": "cus_4hq2v9n1c8x0t6pk",
      "to": { "name": "Amina", "phone": "+255712345678" },
      "channel": "sms",
      "content": { "text": "Amina, order #1042 is ready." },
      "status": "sending",
      "error": null,
      "sendAt": "2026-11-12T09:14:03Z",
      "private": false,
      "template": null
    }
  ]
}
```

| Placeholder | Description                                                                | Sample value           |
| ----------- | -------------------------------------------------------------------------- | ---------------------- |
| `id`        | _String._ The message's id. Webhooks and `GET /v1/messages/{id}` use it.   | `msg_7c1x9v2b4n6m8q0w` |
| `status`    | _String._ Where it is. See [statuses](https://docs.goomzo.africa/docs/developers/messages?utm_source=llms&utm_medium=ai#statuses). | `sending`              |
| `private`   | _Boolean._ It was sent with secrets, shown as `••••••` in `content`.       | `false`                |
| `template`  | _Object or null._ The WhatsApp template it went as.                        | `null`                 |

**Important:** This answer only means Goomzo accepted the message. It doesn't mean it was delivered. Follow its
status with [webhooks](https://docs.goomzo.africa/docs/developers/webhooks?utm_source=llms&utm_medium=ai).

## Notes

- **All or none:** every message is checked, and the SMS for all of them set aside together. If one isn't valid, or
  there isn't enough SMS for all of them, none is sent, and the error names the bad one, such as `messages[1].to`.
- **Not enough SMS:** `422 insufficient_sms` says how many the request `needed` and how many were `available`.
- **Unknown numbers:** a number that isn't one of your customers is still sent to, under the number itself. No
  customer is added.
- **Before you send:** `POST /v1/messaging/estimate` takes the same `channel`, `content` and audience, and says what
  it would use.

## Next steps

- [Send templates](https://docs.goomzo.africa/docs/developers/messages/templates?utm_source=llms&utm_medium=ai)
- [Broadcasts](https://docs.goomzo.africa/docs/developers/messages/broadcasts?utm_source=llms&utm_medium=ai)
- [Safe retries](https://docs.goomzo.africa/docs/developers/idempotency?utm_source=llms&utm_medium=ai)

---

For an index of all available documentation, see [/llms.txt](https://docs.goomzo.africa/llms.txt)
