## Create template

`POST https://whatsapp.paaltech.org/api/v1/businesses/{external_id}/whatsapp/templates`

Submits a new template to Meta for review on the business's WhatsApp account and mirrors it
(usually `PENDING`). Meta's decision arrives as a `template.status` callback. `components`
are Meta's template components, passed through as they are; `category` is marketing,
utility or authentication. With several WhatsApp accounts, pass `waba_id`. Meta allows
100 new templates per account per hour.

Ability: `templates.manage`

### Path parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `external_id` | string | yes | Your own ID for the business (Multi-SKUUL - the tenant ID). Max 191 characters. Pattern `^[A-Za-z0-9._:-]+$` |

### Body

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Max 512 characters. Pattern `^[a-z0-9_]+$` |
| `language` | string | yes | Example `en_US` |
| `category` | string | yes | One of: `marketing`, `utility`, `authentication` |
| `parameter_format` | string | null | no | One of: `named`, `positional`, `` |
| `components` | array of objects | yes | Meta's template components (HEADER, BODY, FOOTER, BUTTONS), with examples. Max 10 items |
| `waba_id` | string | null | no | Needed only when the business has several WhatsApp accounts. |

### Request

```bash
curl --request POST \
  --url 'https://whatsapp.paaltech.org/api/v1/businesses/presec/whatsapp/templates' \
  --header "Authorization: Bearer $PAALCHAT_TOKEN" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "fee_reminder",
  "language": "en_US",
  "category": "utility",
  "parameter_format": "named",
  "components": [
    {
      "type": "BODY",
      "text": "Dear {{parent}}, the fees for {{student}} are due.",
      "example": {
        "body_text_named_params": [
          {"param_name": "parent", "example": "Ama"},
          {"param_name": "student", "example": "Kofi"}
        ]
      }
    }
  ]
}'
```

### Responses

- **201** - Submitted to Meta and mirrored.

```json
{
  "data": {
    "name": "fee_reminder",
    "language": "en_US",
    "category": "UTILITY",
    "status": "PENDING",
    "rejection_reason": null,
    "components": [
      {
        "type": "BODY",
        "text": "Dear {{parent}}, the fees for {{student}} are due.",
        "example": {
          "body_text_named_params": [
            {"param_name": "parent", "example": "Ama"},
            {"param_name": "student", "example": "Kofi"}
          ]
        }
      }
    ],
    "waba_id": "102290129340398",
    "last_synced_at": "2026-10-01T10:00:00+00:00"
  }
}
```

- **401** - unauthenticated - missing, invalid, revoked or expired token

```json
{
  "error": {"code": "unauthenticated", "message": "A valid product token is required."}
}
```

- **403** - missing_ability, product_suspended or product_token_required

```json
{
  "error": {
    "code": "missing_ability",
    "message": "This token does not have the ability this request needs."
  }
}
```

- **404** - not_found - not yours, or does not exist

```json
{"error": {"code": "not_found", "message": "Business not found."}}
```

- **409** - business_suspended - the business is suspended on PaalChat.

```json
{
  "error": {
    "code": "business_suspended",
    "message": "This business is suspended on the platform."
  }
}
```

- **422** - validation_failed, waba_required (several accounts, no waba_id) or template_rejected (Meta refused it - the message says why).

```json
{
  "error": {
    "code": "template_rejected",
    "message": "Meta refused the template: Character limit exceeded"
  }
}
```

- **429** - rate_limited - over 300 requests/minute for this product

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and retry after the Retry-After header."
  }
}
```

- **503** - meta_unavailable - Meta did not answer normally. Retry later.
