# WhatsApp Messaging

Send WhatsApp messages through two channels — **WhatsApp Cloud** (Meta Cloud API) and **WhatsApp Lite** (direct connection). This guide covers message types, template components, media, and SMS fallback.

Addressing a recipient — phone or BSUID
Every customer has a durable, business-scoped user id (**BSUID**, alpha usernames — e.g. `ZA.1021033720668862`) that stays stable for your business even if the customer changes their phone number. Address a recipient by phone (`to`), by BSUID (`customerUserId`), or both — supply at least one. When both are present, `to` takes precedence and the BSUID rides along as a durable fallback. **The phone number remains the primary identifier today** — store the BSUID now and rely on it as phone numbers become optional.

Each entry in `recipients` accepts:

| Field | Type | Description |
|  --- | --- | --- |
| `to` | string | Recipient phone number in international format, country code first, leading `+` optional (`+27821234567` or `27821234567`). Must **not** start with `0`. Required unless `customerUserId` is supplied |
| `customerUserId` | string | Recipient **BSUID** (e.g. `ZA.1021033720668862`), durable across phone-number changes. Supply alongside `to` (phone wins, BSUID kept as a fallback) or on its own to address a recipient with no phone. A malformed value is ignored, so a BSUID-only send then requires a valid `to`. Required unless `to` is supplied |
| `ctId` | string | Client-defined tracking id, echoed back in delivery receipts and webhooks |
| `gstId` | string | eCommunicate system tracking id for end-to-end delivery tracking |


Authentication Required
All API requests require your Developer Key in the `Authorization` header. No `Bearer` prefix — pass the key directly.
See [Authentication](/guides/authentication) for setup and security best practices.

## Endpoints

| Method | Endpoint | Description |
|  --- | --- | --- |
| `POST` | `/whatsapp-api-service/v2/messages` | Unified endpoint — routes to WhatsApp or SMS based on `channel` |
| `POST` | `/whatsapp-api-service/v2/channels/whatsapp` | WhatsApp-only endpoint |


Messages sent here don't appear in Live Chat
Both endpoints above deliver directly to the customer through the API Service — they do **not** flow through the chat service, so they will not show up on agent screens or in `Message/getMessagesByParticipantId` responses.

If an outbound message must be visible to your live-chat agents, send it through `POST /pl4chat-service/Message/sendMessageWhatsapp` (or `/sendMessageWithAttachment`) instead. See the [Live Chat guide](/guides/live-chat) for the request shape, and [How the system fits together](/guides/getting-started#how-the-system-fits-together) for the full architecture.

## Message types

| Type | Value | When to use |
|  --- | --- | --- |
| **Notification** | `NOTIFICATION` | Outbound template messages — requires approved `templateName` and `templateId` |
| **Chat** | `CHAT` | Free-form session messages within a conversation |


Session window
**WhatsApp Cloud:** Chat messages can only be sent within the **24-hour customer service window** (starts when the customer messages you).
**WhatsApp Lite:** Chat messages can be sent **at any time** — no window restrictions.

## Template messaging rules

Five mandatory rules
1. `templateName` and `templateId` are **required** for all `NOTIFICATION` messages
2. If the template body contains `{{n}}` placeholders, include a `body` component with matching parameters
3. Media templates require a `header` component with `format` and `url`
4. Button templates require a `button` component with parameters
5. Carousel templates require a `carousel` component with a `cards` array


## Message examples

### Text template

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "seasonal_promo_text",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321", "customerUserId": "ZA.1021033720668862" }],
        "components": [
          {
            "type": "body",
            "parameters": ["John"]
          }
        ]
      }
    ]
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "seasonal_promo_text",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "body",
          "parameters": ["John"]
        }
      ]
    }
  ]
}
```

The `parameters` array maps to `{{1}}`, `{{2}}`, etc. in the template body.

### Media template

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "invoice_delivery",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "components": [
          {
            "type": "header",
            "format": "DOCUMENT",
            "url": "https://example.com/invoice.pdf",
            "filename": "invoice_jan.pdf"
          },
          {
            "type": "body",
            "parameters": ["John", "January"]
          }
        ]
      }
    ],
    "fallback": {
      "sendFallback": true,
      "unicode": false
    }
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "invoice_delivery",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "header",
          "format": "DOCUMENT",
          "url": "https://example.com/invoice.pdf",
          "filename": "invoice_jan.pdf"
        },
        {
          "type": "body",
          "parameters": ["John", "January"]
        }
      ]
    }
  ],
  "fallback": {
    "sendFallback": true,
    "unicode": false
  }
}
```

