Skip to content
Last updated

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:

FieldTypeDescription
tostringRecipient phone number in international format, country code first, leading + optional (+27821234567 or 27821234567). Must not start with 0. Required unless customerUserId is supplied
customerUserIdstringRecipient 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
ctIdstringClient-defined tracking id, echoed back in delivery receipts and webhooks
gstIdstringeCommunicate 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 for setup and security best practices.


Endpoints

MethodEndpointDescription
POST/whatsapp-api-service/v2/messagesUnified endpoint — routes to WhatsApp or SMS based on channel
POST/whatsapp-api-service/v2/channels/whatsappWhatsApp-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 for the request shape, and How the system fits together for the full architecture.


Message types

TypeValueWhen to use
NotificationNOTIFICATIONOutbound template messages — requires approved templateName and templateId
ChatCHATFree-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

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"]
          }
        ]
      }
    ]
  }
}

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


Media template

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
    }
  }
}

Supported header formats: DOCUMENT, IMAGE, VIDEO


Call to action

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" }
            ]
          }
        ]
      }
    ]
  }
}
  • conversationState: "start" — keeps the conversation open for follow-up
  • conversationState: "end" — closes the conversation when this button is tapped

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"] }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

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


Chat message

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:

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"
        }
      }
    ]
  }
}

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:

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
    }
  }
}

Manual fallback

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

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
    }
  }
}

Fallback fields

FieldTypeDescription
sendFallbackbooleanRequired. true to enable SMS fallback
textstringCustom SMS text. If omitted (auto mode), the resolved WhatsApp template text is used
unicodebooleanfalse = 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

ComponentTypeRequired whenExample
bodyText parameters ["val1", "val2"]Template has {{n}} placeholders{"type": "body", "parameters": ["John"]}
headerMedia with format + urlTemplate has a media header{"type": "header", "format": "IMAGE", "url": "..."}
buttonButton parametersTemplate has dynamic buttons{"type": "button", "parameters": ["Yes"]}
carouselArray of cardsTemplate is a carousel{"type": "carousel", "cards": [...]}

Response

All messaging endpoints return 202 Accepted on success:

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

A 202 means the message is queued — not yet delivered. Use 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