> For the complete documentation index, see [llms.txt](https://docs.channel360.co.za/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.channel360.co.za/api-usage/send-a-template-notification.md).

# Send a template notification

Send one approved WhatsApp template to one person with one API request.

Send one approved WhatsApp template message to one person with one API request.

{% hint style="info" %}
**The Channel360 web app and the API send messages separately.** The API ignores template tag settings. Put your actual placeholder values in the API request.

The template must exist under your organisation and be approved by WhatsApp. [Tags vs. the API](/api-usage/concepts/tags-vs-the-api.md) explains the difference.
{% endhint %}

## Words used on this page

| Term             | Meaning                                                                                      |
| ---------------- | -------------------------------------------------------------------------------------------- |
| **Notification** | One WhatsApp message sent to one person through the API.                                     |
| **Template**     | A WhatsApp-approved message. It can contain numbered blanks such as `{{1}}`.                 |
| **Placeholder**  | A numbered blank in a template.                                                              |
| **Component**    | A part of a template: header, body or button. In the request these are written in lowercase. |
| **Parameters**   | Values that fill placeholders, in order.                                                     |

## Before you start

* **An API key** — **Settings → Developer Settings → API keys** tab → **Create**.
* **Your Organisation API URL** — the **Copy** button on the **API details** card on the same page.
* **A webhook**, so you can see what happened to the message — see [Receive delivery updates](/api-usage/receive-delivery-updates.md).

[Authentication](/api-usage/get-started/authentication.md) explains the key and URL in more detail.

## Steps

### 1. Check the template

1. Open **Templates** in the Channel360 web app.
2. Create the template or select an existing one.
3. Wait until its status is **APPROVED**.
4. Copy its exact name and language code.
5. Note each placeholder and its order.

For example, record `order_shipped`, `en`, and `{{1}}`, `{{2}}`, `{{3}}`.

You do not need to configure template tags for API sends.

### 2. Build the request

Send a `POST` request to:

```
https://channel360.co.za/v1.1/org/<ORG_ID>/notification
```

Add these headers:

```
Authorization: Bearer <API_KEY>
Content-Type: application/json
```

| Field                            | Required | Value                                                                                                        |
| -------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `destination`                    | Yes      | Recipient mobile number in international format, country code included, digits only. Example: `27821234567`. |
| `message.type`                   | Yes      | Always `"template"`.                                                                                         |
| `message.template.name`          | Yes      | Exact approved template name.                                                                                |
| `message.template.language.code` | Yes      | Exact approved language code, such as `"en"`.                                                                |
| `message.template.components`    | Yes      | Components and parameters to fill. Use `[]` when there are no placeholders.                                  |
| `msg_id`                         | No       | Your reference, such as an order number. It comes back in delivery updates.                                  |

### 3. Fill placeholders

Add a component for each template part that has placeholders.

List the parameters in placeholder order. The first parameter fills `{{1}}`.

For a template with `Hi {{1}}, welcome to Acme!`, send:

```json
{
  "destination": "27821234567",
  "message": {
    "type": "template",
    "template": {
      "name": "welcome_message",
      "language": { "code": "en" },
      "components": [
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Sipho" }
          ]
        }
      ]
    }
  }
}
```

See [Filling template placeholders](/api-usage/send-a-template-notification/filling-template-placeholders.md) for media headers and URL buttons.

### 4. Send it

Replace the values inside `<…>` before running this command.

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST "https://channel360.co.za/v1.1/org/<ORG_ID>/notification" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "destination": "27821234567",
    "message": {
      "type": "template",
      "template": {
        "name": "welcome_message",
        "language": { "code": "en" },
        "components": [
          {
            "type": "body",
            "parameters": [
              { "type": "text", "text": "Sipho" }
            ]
          }
        ]
      }
    }
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const response = await fetch(
  "https://channel360.co.za/v1.1/org/<ORG_ID>/notification",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer <API_KEY>",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      destination: "27821234567",
      message: {
        type: "template",
        template: {
          name: "welcome_message",
          language: { code: "en" },
          components: [
            {
              type: "body",
              parameters: [{ type: "text", text: "Sipho" }]
            }
          ]
        }
      }
    })
  }
);

console.log(await response.json());
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.post(
    "https://channel360.co.za/v1.1/org/<ORG_ID>/notification",
    headers={
        "Authorization": "Bearer <API_KEY>",
        "Content-Type": "application/json",
    },
    json={
        "destination": "27821234567",
        "message": {
            "type": "template",
            "template": {
                "name": "welcome_message",
                "language": {"code": "en"},
                "components": [
                    {
                        "type": "body",
                        "parameters": [{"type": "text", "text": "Sipho"}],
                    }
                ],
            },
        },
    },
)

print(response.json())
```

{% endtab %}
{% endtabs %}

### 5. Check the response

A successful request returns HTTP `201` and a notification ID:

```json
{ "notification": { "_id": "6710f3c2a1b2c3d4e5f60789" } }
```

{% hint style="warning" %}
`201` means Channel360 accepted and queued the message. It does not mean the message was delivered.
{% endhint %}

Save the `_id` and your `msg_id`, if used. They help you match delivery updates.

### 6. Get delivery updates

Delivery results reach you **only** through webhooks. If no webhook is registered for your organisation, you cannot find out whether the message arrived.

Channel360 posts status updates to your webhook: sent, delivered, read or failed. They include your `msg_id`. See [Receive delivery updates](/api-usage/receive-delivery-updates.md) to set this up.

## Check it worked

* The message arrives on the recipient's phone.
* Your webhook receives `notification:delivery:channel` when WhatsApp accepts the message.
* It then receives `notification:delivery:user` when the message reaches the phone.
* If it receives `notification:delivery:failure` instead, its `error` object says why.

## What can go wrong

| What you see                                      | Why                                                                    | What to do                                                                                      |
| ------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| **400** `Could not find a valid template`         | Channel360 cannot find a template with that name in your organisation. | Check the name, underscores and case. Check the organisation ID.                                |
| **400** `Template language code must be provided` | `message.template.language.code` is missing.                           | Add `"language": { "code": "en" }`.                                                             |
| **400** `Organization Not Found`                  | The organisation ID in the URL does not exist.                         | Copy the Organisation API URL again.                                                            |
| **401 / 403** unauthorised                        | The API key is missing, wrong, or belongs to another organisation.     | Check the `Authorization: Bearer …` header and organisation ID.                                 |
| **201**, but no message arrives                   | The request was accepted. WhatsApp later rejected the message.         | Check parameter counts, language, public media links and template approval. Check your webhook. |

Every error message is listed in [Troubleshooting](/api-usage/troubleshooting.md).

## Next

{% content-ref url="/pages/Pvr9fMGmTMGuq2mIeqER" %}
[Filling template placeholders](/api-usage/send-a-template-notification/filling-template-placeholders.md)
{% endcontent-ref %}

{% content-ref url="/pages/NtsbXspiU4OagtOGfKyY" %}
[Receive delivery updates](/api-usage/receive-delivery-updates.md)
{% endcontent-ref %}

{% content-ref url="/pages/RJMlaxNFSbVbTDbJ9pC3" %}
[Tags vs. the API](/api-usage/concepts/tags-vs-the-api.md)
{% endcontent-ref %}