**Supported header formats:** `DOCUMENT`, `IMAGE`, `VIDEO`

### Call to action

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "feedback_cta",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "components": [
          {
            "type": "body",
            "parameters": ["John"]
          },
          {
            "type": "button",
            "parameters": ["Yes", "No"],
            "conversationParameters": [
              { "payload": "Yes", "conversationState": "start" },
              { "payload": "No", "conversationState": "end" }
            ]
          }
        ]
      }
    ]
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "feedback_cta",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "body",
          "parameters": ["John"]
        },
        {
          "type": "button",
          "parameters": ["Yes", "No"],
          "conversationParameters": [
            { "payload": "Yes", "conversationState": "start" },
            { "payload": "No", "conversationState": "end" }
          ]
        }
      ]
    }
  ]
}
```

- `conversationState: "start"` — keeps the conversation open for follow-up
- `conversationState: "end"` — closes the conversation when this button is tapped


### Carousel

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "product_carousel_v1",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "components": [
          {
            "type": "body",
            "parameters": ["John"]
          },
          {
            "type": "carousel",
            "cards": [
              {
                "components": [
                  { "type": "header", "format": "IMAGE", "url": "https://example.com/product1.jpg" },
                  { "type": "body", "parameters": ["Widget A", "$19.99"] },
                  { "type": "button", "parameters": ["https://example.com/widget-a"] }
                ]
              },
              {
                "components": [
                  { "type": "header", "format": "IMAGE", "url": "https://example.com/product2.jpg" },
                  { "type": "body", "parameters": ["Widget B", "$29.99"] },
                  { "type": "button", "parameters": ["https://example.com/widget-b"] }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "product_carousel_v1",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "body",
          "parameters": ["John"]
        },
        {
          "type": "carousel",
          "cards": [
            {
              "components": [
                { "type": "header", "format": "IMAGE", "url": "https://example.com/product1.jpg" },
                { "type": "body", "parameters": ["Widget A", "$19.99"] },
                { "type": "button", "parameters": ["https://example.com/widget-a"] }
              ]
            },
            {
              "components": [
                { "type": "header", "format": "IMAGE", "url": "https://example.com/product2.jpg" },
                { "type": "body", "parameters": ["Widget B", "$29.99"] },
                { "type": "button", "parameters": ["https://example.com/widget-b"] }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

Each card can have its own header, body parameters, and button — allowing rich product showcases.

### Chat message

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "messageType": "CHAT",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "messageText": "Hello, this is a standard session message."
      }
    ]
  }
}
```

**With media attachment:**

```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "messageType": "CHAT",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "messageText": "Here is the document you requested.",
        "media": {
          "url": "https://example.com/document.pdf",
          "caption": "Monthly Report"
        }
      }
    ]
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "messageType": "CHAT",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "messageText": "Hello, this is a standard session message."
    }
  ]
}
```

**With media attachment:**

```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "messageType": "CHAT",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "messageText": "Here is the document you requested.",
      "media": {
        "url": "https://example.com/document.pdf",
        "caption": "Monthly Report"
      }
    }
  ]
}
```

## SMS fallback

Automatically send an SMS when the WhatsApp recipient cannot be reached. Add the `fallback` object to any WhatsApp message. There are two modes:

- **Auto fallback** — uses the resolved WhatsApp template text as the SMS body
- **Manual fallback** — overrides with your own custom SMS text


