# WhatsApp utility templates

A utility template follows up on something the recipient already did: an order, a payment, a booking, a sign-in. Bird's catalog stocks eight of them, including `bird_signin_alert` and `bird_delivery_update`. Take a slug's category from the template list rather than its name: `bird_signin_alert` reads like an authentication template and isn't one, it's utility.

## Before you send

Utility has the fewest prerequisites of the three categories.

Sending Bird's stocked catalog templates needs no verification of yours, the same as authentication. Authoring a utility template of your own needs none either: unlike authentication, Meta's business-verification gate never applies to utility, so you can create and edit utility templates on an unverified workspace. See [WhatsApp business verification](/docs/knowledge-base/whatsapp/business-verification) for what verification unlocks elsewhere.

`to` can be an E.164 phone number or a business-scoped user ID. A utility template carries no OTP button, so it doesn't require the phone-number-only recipient that authentication does.

Every managed catalog utility template is registered in `en` only, with `on_missing_language: fail`. Requesting a language the catalog doesn't stock fails the send rather than falling back to English or anything else.

## Sending a utility template

`POST /v1/whatsapp/messages` with a `template` object naming a catalog slug:

<!-- bird:tabs typescript,python,go,php,cli,curl -->

```typescript
const msg = await bird.whatsapp.send({
  to: "+16505551234",
  template: {
    slug: "bird_order_confirmation",
    language: "en",
    components: [
      {
        type: "body",
        parameters: [
          { type: "text", name: "ref", text: "A1B2C3D4" },
          { type: "text", name: "amount", text: "USD 49.99" },
        ],
      },
    ],
  },
});
console.log(msg.id, msg.status);
```

```python
msg = client.whatsapp.send(
    to="+16505551234",
    template="bird_order_confirmation",
    language="en",
    components=[
        {
            "type": "body",
            "parameters": [
                {"type": "text", "name": "ref", "text": "A1B2C3D4"},
                {"type": "text", "name": "amount", "text": "USD 49.99"},
            ],
        }
    ],
)
print(msg.id, msg.status)
```

```go
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	bird "github.com/messagebird/bird-sdk-go"
	"github.com/messagebird/bird-sdk-go/option"
)

func main() {
	client, err := bird.NewClient(option.WithAPIKey(os.Getenv("BIRD_API_KEY")))
	if err != nil {
		log.Fatal(err)
	}
	ref := "A1B2C3D4"
	amount := "USD 49.99"
	refName := "ref"
	amountName := "amount"
	components := []bird.WhatsAppMessageTemplateComponent{{
		Type: "body",
		Parameters: &[]bird.WhatsAppMessageTemplateComponentParameter{
			{Type: "text", Name: &refName, Text: &ref},
			{Type: "text", Name: &amountName, Text: &amount},
		},
	}}
	msg, err := client.Whatsapp.Send(context.Background(), bird.WhatsappSendParams{
		To:       "+16505551234",
		Template: "bird_order_confirmation",
		Language: "en",
		Components: components,
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(msg.Id, *msg.Status)
}
```

```php
$components = [
    (new WhatsAppMessageTemplateComponent())
        ->setType('body')
        ->setParameters([
            (new WhatsAppMessageTemplateComponentParameter())->setType('text')->setName('ref')->setText('A1B2C3D4'),
            (new WhatsAppMessageTemplateComponentParameter())->setType('text')->setName('amount')->setText('USD 49.99'),
        ]),
];
$message = $bird->whatsapp->send(
    to: '+16505551234',
    template: 'bird_order_confirmation',
    language: 'en',
    components: $components,
);
echo $message->getId(), ' ', $message->getStatus();
```

```cli
bird whatsapp send \
  --to +16505551234 \
  --template bird_order_confirmation \
  --language en \
  --components '[{"type":"body","parameters":[{"type":"text","name":"ref","text":"A1B2C3D4"},{"type":"text","name":"amount","text":"USD 49.99"}]}]'
```

```curl
curl -X POST "https://us1.platform.bird.com/v1/whatsapp/messages" \
  -H "Authorization: Bearer $BIRD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "to": "+16505551234",
      "template": {
        "slug": "bird_order_confirmation",
        "language": "en",
        "components": [
          {
            "type": "body",
            "parameters": [
              {
                "type": "text",
                "name": "ref",
                "text": "A1B2C3D4"
              },
              {
                "type": "text",
                "name": "amount",
                "text": "USD 49.99"
              }
            ]
          }
        ]
      }
    }'
```

<!-- /bird:tabs -->

As with any managed template, omit `from`: Bird picks the sending number from the category and region, and setting it returns `422` [`E15018`](/docs/api/errors/E15018) `WhatsAppSenderNotAllowed`. Authoring your own utility template and sending it works the same way as any authored send; see [Sending with a template](/docs/guides/whatsapp/templates#sending-with-a-template) for the general contract.

## Filling the variables

Utility parameters are named, the reverse of authentication's single positional code. Every parameter carries a `name`, and a named parameter's order in the array carries no meaning. Send one `components` entry for each block that actually has a placeholder; a body with no variables takes no `components` entry for it at all.

A URL button is the one exception: its variable is always positional `{{1}}`, and the send carries the bare value rather than a full address:

```json
{ "type": "button", "parameters": [{ "type": "text", "text": "A-4192" }] }
```

For the shared rules on components, `sub_type`, and how a send's `components` line up with a template's declared placeholders, see [Sending with a template](/docs/guides/whatsapp/templates#sending-with-a-template) and [Components and parameters](/docs/guides/whatsapp/sending-whatsapp#components-and-parameters).

## Cost

A utility template delivered inside an open customer service window is free on Meta's side of the invoice. It is not free on Bird's: Bird's own accept-time fee is charged regardless of the window, because that charge is set before delivery, when Meta's verdict isn't known yet. Treat "utility in-window is free" as only half the story.

See [Cost and billing](/docs/guides/whatsapp/sending-whatsapp#cost-and-billing) for when a send is charged, and [WhatsApp pricing](https://bird.com/pricing/whatsapp) for rates.

## Things to watch

- **Meta can recategorize a utility template as marketing on its own initiative**, and the message keeps sending at the new, higher price. A business Meta has already warned for miscategorization gets no advance notice at all since April 2025; the change lands instantly. Keep promotional language, offers, or upsells out of a utility template's copy, since that's what triggers the move. See [Template guidelines](/docs/knowledge-base/whatsapp/template-guidelines) for what reads as promotional.
- **A `gif` header or a `copy_code` button is refused outside marketing.** Both are marketing-only components; declaring either on a utility template fails.
- **An authored send isn't checked for parameter count before it's charged.** Send the wrong number of parameters on a template of your own and the message is accepted and charged, then rejected by Meta. Managed catalog sends don't have this gap.
- **A sender on the wrong WhatsApp Business Account is refused before any charge.** `from` has to sit on the same account as the template; otherwise the send fails `422` [`E15023`](/docs/api/errors/E15023) `WhatsAppSenderWABAMismatch`.

## Next steps

- [WhatsApp templates](/docs/guides/whatsapp/templates): browsing the catalog and the shared send-by-template contract
- [Authentication templates](/docs/guides/whatsapp/templates/authentication): one-time passcodes and the verification gate on authoring one
- [Marketing templates](/docs/guides/whatsapp/templates/marketing): promotional sends and the account you need to author one