Skip to main content
Every template has a body. The formats on this page add something around it: a row of cards, a moving header, a button that starts a WhatsApp call, or a limit on how long WhatsApp keeps trying to deliver. You can build all of them in the console under Templates → New template, or with POST /v1/templates.

Header samples

Meta reviews a sample of every image, video, GIF and document header. Upload it first, then pass the returned handle:
Use the handle as header.example_handle, or carousel_cards[].example_handle for a card. The sample is only for review. You send the real media when you send the template. Or skip the upload: give a public https URL as header.example_url (or carousel_cards[].example_url) on POST /v1/templates, and LazyApp fetches the file and uploads it for you. That makes a media template one JSON call, which suits setup scripts and manifests.
A URL that cannot be fetched, or returns the wrong type or too large a file, is a 422 on header.example_url. Limits: JPEG or PNG images, MP4 video and PDF documents up to 16 MB. A GIF is an MP4 of up to 3.5 MB.

Carousels

A carousel is a row of cards the contact swipes through. Every card has the same layout: the same header type and the same button types in the same order. Meta rejects carousels whose cards differ.
  • Media carousels take 2 to 10 cards with header_format IMAGE or VIDEO. Card buttons are QUICK_REPLY, URL or PHONE_NUMBER, at most two per card.
  • Product carousels use header_format: "PRODUCT" and one SPM (view product) or URL button per card. Meta takes exactly 2 cards when you create one. When you send, you can show up to 10 products. Your connection needs a catalog.
When you send a carousel, pass each card’s media or product under template.features.cards. A template’s send_features lists exactly what a send needs. Campaigns and the inbox show one field per card.

GIF headers

header.format: "GIF" shows a short looping animation. It is a marketing-only format that Meta delivers through the Marketing Messages API. Upload the sample with format=GIF. The file is an MP4 of up to 3.5 MB.

Call on WhatsApp buttons

A VOICE_CALL button lets the contact start a WhatsApp call to your number straight from the message. Your number needs calling turned on.
ttl_minutes sets how long the button works after delivery, from 1 day (1440) to 30 days (43200). Meta’s default is 7 days.

Call permission requests

A call permission request asks the contact whether you may call them on WhatsApp. If they agree, you can call them for a limited time without them calling first.
Meta adds the Allow and Decline choices itself, so these templates have a body only: no header and no buttons. Marketing and utility templates both work. The contact’s answer reaches you as a call.permission_request webhook.

Delivery time limit

If a phone is off, WhatsApp keeps trying to deliver for up to 30 days. That is fine for a newsletter. For a login code or a “your driver is outside” message, a late delivery confuses people. Set message_send_ttl_seconds and WhatsApp stops trying after that time: -1 means 30 days for authentication and utility templates. If Meta moves your template to another category, LazyApp clears the time limit so it never falls outside the new range.

Open your app from a button

Marketing URL buttons can open your Android app first. If the app is not installed, the contact goes to the Play Store or to the link.

Template library

Meta keeps a library of ready-made utility and authentication templates, such as order and delivery updates. Library templates are approved straight away because Meta wrote the wording.
Create one by name. Meta takes the wording from the library, so body_text is not needed:
In the console, open Templates → New template and pick Ready-made.

Sending these formats

Send any of these with POST /v1/messages and type: "template". Body and header values go in template.components, as in any template send. The extra inputs these formats need go in template.features, and LazyApp builds the matching components for you. Each template’s send_features (on GET /v1/templates/{template}) lists the ones it needs.
A GIF header takes a header component of type gif: { "type": "header", "parameters": [{ "type": "gif", "gif": { "link": "https://acme.example/sale.mp4" } }] }. The console, campaigns and the inbox ask for the link and build this for you.