Send Template Message
Send a WhatsApp message to a contact using an approved message template. This is the primary way to reach contacts — template messages can be sent anytime, even outside the 24-hour customer service window.
POST /api/v1/messages/send
Request body
| Field | Type | Required | Description |
|---|---|---|---|
template_name | string | Yes | Name of your approved template (case-sensitive) |
contact_phone | string | Yes | Phone number with country code, without + (e.g., 911234567890) |
contact_name | string | No | Contact's name. Defaults to User #<random> if omitted |
body_data | object | No | Template body variables as key-value pairs. Defaults to empty {}. Required if your template has variables like {{1}}, {{2}} |
header_data | object | No | Header variables — only needed for templates with a text header that contains variables |
media_url | string | No | Publicly accessible URL for image, video, or document. Required if template has a media header |
filename | string | No | Filename for document attachments (defaults to untitled) |
waba_phone_id | string | No | Which WhatsApp number to send from (uses your default number if omitted) |
If the contact phone number doesn't exist in your Waplify account, the contact will be created automatically when you send the message. The source will be set to api.
Understanding template variables
Templates use placeholders like {{1}}, {{2}} for personalized content. You fill these in via body_data when sending.
How to know which variables your template needs:
- Call the List Templates endpoint
- Look at the
bodyfield — it shows the template text with placeholders - Look at
header_format— if it'sIMAGE,VIDEO, orDOCUMENT, you need amedia_url - Look at
requires_media— iftrue, amedia_urlis required
Variable types
Positional variables (most common): {{1}}, {{2}}, {{3}}
Pass them as string keys:
{
"body_data": { "1": "John", "2": "Premium Plan", "3": "99" }
}
Named variables: {{name}}, {{company}}, {{amount}}
Pass them with the exact key name (case-sensitive):
{
"body_data": { "name": "John", "company": "Acme Corp", "amount": "99" }
}
Examples
Basic template (body variables only)
- curl
- JavaScript
- Python
curl -X POST https://server.waplify.io/api/v1/messages/send \
-H "Authorization: Bearer wapl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_name": "order_confirmation",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {
"1": "John",
"2": "Premium Plan",
"3": "99"
}
}'
const response = await fetch("https://server.waplify.io/api/v1/messages/send", {
method: "POST",
headers: {
"Authorization": "Bearer wapl_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
template_name: "order_confirmation",
contact_phone: "911234567890",
contact_name: "John Doe",
body_data: { "1": "John", "2": "Premium Plan", "3": "99" },
}),
});
const data = await response.json();
console.log(data);
import requests
response = requests.post(
"https://server.waplify.io/api/v1/messages/send",
headers={"Authorization": "Bearer wapl_your_api_key"},
json={
"template_name": "order_confirmation",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {"1": "John", "2": "Premium Plan", "3": "99"},
},
)
print(response.json())
Template with text header variables
curl -X POST https://server.waplify.io/api/v1/messages/send \
-H "Authorization: Bearer wapl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_name": "daily_report",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"header_data": {
"1": "Daily Checkup"
},
"body_data": {
"1": "Rahul"
}
}'
Template with image header
curl -X POST https://server.waplify.io/api/v1/messages/send \
-H "Authorization: Bearer wapl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_name": "promo_image",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {
"1": "John",
"2": "50%"
},
"media_url": "https://example.com/promo-banner.png"
}'
Template with video header
curl -X POST https://server.waplify.io/api/v1/messages/send \
-H "Authorization: Bearer wapl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_name": "product_video",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {
"1": "John"
},
"media_url": "https://example.com/product-demo.mp4"
}'
Template with document header
curl -X POST https://server.waplify.io/api/v1/messages/send \
-H "Authorization: Bearer wapl_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"template_name": "invoice_template",
"contact_phone": "911234567890",
"contact_name": "John Doe",
"body_data": {
"1": "John"
},
"media_url": "https://example.com/invoice-june.pdf",
"filename": "Invoice June 2024.pdf"
}'
Success response
{
"status": "success",
"message": "Message sent successfully",
"message_id": "wamid.HBgNOTE4MDMxMjM0NTY3OA==",
"contact_id": "507f1f77bcf86cd799439012",
"template_name": "order_confirmation",
"timestamp": "2024-06-15T10:00:00Z"
}
| Field | Description |
|---|---|
message_id | WhatsApp's message ID — use this to track delivery via webhooks |
contact_id | The contact's ID in Waplify (created automatically if new) |
timestamp | When the message was accepted (ISO 8601 format) |
A "status": "success" response does not mean the message has been delivered to the contact's phone. It only means WhatsApp has accepted your message and will attempt to deliver it.
What happens after a successful response:
- API returns
success→ WhatsApp accepted the message message.sentwebhook → WhatsApp started processing the messagemessage.deliveredwebhook → Message reached the contact's phonemessage.readwebhook → Contact opened and read the message
If delivery fails at any point, you receive a message.failed webhook with the error details.
To track actual delivery, set up webhooks and listen for the message.delivered event. Do not assume a success API response means the message was delivered.
Error responses
Missing template variables
// 400 Bad Request
{
"error": "bad_request",
"message": "Missing body variables in 'body_data': 2, 3"
}
Template not approved
// 400 Bad Request
{
"error": "bad_request",
"message": "Template 'my_template' is not approved. Status: PENDING"
}
Template not found
// 404 Not Found
{
"error": "not_found",
"message": "Template 'nonexistent_template' not found"
}
Media required but not provided
// 400 Bad Request
{
"error": "bad_request",
"message": "Media URL is required for this template"
}
Invalid phone number
// 400 Bad Request
{
"error": "bad_request",
"message": "Invalid phone number format"
}
Media file limits
| Type | Max Size | Accepted Formats |
|---|---|---|
| Image | 5 MB | JPEG, PNG |
| Video | 16 MB | MP4 |
| Document | 100 MB | PDF, DOC, DOCX, PPT, PPTX, TXT |