WhatsApp templates
Start or resume a WhatsApp conversation with an approved template.
WhatsApp only lets a business message a customer freely within 24 hours of the customer's last message. Outside that window, the first message must be a template that Meta has approved. Use templates for notifications such as order updates, reminders and one-time codes, and to re-open a conversation.
Endpoint: POST /v2/wa/template, scope message:send.
POST /v1/wa/template takes the same body but returns failures as an opaque 500. It still
works but is deprecated; use v2.
Request
{
"channelId": "3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a6c19",
"to": "249912345678",
"template": {
"name": "order_update",
"language": { "policy": "deterministic", "code": "en" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Ahmed" },
{ "type": "text", "text": "#10234" }
]
}
]
}
}channelId: copy it from your WhatsApp channel's card on the dashboard's Channels page.to: the recipient's number in international format, digits only, no+.template.nameandtemplate.language.code: exactly as approved in WhatsApp Manager.language.policyis alwaysdeterministic.template.components: values for the template's variables, in order. Leave it out for a template without variables.
The first send to a number creates the contact and its conversation in Enigma, so replies show up in your inbox and on your webhook.
Components
Header, body and footer
Each {{n}} variable takes one parameter, in order.
Parameter type | Fields |
|---|---|
text | text |
currency | currency: { fallback_value, code, amount_1000 }. amount_1000 is the amount × 1000. |
date_time | date_time: { fallback_value } |
image, video, document, audio | an object of the same name with link (public HTTPS URL) or id (WhatsApp media ID), plus optional caption and filename |
A template with an image header:
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://example.com/banner.jpg" } }
]
}Buttons
Buttons that need values take a button component per button. index is the button's
zero-based position in the template.
sub_type | Parameter |
|---|---|
quick_reply | { "type": "payload", "payload": "…" }, returned to you when tapped |
url | { "type": "text", "text": "…" }, appended to the template's dynamic URL |
copy_code | { "type": "coupon_code", "coupon_code": "…" } |
flow | { "type": "action", "action": { "flow_token": "…", "flow_action_data": { } } } |
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [{ "type": "text", "text": "10234" }]
}Response
201 means WhatsApp accepted the message:
{
"success": true,
"messageId": "wamid.HBgLMjQ5OTEyMzQ1Njc4FQIAERgS",
"timestamp": "2026-10-10T08:45:35.000Z"
}Keep messageId: the message_status webhook reports delivered, read or
failed against it.
If the send fails, the response says why. 402 means not enough credits; 502 means WhatsApp
rejected it, with the WhatsApp error code in errorDetails.code. See Errors.