> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pilotstatus.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Reusable Message Templates and Variables in Pilot Status

> Create reusable message templates with dynamic variables in Pilot Status. Official API requires Meta approval; unofficial API supports free-form templates.

Templates define reusable message content. Create and manage them in the dashboard (`/templates`), via the REST API (`/v1/templates`), or through the MCP server (`templates_create` / `templates_update` / `templates_delete`). When sending, reference the template by `templateId` in `POST /v1/messages/send` and pass a `variables` object with matching keys.

## Categories

The category is set at creation time and **cannot be changed later**:

* **MARKETING** — promotional messages (most sensitive to WhatsApp policies).
* **UTILITY** — transactional messages (account updates, alerts, reminders).
* **OTP** — one-time / verification code messages.

## Meta approval vs. local templates

* **Official (Meta) numbers:** when you save a template with a Meta number selected, the dashboard asks whether to **submit it to Meta for review** now or keep it as a draft and submit later. Once submitted, category, language, and approval status follow Meta's rules. A template is only sendable on a Meta number after it has an **approved** version.
* **Unofficial numbers (Evolution):** templates are created locally and are **immediately usable** — there is no approval step.

Templates returned by `GET /v1/templates` carry a `source` field (where the template came from), a `metaStatus` field (Meta review status, e.g. `PENDING`, `APPROVED`, `REJECTED`), and a `sendable` flag indicating whether it can be used for sends right now.

## Template structure

Only **body** is required.

| Component   | Required     | What it is                                                                                                                                 |
| ----------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Header**  | optional     | Text (≤60 chars, ≤1 variable) or one media item (`IMAGE` JPG/PNG, `VIDEO` MP4, `DOCUMENT` PDF).                                            |
| **Body**    | **required** | Main text (≤1024 chars) with `{{variable}}` placeholders.                                                                                  |
| **Footer**  | optional     | Static text ≤60 chars, no variables.                                                                                                       |
| **Buttons** | optional     | Up to 10 buttons: `QUICK_REPLY` (≤10), `URL` (≤2), `PHONE_NUMBER` (≤1, E.164 with country code), `COPY_CODE` (≤1, alphanumeric ≤15 chars). |

Media header values: via REST pass `header.url` (public http(s) URL) **or** `header.base64` (data URI, re-hosted server-side automatically). Via MCP only `header.url` is accepted.

<Note>
  There is no `LOCATION` header. Also not supported: `FLOW`, `CAROUSEL`, `CATALOG`/`MPM`, `LIMITED_TIME_OFFER`, OTP autofill/one-tap/zero-tap, `VOICE_CALL` buttons, and the `NAMED` `parameter_format`.
</Note>

## Variable rules

* Write variables as `{{name}}` in the body, text header, and dynamic URL buttons (e.g. `https://shop.com/promo/{{link}}` — one variable, at the **end** of the URL, never in the domain).
* The body **must not start or end with a variable** — always include literal text at both ends.
* When creating/updating via API or MCP, an `examples` object mapping **every** variable to a real sample value is **required**. Missing samples return `400 TEMPLATE_EXAMPLES_REQUIRED` with the missing keys in `details.missing`.
* The copy-code value is the one exception: it goes on the button as `example` (e.g. `["PROMO10"]`), not in top-level `examples`.
* **When sending**, every placeholder — including keys used only in buttons — must be supplied in `variables`, and each value must be a **non-empty string**.

## Text formatting

WhatsApp formatting markers work in the body: `*bold*`, `_italic_`, `~strikethrough~`, `monospace`. The **text header does not allow** formatting markers, emojis, or line breaks.

## Templates API

<CodeGroup>
  ```bash Create theme={null}
  curl -X POST "https://pilotstatus.com.br/v1/templates" \
    -H "x-api-key: ps_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "promo_coupon",
      "category": "MARKETING",
      "language": "pt_BR",
      "body": {
        "header": { "type": "IMAGE", "url": "https://cdn.example.com/banner.png" },
        "body":   { "text": "Hi {{name}}! Use it and get {{discount}} off." },
        "footer": { "text": "Limited-time offer" },
        "buttons": [
          { "type": "QUICK_REPLY",  "text": "I want it!" },
          { "type": "URL",          "text": "Buy", "url": "https://shop.com/promo/{{link}}" },
          { "type": "COPY_CODE",    "example": ["PROMO10"] }
        ]
      },
      "examples": { "name": "Maria", "discount": "10%", "link": "abc123" }
    }'
  ```

  ```bash Update theme={null}
  curl -X PUT "https://pilotstatus.com.br/v1/templates/tmpl_123" \
    -H "x-api-key: ps_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{ "body": { "body": { "text": "Hi {{name}}! New copy here." } }, "examples": { "name": "Maria" } }'
  ```

  ```bash Delete theme={null}
  curl -X DELETE "https://pilotstatus.com.br/v1/templates/tmpl_123" \
    -H "x-api-key: ps_your_key_here"
  ```
</CodeGroup>

A successful create returns `201`:

```json theme={null}
{ "id": "tmpl_123", "name": "promo_coupon", "category": "MARKETING", "metaStatus": "PENDING" }
```

After publishing a version, `GET /v1/templates/{id}` returns all detected variable keys in `latestVersion.variables`.

## Common submission and send errors

| Situation                                                         | Fix                              | Meta code     |
| ----------------------------------------------------------------- | -------------------------------- | ------------- |
| Body starts/ends with a variable                                  | Add literal text at both ends    | `2388299`     |
| URL button on a placeholder domain (example.com, yourdomain.com…) | Use your real business domain    | `368/1346003` |
| Call button phone without country code                            | Use E.164, e.g. `+5521999998888` | `192`         |
| Too many variables relative to fixed text                         | Add wording or drop variables    | `2388293`     |
| Sending a template not yet approved by Meta                       | Wait for approval                | `131053`      |
| Variables sent don't match the approved template                  | Send every expected key          | `132000`      |
| Template paused by Meta for quality drop                          | Improve content, reduce reports  | `132015`      |

A `404` when sending means the template does not exist for the key or — on a Meta number — it has no approved version yet.

## Related

* [Send Messages](/guides/send-messages)
* [Media Messages](/guides/media-messages)
