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

# WhatsApp Templates API

> Create, update, fetch, list, and delete WhatsApp message templates bound to a WhatsApp Business Account.

<Info title="TL;DR">
  Submit, fetch, list, update, and delete WhatsApp message templates for a WhatsApp Business Account (WABA) linked to your Plivo account. See the [WhatsAppTemplate object](#the-whatsapptemplate-object) for the resource schema. Templates start in `PENDING`; Meta reviews them asynchronously and emits status events that Plivo forwards to your configured WABA webhook URL.
</Info>

Use this API to manage WhatsApp templates programmatically as an alternative to the [WhatsApp Manager UI](/messaging/concepts/whatsapp/manage-templates/). All operations are scoped to a single WABA identified by `waba_id`.

**API Endpoint**

```http theme={null}
https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/
```

<Info>
  Find your `waba_id` in the [Plivo console](https://cx.plivo.com/home) under **Messaging > WhatsApp Business Account**.
</Info>

**Authentication**

All endpoints use HTTP Basic Auth. Use your Plivo `auth_id` as the username and `auth_token` as the password. Find these on the [Plivo console](https://cx.plivo.com/home).

**Asynchronous review**

When you create or update a template, Meta reviews it asynchronously. The template's status moves from `PENDING` to `APPROVED`, `REJECTED`, `PAUSED`, or `DISABLED` over time. Meta emits an event for each transition, which Plivo forwards to the webhook URL configured for your WABA. You can also call [Get a Template](#get-a-template) or [List Templates](#list-templates) at any time to fetch the current status.

***

## The WhatsAppTemplate Object

### Attributes

<ParamField body="template_id" type="string">
  Meta-issued template ID. Use this in path parameters for Get, Update, and Delete.
</ParamField>

<ParamField body="name" type="string">
  snake\_case template name, unique per WABA. Allowed characters: `a-z`, `0-9`, underscore.
</ParamField>

<ParamField body="language" type="string">
  BCP-47 language code. Examples: `en`, `en_US`, `es_MX`.
</ParamField>

<ParamField body="category" type="string">
  Template category. Values: `MARKETING`, `UTILITY`, `AUTHENTICATION`.
</ParamField>

<ParamField body="status" type="string">
  Current Meta-assigned status. Values: `PENDING`, `APPROVED`, `REJECTED`, `PAUSED`, `DISABLED`.
</ParamField>

<ParamField body="quality_score" type="object">
  Quality metric assigned by Meta. When present, contains a single field `score` with values `GREEN`, `YELLOW`, `RED`, or `UNKNOWN`. May be `null` or absent for templates in `PENDING` status — check for the field before reading `quality_score.score`.
</ParamField>

<ParamField body="rejected_reason" type="string">
  Reason for rejection assigned by Meta. Returned as `NONE` for templates that have not been rejected. Possible values when `status` is `REJECTED`: `ABUSIVE_CONTENT`, `INVALID_FORMAT`, `PROMOTIONAL`, `TAG_CONTENT_MISMATCH`, `INCORRECT_CATEGORY`, `SCAM`.
</ParamField>

<ParamField body="components" type="array">
  Ordered list of template sections. See [Component object](#component-object) below.
</ParamField>

### Component Object

Each item in `components` is a `TemplateComponent`:

<ParamField body="type" type="string">
  Component type. Values: `HEADER`, `BODY`, `FOOTER`, `BUTTONS`, `CAROUSEL`.
</ParamField>

<ParamField body="format" type="string">
  Header format. Only meaningful when `type` is `HEADER`. Values: `TEXT`, `IMAGE`, `VIDEO`, `DOCUMENT`, `LOCATION`.
</ParamField>

<ParamField body="text" type="string">
  Text content for `BODY`, `FOOTER`, and text-format `HEADER`. Use `{{1}}`, `{{2}}` for positional placeholders, or named placeholders like `{{customer_name}}` paired with `example.body_text_named_params`.
</ParamField>

<ParamField body="example" type="object">
  Sample values Meta uses during review. Pick the variant matching your component:

  * `header_text` — array of sample strings for a TEXT header with placeholders.
  * `header_handle` — array of media handles from Meta's resumable-upload API for `IMAGE`, `VIDEO`, or `DOCUMENT` headers.
  * `header_text_named_params` — array of `{ param_name, example }` for a TEXT header that uses `{{name}}` style placeholders.
  * `body_text` — array of example sets for positional `{{1}}`, `{{2}}` placeholders. The outer array contains one or more example sets; each inner array contains one sample value per placeholder, in order.
  * `body_text_named_params` — array of `{ param_name, example }` for a body that uses `{{name}}` style placeholders.
</ParamField>

<ParamField body="buttons" type="array">
  Only meaningful when `type` is `BUTTONS`. Each button has `type` (`QUICK_REPLY`, `PHONE_NUMBER`, `URL`, `OTP`, `COPY_CODE`), `text`, and optionally `phone_number`, `url`, or `example`.
</ParamField>

<ParamField body="cards" type="array">
  Only meaningful when `type` is `CAROUSEL`. Each card has its own `components` array (at minimum a `HEADER` and a `BODY`).
</ParamField>

### Example Object

```json theme={null}
{
  "api_id": "db342550-7f1d-11e1-8ea7-1231380bc196",
  "template_id": "123456789012345",
  "name": "order_confirmation",
  "language": "en_US",
  "category": "MARKETING",
  "status": "APPROVED",
  "quality_score": { "score": "GREEN" },
  "rejected_reason": "NONE",
  "components": [
    {
      "type": "BODY",
      "text": "Hi {{1}}, your order {{2}} is on its way.",
      "example": {
        "body_text": [["Alex", "ORD-12345"]]
      }
    }
  ]
}
```

***

## Create a Template

Submit a new template to Meta via the bound WABA. The new template starts in `PENDING`. Meta reviews it asynchronously and emits a status event that Plivo forwards to your configured WABA webhook URL.

Create returns an action confirmation envelope (`api_id`, `template_id`, `template_status`, etc.) — not the full template object. Call [Get a Template](#get-a-template) to fetch components and other fields.

```http theme={null}
POST https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/
```

### Arguments

<ParamField body="name" type="string" required>
  snake\_case template name, unique per WABA. After you delete a template, Meta enforces a 30-day cooldown before the same name can be reused.
</ParamField>

<ParamField body="language" type="string" required>
  BCP-47 language code (for example, `en_US`).
</ParamField>

<ParamField body="category" type="string" required>
  Values: `MARKETING`, `UTILITY`, `AUTHENTICATION`.
</ParamField>

<ParamField body="components" type="array" required>
  Non-empty array of components. At least one `BODY` component is required; `HEADER`, `FOOTER`, `BUTTONS`, and `CAROUSEL` are optional. See [Component object](#component-object).
</ParamField>

<ParamField body="allow_category_change" type="boolean">
  When `true`, Meta is allowed to switch the template's category during review (for example, `UTILITY` to `MARKETING`) instead of rejecting the submission for mismatched content. Defaults to `false`, in which case Meta typically rejects templates whose content doesn't match the requested category.
</ParamField>

### Example — Text-only marketing template

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/" \
    -u '<auth_id>:<auth_token>' \
    -H "Content-Type: application/json" \
    -d '{
      "name": "order_confirmation",
      "language": "en_US",
      "category": "MARKETING",
      "components": [
        {
          "type": "BODY",
          "text": "Hi {{1}}, your order {{2}} is on its way.",
          "example": {
            "body_text": [["Alex", "ORD-12345"]]
          }
        }
      ]
    }'
  ```
</CodeGroup>

### Example — Body with named parameters

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/" \
    -u '<auth_id>:<auth_token>' \
    -H "Content-Type: application/json" \
    -d '{
      "name": "account_alert_named",
      "language": "en_US",
      "category": "UTILITY",
      "components": [
        {
          "type": "BODY",
          "text": "Hi {{customer_name}}, your balance is {{balance}}.",
          "example": {
            "body_text_named_params": [
              { "param_name": "customer_name", "example": "Alex" },
              { "param_name": "balance", "example": "$42.00" }
            ]
          }
        }
      ]
    }'
  ```
</CodeGroup>

### Example — Image header with media handle

Upload your media via Meta's [resumable-upload API](https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates/#resumable-upload-api) and pass the returned handle in `header_handle`.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/" \
    -u '<auth_id>:<auth_token>' \
    -H "Content-Type: application/json" \
    -d '{
      "name": "receipt_image",
      "language": "en_US",
      "category": "UTILITY",
      "components": [
        {
          "type": "HEADER",
          "format": "IMAGE",
          "example": {
            "header_handle": ["4::aW1hZ2UvanBlZw==:..."]
          }
        },
        {
          "type": "BODY",
          "text": "Your receipt is attached."
        }
      ]
    }'
  ```
</CodeGroup>

### Example — Carousel template

Meta requires a CAROUSEL component to contain between 2 and 10 cards.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/" \
    -u '<auth_id>:<auth_token>' \
    -H "Content-Type: application/json" \
    -d '{
      "name": "product_carousel",
      "language": "en_US",
      "category": "MARKETING",
      "components": [
        { "type": "BODY", "text": "Check out our new arrivals!" },
        {
          "type": "CAROUSEL",
          "cards": [
            {
              "components": [
                {
                  "type": "HEADER",
                  "format": "IMAGE",
                  "example": { "header_handle": ["4::aW1nMQ==:..."] }
                },
                {
                  "type": "BODY",
                  "text": "Card 1: {{1}}",
                  "example": { "body_text": [["Free shipping"]] }
                }
              ]
            },
            {
              "components": [
                {
                  "type": "HEADER",
                  "format": "IMAGE",
                  "example": { "header_handle": ["4::aW1nMg==:..."] }
                },
                {
                  "type": "BODY",
                  "text": "Card 2: {{1}}",
                  "example": { "body_text": [["20% off"]] }
                }
              ]
            }
          ]
        }
      ]
    }'
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "api_id": "a5f1e9b2-58b6-11e1-86da-77300b68f8bb",
  "status": "success",
  "message": "template submitted to meta for review",
  "template_id": "123456789012345",
  "template_name": "order_confirmation",
  "template_status": "PENDING",
  "template_language": "en_US",
  "template_category": "MARKETING"
}
```

***

## List Templates

Retrieve a paginated list of templates for a WABA. List returns a summary projection of each template — call [Get a Template](#get-a-template) to fetch `components`, `quality_score`, and `rejected_reason`.

```http theme={null}
GET https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/
```

### Query Parameters

<ParamField query="template_name" type="string">
  Substring filter on template name.
</ParamField>

<ParamField query="limit" type="integer">
  The number of results per page. The maximum number of results that can be fetched is 20. Defaults to 20.
</ParamField>

<ParamField query="offset" type="integer">
  The number of value items by which the results should be offset. Defaults to 0. Read more about [offset-based pagination](/messaging/api/request/pagination).
</ParamField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/?limit=20&offset=0" \
    -u '<auth_id>:<auth_token>'
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "api_id": "b1c2d3e4-58b6-11e1-86da-77300b68f8bb",
  "status": "success",
  "meta": {
    "limit": 20,
    "offset": 0,
    "next": "/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/?limit=20&offset=20",
    "previous": null
  },
  "objects": [
    {
      "template_id": "123456789012345",
      "name": "order_confirmation",
      "language": "en_US",
      "category": "MARKETING",
      "status": "APPROVED"
    },
    {
      "template_id": "234567890123456",
      "name": "account_alert_named",
      "language": "en_US",
      "category": "UTILITY",
      "status": "PENDING"
    }
  ]
}
```

***

## Get a Template

Retrieve the current state of a single template, including its components.

```http theme={null}
GET https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/{template_id}/
```

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/123456789012345/" \
    -u '<auth_id>:<auth_token>'
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "api_id": "c1d2e3f4-58b6-11e1-86da-77300b68f8bb",
  "template_id": "123456789012345",
  "name": "order_confirmation",
  "language": "en_US",
  "category": "MARKETING",
  "status": "APPROVED",
  "quality_score": { "score": "GREEN" },
  "rejected_reason": "NONE",
  "components": [
    {
      "type": "BODY",
      "text": "Hi {{1}}, your order {{2}} is on its way.",
      "example": {
        "body_text": [["Alex", "ORD-12345"]]
      }
    }
  ]
}
```

***

## Update a Template

Submit an update to an existing template. The body shape is identical to [Create](#create-a-template). The template typically transitions back to `PENDING` while Meta re-reviews; the resulting `APPROVED` or `REJECTED` status is delivered to your configured WABA webhook URL.

```http theme={null}
POST https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/{template_id}/
```

### Arguments

Same as [Create a Template](#create-a-template).

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/123456789012345/" \
    -u '<auth_id>:<auth_token>' \
    -H "Content-Type: application/json" \
    -d '{
      "name": "order_confirmation",
      "language": "en_US",
      "category": "MARKETING",
      "components": [
        {
          "type": "BODY",
          "text": "Hi {{1}}, your order {{2}} has been dispatched.",
          "example": {
            "body_text": [["Alex", "ORD-12345"]]
          }
        }
      ]
    }'
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "api_id": "d1e2f3a4-58b6-11e1-86da-77300b68f8bb",
  "status": "success",
  "message": "template update submitted to meta for review",
  "template_id": "123456789012345",
  "template_name": "order_confirmation",
  "template_status": "PENDING",
  "template_language": "en_US",
  "template_category": "MARKETING"
}
```

***

## Delete a Template

Remove a template from the WABA via Meta. This operation cannot be undone — to reuse the same template name later, you may need to wait out Meta's name-reuse cooldown.

```http theme={null}
DELETE https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/{template_id}/?name={name}
```

<Warning>
  Both `template_id` (path) and `name` (query) are required. Meta's Graph API needs both to delete a specific language variant. Calls missing `?name=` are rejected with a 400.
</Warning>

### Query Parameters

<ParamField query="name" type="string" required>
  The template's `name` (the same value you sent on Create or received on List).
</ParamField>

### Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.plivo.com/v1/Account/{auth_id}/WhatsApp/Template/{waba_id}/123456789012345/?name=order_confirmation" \
    -u '<auth_id>:<auth_token>'
  ```
</CodeGroup>

### Response

```text theme={null}
HTTP Status Code: 204
```

***

## HTTP Status Codes

| Code    | Description                                                                 |
| ------- | --------------------------------------------------------------------------- |
| **200** | Request executed successfully.                                              |
| **204** | Template deleted (no body).                                                 |
| **400** | Validation error — missing or invalid parameter.                            |
| **401** | Authentication failed.                                                      |
| **404** | Template not found.                                                         |
| **429** | Rate limit exceeded. Rate limits are applied per `auth_id` per endpoint.    |
| **502** | Upstream service (messaging-whatsapp or Meta) returned a transient failure. |

For the canonical error envelope and common error codes, see the [Messaging API Response](/messaging/api/response/) page.

***

## Related

* [Manage WhatsApp Templates (concept)](/messaging/concepts/whatsapp/manage-templates/) — UI walkthrough and template structure overview.
* [Send a Message](/messaging/api/message/send-a-message/) — Send a templated WhatsApp message once the template is `APPROVED`.
* [WhatsApp Prerequisites](/messaging/concepts/whatsapp/prerequisites/) — WABA setup steps.
