Skip to content

Send a template with media and buttons

The richest message you can send to any customer, even outside the 24-hour window, is a template that combines a media header, body text, a footer and buttons. Product launches, offers, tickets and invoices commonly use it.

This page goes end to end: create the template, wait for approval, then send it.

Terminal window
curl -X POST "$HELLO_API_URL/v1/<your-waba-id>/templates" \
-H "Authorization: Bearer $HELLO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "new_arrival_offer",
"language": "en",
"category": "MARKETING",
"components": [
{
"type": "HEADER",
"format": "IMAGE",
"example": { "header_handle": ["https://example.com/samples/sneaker.jpg"] }
},
{
"type": "BODY",
"text": "Hi {{1}}, the {{2}} just landed. Get 15% off this week only.",
"example": { "body_text": [["Asha", "Runner 2"]] }
},
{ "type": "FOOTER", "text": "Reply STOP to opt out" },
{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "Shop now", "url": "https://example.com/new-arrivals" },
{ "type": "QUICK_REPLY", "text": "Not interested" }
]
}
]
}'

The response is Meta’s { id, status, category }, with "status": "PENDING". Keep the id.

Terminal window
curl "$HELLO_API_URL/v1/templates/$TEMPLATE_ID" \
-H "Authorization: Bearer $HELLO_API_KEY"

Send once status is APPROVED. If it’s REJECTED, rejected_reason says what to change.

Each send supplies the header image and the body variables. The footer and buttons come from the template.

Terminal window
curl -X POST "$HELLO_API_URL/v1/<your-phone-number-id>/messages" \
-H "Authorization: Bearer $HELLO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+919999999999",
"type": "template",
"template": {
"name": "new_arrival_offer",
"language": { "code": "en" },
"components": [
{
"type": "header",
"parameters": [
{ "type": "image", "image": { "link": "https://example.com/catalog/runner-2-red.jpg" } }
]
},
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Asha" },
{ "type": "text", "text": "Runner 2" }
]
}
]
}
}'
{
"messaging_product": "whatsapp",
"contacts": [{ "input": "+919999999999", "wa_id": "919999999999" }],
"messages": [{ "id": "9e8d7c6b-5a4f-4e3d-8c2b-1a0f9e8d7c6b", "message_status": "queued" }]
}

To send the same image to many people, upload it once and use "image": { "id": "<media_id>" } instead of link. WhatsApp then doesn’t fetch the file for every message.

Video header. Create the template with "format": "VIDEO" and send { "type": "video", "video": { "link": "https://…/launch.mp4" } }.

Document header with buttons, for example an invoice with a “Pay now” link:

{
"type": "header",
"parameters": [
{
"type": "document",
"document": { "link": "https://example.com/invoices/INV-2291.pdf", "filename": "INV-2291.pdf" }
}
]
}

Call button. Add { "type": "PHONE_NUMBER", "text": "Call us", "phone_number": "+919812345678" } to the template’s buttons. Nothing changes in the send request.

Dynamic URL or copy-code button. Add a button component to the send — see Buttons.