Skip to main content
WhatsApp permits free-form messages only within 24 hours of the customer’s last inbound message. Outside it — a broadcast, an order update, a payment reminder, anyone who has never written to the merchant — only an approved template may be sent. So a partner running campaigns needs to create and track templates without a merchant logging into anything.
Reading takes channels:read; creating and deleting take channels:write.

Listing

Returns Meta’s own payload — data[] with each template’s name, status, category, language, components and, when it was refused, rejected_reason. Pass phone_number_id when a merchant holds numbers on more than one WhatsApp Business Account: templates belong to the WABA, not to the merchant.

Creating

string
required
UTILITY, MARKETING or AUTHENTICATION. This is what you are billed on, and Meta re-categorises templates it thinks are miscategorised — a marketing message dressed as a utility one gets moved, and priced accordingly.
string
required
Positional placeholders, {{1}} upward. Every one of them needs a matching entry in example_body_params or Meta rejects the template outright.
201 with Meta’s response, including the template id and its initial status — almost always PENDING. A template Meta refuses at submission comes back 400 carrying their validation error verbatim rather than a flattened one, because their message names the component that was wrong.

Approval is asynchronous, and slow

A 201 does not mean you can send it. Review takes minutes at best and hours routinely. A campaign scheduled against a template created moments earlier will fail at send time with a channel_rejected naming the template.
The outcome arrives as a webhook:
status is APPROVED, REJECTED, PAUSED or DISABLED. A template can move after approval: Meta pauses one whose recipients repeatedly block or report the sender, and disables it if that continues. Treat PAUSED as a signal about the message, not a glitch — it means people did not want it. Store the status against your own copy and check it before scheduling, rather than listing templates on every send.

Sending one

Templates are sent through the ordinary message routes, addressed either to a thread or straight to a number:
Positional, in {{1}}, {{2}} order. See Conversations and messaging a number with no thread.

Deleting

Meta deletes by name, which removes every language version of it. Anything still scheduled against that template starts failing at send time rather than here, so delete deliberately.

What to build

Store each template’s status locally and update it from template.status_changed. Listing templates before every send costs a Graph call per broadcast and tells you nothing new between approvals.
UTILITY is cheaper than MARKETING, which is why every platform sees merchants labelling promotions as order updates. Meta re-categorises, bills the corrected category, and a merchant whose templates keep being moved attracts quality review. Label it as what it is.
A merchant’s first contact with a customer is always a template. Free-form replies only become available once the customer answers — which is what the 24-hour window in every conversation payload tells you.