### Auto fallback

The system converts your WhatsApp template text into the SMS body automatically:

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "seasonal_promo_text",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "components": [
          {
            "type": "body",
            "parameters": ["John"]
          }
        ]
      }
    ],
    "fallback": {
      "sendFallback": true,
      "unicode": false
    }
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "seasonal_promo_text",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "body",
          "parameters": ["John"]
        }
      ]
    }
  ],
  "fallback": {
    "sendFallback": true,
    "unicode": false
  }
}
```

### Manual fallback

Override the SMS text with a custom message using the `text` field:

Unified Endpoint
```json
POST /whatsapp-api-service/v2/messages

{
  "channel": "WHATSAPP",
  "payload": {
    "sender": "+27123456789",
    "templateName": "seasonal_promo_text",
    "templateId": "your-template-uuid",
    "messageType": "NOTIFICATION",
    "messages": [
      {
        "recipients": [{ "to": "+27987654321" }],
        "components": [
          {
            "type": "body",
            "parameters": ["John"]
          }
        ]
      }
    ],
    "fallback": {
      "sendFallback": true,
      "text": "Hi John, your order is ready. Check the app for details.",
      "unicode": true
    }
  }
}
```

WhatsApp Endpoint
```json
POST /whatsapp-api-service/v2/channels/whatsapp

{
  "sender": "+27123456789",
  "templateName": "seasonal_promo_text",
  "templateId": "your-template-uuid",
  "messageType": "NOTIFICATION",
  "messages": [
    {
      "recipients": [{ "to": "+27987654321" }],
      "components": [
        {
          "type": "body",
          "parameters": ["John"]
        }
      ]
    }
  ],
  "fallback": {
    "sendFallback": true,
    "text": "Hi John, your order is ready. Check the app for details.",
    "unicode": true
  }
}
```

### Fallback fields

| Field | Type | Description |
|  --- | --- | --- |
| `sendFallback` | boolean | **Required.** `true` to enable SMS fallback |
| `text` | string | Custom SMS text. If omitted (auto mode), the resolved WhatsApp template text is used |
| `unicode` | boolean | `false` = GSM 7-bit (160 chars/part), `true` = Unicode (70 chars/part) |


When does fallback trigger?
SMS fallback activates when the recipient's number is **not registered on WhatsApp**. It does not trigger for messages that fail after being accepted by WhatsApp (e.g., template rejection, rate limits).

## Template components reference

| Component | Type | Required when | Example |
|  --- | --- | --- | --- |
| `body` | Text parameters `["val1", "val2"]` | Template has `{{n}}` placeholders | `{"type": "body", "parameters": ["John"]}` |
| `header` | Media with `format` + `url` | Template has a media header | `{"type": "header", "format": "IMAGE", "url": "..."}` |
| `button` | Button parameters | Template has dynamic buttons | `{"type": "button", "parameters": ["Yes"]}` |
| `carousel` | Array of `cards` | Template is a carousel | `{"type": "carousel", "cards": [...]}` |


## Response

All messaging endpoints return **202 Accepted** on success:

```json
{
  "response": "Request Accepted for Processing",
  "batchId": "batch-uuid",
  "reqObject": { "..." : "..." }
}
```

Track delivery
A `202` means the message is queued — not yet delivered. Use [Webhooks](/guides/webhooks) or the Message Reports API to track the full delivery lifecycle: `ACCEPTED` > `SENT` > `DELIVERED` > `READ`.

## Production tips

- **Always set `ctId`** on recipients for end-to-end message tracking through your system
- **Validate recipient identifiers** — a phone number in international format (leading `+` optional, never a leading `0`), a `customerUserId` (BSUID), or both. A recipient addressed by `customerUserId` alone needs no phone number.
- **Use SMS fallback** for critical notifications where delivery matters more than channel
- **Batch recipients** into a single API call (up to the batch limit) rather than making individual calls
- **Monitor delivery rates** via the Analytics API and investigate any drop in delivery percentages