# 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](/docs/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`](/docs/api/callbacks/template-status) callback. Delete one language,
or all of them, with [Delete template](/docs/api/delete-template).

## List them

[`GET /businesses/{external_id}/whatsapp/templates?status=APPROVED`](/docs/api/list-templates)

```json
{
  "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`](/docs/api/callbacks/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:

```json
{
  "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](/docs/api/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](/docs/api/list-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](/docs/api/create-template-from-library)
copies one with the business's name and submits it to Meta.
