Common workflows
Templates
Find approved templates and fill in their parameters.
In a nutshell
Create templates through the API (Meta reviews them) or in WhatsApp Manager; PaalChat mirrors them. List the APPROVED ones, count the {{n}} placeholders and send one parameter per placeholder.
Where templates come from
A template is a message format Meta has reviewed. Create it through the API
(Create template) or in Meta's WhatsApp Manager - PaalChat
syncs every template of the account and keeps its status current. A new template is
PENDING until Meta decides; the decision arrives as a
template.status callback. Delete one language,
or all of them, with Delete template.
List them
GET /businesses/{external_id}/whatsapp/templates?status=APPROVED
{
"data": [
{
"name": "fees_reminder",
"language": "en_US",
"category": "UTILITY",
"status": "APPROVED",
"rejection_reason": null,
"components": [
{"type": "BODY", "text": "Dear {{1}}, the fees balance for {{2}} is GHS {{3}}. Please pay before {{4}}.",
"example": {"body_text": [["Mrs Mensah", "Kofi", "450.00", "30 October"]]}}
],
"waba_id": "102290129340398",
"last_synced_at": "2026-09-30T17:54:27+00:00"
}
]
}
Filters: status, name, language. 100 per page. Cache the list and refresh it
when a template.status callback arrives.
Fill in the parameters
components are exactly what Meta returns. For each component with {{n}}
placeholders, send one parameter per placeholder, in order:
| Template component | Send |
|---|---|
HEADER with {{1}} (text) |
{"type": "header", "parameters": [{"type": "text", "text": "..."}]} |
BODY with {{1}}..{{n}} |
{"type": "body", "parameters": [{"type": "text", "text": "..."}, ...]} |
BUTTONS → URL button with {{1}} |
{"type": "button", "sub_type": "url", "index": "0", "parameters": [{"type": "text", "text": "..."}]} |
| No placeholders | Send no component for it |
For fees_reminder above:
{
"to": "+233241234567", "type": "template", "reference": "notification-4411",
"template": {"name": "fees_reminder", "language": "en_US", "components": [
{"type": "body", "parameters": [
{"type": "text", "text": "Mrs Mensah"}, {"type": "text", "text": "Kofi"},
{"type": "text", "text": "450.00"}, {"type": "text", "text": "30 October"}]}]}
}
Tip
Count placeholders with a regular expression such as /\{\{\d+\}\}/g on each
component's text, and validate your parameters before sending. A mismatch fails
at Meta with error 132000.
Template status
| Status | Can send? |
|---|---|
APPROVED |
Yes |
PENDING, IN_APPEAL |
Not yet |
REJECTED (see rejection_reason), PAUSED, DISABLED, FLAGGED, LIMIT_EXCEEDED, ARCHIVED, DELETED |
No - 422 template_not_approved |
When a template is rejected or paused, stop offering it. The customer edits it in
WhatsApp Manager, and an APPROVED callback follows when Meta approves.
Versions and history
Every change to a template's content is kept as a version -
List template versions shows what each said and Meta's
decision on it. A template deleted at Meta (through the API or WhatsApp Manager) is kept
with status REMOVED; list it with include_removed=1. Nothing is ever deleted from the
history.
Checked before sending
PaalChat checks a send against the template before Meta sees it: every body and header
variable needs a value (named templates: parameter_name), a media header needs its image,
video or document, and a URL button with a variable needs its value. Values may not contain
new lines, tabs or more than four spaces in a row. Otherwise the send is refused with
422 invalid_template_parameters, listing what is wrong.
Starter templates
The template library has ready-made templates for schools (fee reminder, results, PTA meeting, absence, admission offer) and shops (order confirmed, receipt, delivery update). Create template from library copies one with the business's name and submits it to Meta.