# Create a template

`POST /v1/templates`

Creates a template and submits it to WhatsApp for review. WhatsApp approves or rejects it later.

Needs `templates:write`. Counts against the heavy request limit (10 a minute).

> If WhatsApp refuses the template, Soosh keeps it as a `DRAFT` in the app, and `error.details.id` is the draft.

## Body

- `number_id` (string, uuid, required): The number to make the template on (see `GET /v1/numbers`).
- `name` (string, required): Lowercase letters, numbers and underscores, up to 255 characters. Unique per number and language.
- `language` (string, required): A WhatsApp language code, such as `en` or `pt_BR`.
- `category` (string, required): Authentication templates are made in the app. One of `MARKETING`, `UTILITY`.
- `body` (string, required): Up to 1024 characters. Variables are `{{1}}`, `{{2}}` in order, or `{{name}}`; not both.
- `header` (object): A text header. Image, video and document headers are made in the app.
  - `format` (string, required): Always `TEXT`.
  - `text` (string, required): Up to 60 characters, with at most one variable.
  - `example` (string): An example for the header's variable. Required when it has one.
- `body_examples` (array of strings): One example for each variable of the body, in the order they first appear. Required when the body has variables.
- `footer` (string): Up to 60 characters.
- `buttons` (array of objects): Up to 10 buttons. Keep quick replies together, before or after the others.
  - `type` (string, required): One of `QUICK_REPLY`, `URL`, `PHONE_NUMBER`, `COPY_CODE`.
  - `text` (string): Up to 25 characters. Not used by `COPY_CODE`.
  - `url` (string): For `URL`. May end in `{{1}}`.
  - `phone_number` (string): For `PHONE_NUMBER`, for example `+14155550123`.
  - `example` (string): For `URL` with a `{{1}}`: an example for the variable. For `COPY_CODE`: the sample code (up to 20 characters).

## Headers

- `Idempotency-Key` (string): Send one so a retry doesn't create the template twice. See [Retrying safely](/reference/api/#retrying-safely). 1 to 255 characters.

## Names and languages

A template is the same one only in the same language. The same name in another language is a new template.

## Copy-code buttons

A `COPY_CODE` button needs an `example` code. Its value is required again when you send the template: `variables.buttons` of the template lists it, and `POST /v1/messages` must supply it.

## Example

```sh
curl -X POST https://app.soosh.io/v1/templates \
  -H "Authorization: Bearer $SOOSH_API_KEY" \
  -H "Idempotency-Key: create-template-a-utility-template-1" \
  -H "Content-Type: application/json" \
  -d '{
    "number_id": "0f6d3c1e-5b7a-4c52-9a55-3f6a2d5c8b10",
    "name": "order_update",
    "language": "en",
    "category": "UTILITY",
    "header": {
      "format": "TEXT",
      "text": "Order {{1}}",
      "example": "A-1001"
    },
    "body": "Hi {{1}}, your order {{2}} is on its way.",
    "body_examples": [
      "Priya",
      "A-1001"
    ],
    "footer": "Thanks for shopping with us",
    "buttons": [
      {
        "type": "URL",
        "text": "Track",
        "url": "https://example.com/track/{{1}}",
        "example": "A-1001"
      }
    ]
  }'
```

Response 201:

```json
{
  "id": "2f9a6c1d-5e3b-4a78-8c04-b1d7e5f3a920",
  "name": "order_update",
  "language": "en",
  "category": "UTILITY",
  "status": "PENDING",
  "rejection_reason": null,
  "quality": "UNKNOWN",
  "number_id": "0f6d3c1e-5b7a-4c52-9a55-3f6a2d5c8b10",
  "parameter_format": "positional",
  "header": {
    "format": "TEXT",
    "text": "Order {{1}}"
  },
  "body": "Hi {{1}}, your order {{2}} is on its way.",
  "footer": "Thanks for shopping with us",
  "buttons": [
    {
      "type": "URL",
      "text": "Track",
      "url": "https://example.com/track/{{1}}"
    }
  ],
  "variables": {
    "header": [
      "1"
    ],
    "body": [
      "1",
      "2"
    ],
    "buttons": {
      "0": [
        "1"
      ]
    }
  },
  "created_at": "2026-10-01T06:15:03.774Z",
  "updated_at": "2026-10-01T06:15:03.774Z"
}
```

## Returns

201. The template, `PENDING` until WhatsApp decides. Follow it with `GET /v1/templates/{id}` or the `template.status` webhook.

## Errors

Besides the ones every request can get (https://docs.soosh.io/reference/api/errors/):

- 422 `invalid_field`: A field breaks a rule, such as a header that isn't `TEXT`, or WhatsApp refuses the template.
- 409 `conflict`: The name and language already exist on this number. `error.details.id` is the existing template.
- 409 `idempotency_in_progress`: A request with the same `Idempotency-Key` is still running.
- 422 `idempotency_mismatch`: The `Idempotency-Key` was used before for a different request, or by another of your API keys.