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…" } }
| Field | Notes |
|---|---|
channelId | The channel id from GET /channels |
to | Recipient in E.164, e.g. +919876543210 |
template | Approved template name |
language | Optional; defaults to en_US. Must match the template's language |
variables | Positional 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
400in the132000–132999range (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
componentsinstead ofvariables— put your body substitutions in thebodycomponent'sparameters, not in a separatevariablesarray. - 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
buttoncomponent, e.g.{ "type": "button", "sub_type": "url", "index": 0, "parameters": [ { "type": "text", "text": "1234" } ] }— the text fills the{{1}}in the button's URL.
Related
- Creating templates — author, submit for approval, and add media headers or dynamic buttons.
- Broadcasts — send a template to many recipients at once.
- Media messages — upload assets and get a
mediaId. - Webhooks & events — track
sent/delivered/read/failedstatus perwamid. - WhatsApp overview — connect a number and find your
channelId.