Template messages

Sending template messages

Templates are the only way to start a conversation or message a customer outside the 24-hour window — Meta requires a pre-approved template for any business-initiated message. You send one through POST /send-template, naming an approved template and filling its variables in order.

This page covers listing your approved templates and sending them. To author and submit templates for approval, see Creating templates; to send one template to many recipients, see Broadcasts.


List approved templates

Before sending, fetch the approved templates on a channel so you know each template's exact name, language, and how many variables it expects. GET /channels/{id}/templates returns approved templates only, each with a variables array whose entries carry the positional index of every {{n}} placeholder in the template.

curl https://api.telenow.ai/api/app-whatsapp/channels/b1e2c3d4-…/templates \
  -H "Authorization: Bearer vai_app_…"
{
  "success": true,
  "data": {
    "templates": [
      {
        "name": "order_update",
        "language": "en_US",
        "category": "UTILITY",
        "variables": [ { "index": 1 }, { "index": 2 } ]
      },
      {
        "name": "welcome",
        "language": "en_US",
        "category": "MARKETING",
        "variables": []
      }
    ]
  }
}

The length of variables is how many strings you must pass — order_update above takes two, welcome takes none.

Send a template

POST /send-template takes { channelId, to, template, language?, variables }. language defaults to en_US; variables is a positional array of strings that fill {{1}}, {{2}}, … in order. A successful send returns the wamid, just like /send.

curl -X POST https://api.telenow.ai/api/app-whatsapp/send-template \
  -H "Authorization: Bearer vai_app_…" \
  -H "Content-Type: application/json" \
  -d '{
    "channelId": "b1e2c3d4-…",
    "to": "+919876543210",
    "template": "order_update",
    "language": "en_US",
    "variables": ["Asha", "#1234"]
  }'
{ "success": true, "data": { "wamid": "wamid.HBgLMTQxNTU1MDEwMBUCABIYFj…" } }
FieldNotes
channelIdThe channel id from GET /channels
toRecipient in E.164, e.g. +919876543210
templateApproved template name
languageOptional; defaults to en_US. Must match the template's language
variablesPositional strings that fill {{1}}, {{2}}, … in order — supply exactly as many as the template's variables array

If the count or order is wrong you'll get an actionable 400 in the 132000–132999 range (template problem). Fetch the template again to confirm its variable count.

Templates with a media header or dynamic buttons

A template whose header is an image/video/document, or that has a dynamic URL button, needs richer per-message data than a flat variables array can carry. For these, pass a components array instead — this is Meta's runtime component format, where each object targets a template part (header, body, button) and lists its parameters.

For a media header, first upload the asset with POST /channels/{id}/media to get a mediaId, then put that mediaId in the header parameter. Telenow translates it into WhatsApp's own media id at send time — you never handle a raw Meta media handle here.

# 1) Upload the header image → mediaId
curl -X POST https://api.telenow.ai/api/app-whatsapp/channels/b1e2c3d4-…/media \
  -H "Authorization: Bearer vai_app_…" \
  -F "file=@/path/to/receipt.png"
{ "success": true, "data": { "mediaId": "med_9f2a…", "mime": "image/png", "filename": "receipt.png", "bytes": 84213 } }
# 2) Send the template, referencing that mediaId in the header component
curl -X POST https://api.telenow.ai/api/app-whatsapp/send-template \
  -H "Authorization: Bearer vai_app_…" \
  -H "Content-Type: application/json" \
  -d '{
    "channelId": "b1e2c3d4-…",
    "to": "+919876543210",
    "template": "order_receipt",
    "language": "en_US",
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "id": "med_9f2a…" } }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Asha" }
        ]
      }
    ]
  }'
{ "success": true, "data": { "wamid": "wamid.HBgLMTQxNTU1MDEwMBUCABIYFj…" } }
  • Use components instead of variables — put your body substitutions in the body component's parameters, not in a separate variables array.
  • For a video or document header, swap the parameter to { "type": "video", "video": { "id": "<mediaId>" } } or { "type": "document", "document": { "id": "<mediaId>" } }.
  • For a dynamic URL button, add a button component, e.g. { "type": "button", "sub_type": "url", "index": 0, "parameters": [ { "type": "text", "text": "1234" } ] } — the text fills the {{1}} in the button's URL.