# 编写 WhatsApp 模板

Bird 的托管目录涵盖了常见场景，但要使用你自己措辞的模板，则需要在你已连接的 WhatsApp Business Account 上编写。本页介绍如何创建模板；[WhatsApp 模板](/docs/guides/whatsapp/templates)介绍如何浏览和发送现有模板。

整个流程由三件事决定：

- **模板包含版本，版本包含每种语言的一个条目。** 实际发送的是某个版本中的某种语言，而不是模板本身。
- **内容写入草稿。** 一个模板最多有一个打开的草稿，在你提交之前，草稿中的任何内容都不会到达 WhatsApp。
- **审批按语言返回。** 同一版本中，一种语言可能获批，而另一种被拒绝。

## 开始之前

你需要连接一个[属于你自己的号码](/docs/guides/whatsapp/phone-number-setup)，这样你的工作区才能获得一个可用于编写模板的 WhatsApp Business Account。未连接的账号会被拒绝，编辑 Bird 内置的 `bird_` 模板也会被拒绝：这些模板在 Bird 自己的账号上，请改为将其复制到你的账号上。

编写 **authentication** 模板还需要经过验证的企业；utility 和 marketing 类别则不需要。相关门槛请参阅[身份验证模板](/docs/guides/whatsapp/templates/authentication#before-you-send)。

你可以在仪表板的 **WhatsApp** > **Templates** 下编写模板，也可以使用 [`bird` CLI](/docs/cli)，或通过 [MCP 服务端](/docs/ai/mcp-server)。仪表板遵循本页描述的相同步骤；后续示例使用 CLI。

## 在仪表板中

**New template** 提供两种方式。**Start with a template** 会打开模板库，这是最快的方式：选择一个内容已接近你需求的模板（包括 Bird 的模板），副本会作为打开的草稿出现在你的账号上。

![Bird 仪表板中的模板库：模板卡片网格，每张卡片预览其消息内容，并标注名称、slug、状态、类别和语言，旁边有模板来源、类别和语言的筛选器](/images/docs/dashboard-whatsapp-template-gallery.png)

**Start from scratch** 要求你选择类别、输入名称并设置默认语言，然后打开编辑器。marketing 模板还需要选择消息类型。名称会成为 slug，而 slug 和类别是之后无法更改的两项选择。

![Bird 仪表板中的创建新模板步骤：Marketing、Utility 和 Authentication 类别磁贴下方有 Name 字段和 Default language 选择器，以及 Create template 按钮](/images/docs/dashboard-whatsapp-template-details.png)

编辑器一次编写一种语言：侧边栏列出模板的各种语言及其审核状态，中间栏放置内容，手机预览以替换后的示例值渲染消息。

![Bird 仪表板中 Order update utility 模板的模板编辑器：语言侧边栏中 English 标记为 Approved，旁边是 Dutch，手机预览显示渲染后的消息及其 Track order 和 Contact support 按钮](/images/docs/dashboard-whatsapp-template-builder.png)

编辑器会随模板类型改变布局。**carousel** 模板在消息旁为每张卡片添加一个标签页，每张卡片都必须重复卡片 1 的结构：相同的头部格式和相同顺序的按钮。

![Bird 仪表板中 carousel marketing 模板的模板编辑器：消息正文上方有 Message、Card 1、Card 2 和 Card 3 标签页，下方有变量示例区域，旁边手机预览显示消息后跟可滑动的图片卡片，每张卡片带有 Show me 按钮](/images/docs/dashboard-whatsapp-template-builder-carousel.png)

**authentication** 模板没有消息编辑器。WhatsApp 会编写文案，因此编辑器只提供生成文案所需的两个设置：**Add security recommendation** 和 **Code expiration (minutes)**。

![Bird 仪表板中 authentication 模板的模板编辑器：Authentication settings 面板包含 Add security recommendation 开关和 Code expiration (minutes) 字段，旁边手机预览显示 WhatsApp 编写的验证码消息及其 Copy code 按钮](/images/docs/dashboard-whatsapp-template-builder-auth.png)

**Save as draft** 保存你的工作，不会联系 WhatsApp。**Submit for review** 冻结版本并将其发送到 WhatsApp。下文介绍的 CLI 提交执行相同的冻结操作。

## 两种起步方式

### 复制现有模板

复制操作将源模板的内容作为打开的草稿，且不会调用 WhatsApp，因此在你主动选择之前不会提交任何内容。在复制之前，有两点值得了解：

- **类别继承自源模板，且无法更改。** 如果你需要不同的类别，请改为从头创建。
- **你只能缩减语言范围，不能增加。** 一个包含 70 种语言的目录模板不必变成你的 70 种语言：只选择你实际会维护的子集。请求源模板不包含的语言会被拒绝并返回 [`E15060`](/docs/api/errors/E15060)，响应中会指明哪些语言不匹配。之后可以向副本添加更多语言。

语言子集是一个数组，因此需要放在请求体中而不是作为标志传递：

```bash
bird whatsapp templates duplicate bird_order_confirmation --body-file copy.json
```

```json
{
  "waba": "102290129340398",
  "slug": "acme_order_update",
  "include_languages": ["en", "es-ES"],
  "default_language": "en"
}
```

省略 `include_languages`，副本会继承源模板的所有语言。省略 `default_language`，当你的子集仍包含源模板的默认语言时，副本会保留该默认语言；否则会取副本语言中按规范标签排序的第一个，这不一定是你列出的第一个，因此如有需要请显式设置。

### 从头创建

创建模板需要 slug、账号、类别和默认语言：

```bash
bird whatsapp templates create order_update \
  --waba 102290129340398 \
  --category utility \
  --default-language en
```

**slug 和类别都是永久性的。** WhatsApp 根据 slug 派生自己的模板名称，两者之后都无法更改；需要不同的就意味着创建新模板。`bird_` 前缀为 Bird 的目录所保留。你选择的类别不一定是发送时的计费类别：Meta 会按语言应用自己的类别并可能调整，价格以 Meta 的为准。

## 编写各语言内容

打开草稿，然后一次编写一种语言：

```bash
bird whatsapp templates versions create order_update
bird whatsapp templates versions languages set order_update <version-id> en --body-file en.json
```

打开草稿可以安全地重复调用：模板只有一个草稿，因此会返回已打开的那个，而不会创建第二个。模板也会将其报告为 `draft_version_id`。

**写入语言会替换整个语言内容，而不是合并。** 文件每次都携带该语言的完整 `components`，因此请先读取语言内容再整体写回；只发送你修改的部分会删除其余内容。

**每个变量都需要一个示例值。** WhatsApp 审核的是填充后的消息而非模板本身，因此包含占位符但没有示例参数的块会在提交时而非写入时被拒绝。

## 检查后提交

在冻结任何内容之前先进行验证。仅验证的提交会对每种语言运行所有检查，并在一次调用中报告每个问题，不会向 WhatsApp 发送任何内容：

```bash
bird whatsapp templates versions submit order_update <version-id> --validate-only
```

阅读 `valid` 和 `errors`；每个错误会指明语言、字段以及实际提交时会失败的错误码。然后去掉该标志进行正式提交。正式提交会将草稿冻结为不可变版本并返回 `202`。检查和提交请使用不同的幂等键，因为对已更改的请求体重用同一个键会被拒绝。

只有内容与已批准副本不同的语言才会发送到 WhatsApp。已匹配的语言会继承其批准状态，因此如果没有任何更改，提交会立即完成，无需轮询。之后不会自动打开替换草稿：下一轮编辑从重新创建草稿开始。

仅验证的通过并不能预测 WhatsApp 的决定。WhatsApp 没有提前查询的途径，因此它仍然可能拒绝通过了所有本地检查的内容。

## 关注审核进度

审批稍后到达，且按语言返回。当任何语言尚未决定时，模板的 `pending_version_id` 保持已设置状态，每种语言的列表携带各自的结果：

- **`approved`** 可发送。模板上的 `available_languages` 正是当前发送可以解析使用的语言列表。
- **`rejected`、`submit_failed`、`paused`** 需要在新草稿中进行编辑。WhatsApp 接受对已暂停语言的编辑，重新提交即可清除该状态。
- **`disabled`、`limit_exceeded`、`in_appeal`** 完全拒绝编辑；需要重新读取其状态，直到 WhatsApp 更新这些状态。

模板自身的 `status` 是一个聚合值：`active` 表示至少有一种语言可发送，而非全部。

## 发送你编写的模板

你编写的模板通过与其他模板相同的端点发送，与 Bird 目录的一个区别是：**你必须指定 `from`**，且该号码必须属于与模板相同的 WhatsApp Business Account。使用不同账号的发送者会在计费之前被拒绝，返回 `422` [`E15023`](/docs/api/errors/E15023)。

模板可以通过 `language_source_required` 要求指定接收者语言。否则，`on_missing_language` 控制解析是直接失败，还是可以使用已批准的基础语言或 `default_language`。请针对模板已批准的 `available_languages` 测试配置的策略；未批准的默认语言不可发送。你提供的值必须填充实际解析到的语言的占位符，因此发送前请先读取该语言的内容。完整载荷请参阅[发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp)。

## 注意事项

- **最新版本不一定是发送中的版本。** 版本列表按最新排序，且包含任何打开的草稿，因此最上面一行通常是草稿或仍在审核中的版本。模板将正在使用的版本标记为 `live_version_id`；没有活跃版本的模板完全无法发送。
- **审核中的语言拒绝写入。** WhatsApp 会锁定该语言直到审核完成，因此在 `pending` 期间的编辑会失败而不是排队等待。
- **列表行不包含内容。** 列出模板只能找到模板并显示生命周期状态；读取模板的实际内容需要进行版本读取。
- **删除不可恢复。** 丢弃一种语言、删除草稿和删除模板都需要显式确认，删除模板会停止该 slug 下的所有发送。

## 后续步骤

- [WhatsApp 模板](/docs/guides/whatsapp/templates)：目录、类别以及共享的按模板发送契约
- [模板指南](/docs/knowledge-base/whatsapp/template-guidelines)：Meta 审核关注的内容
- [电话号码设置](/docs/guides/whatsapp/phone-number-setup)：连接你用于编写模板的账号
- [发送 WhatsApp 消息](/docs/guides/whatsapp/sending-whatsapp)：完整的发送载荷
- [创建和提交 WhatsApp 模板](/learn/whatsapp/building-and-submitting-a-whatsapp-template)：一段编写 utility 模板和 marketing carousel 的视频

## Related resources

- [What is a WhatsApp message template?](/explained/whatsapp/what-is-a-whatsapp-message-template) (answer)
- [WhatsApp templates](/products/whatsapp/templates) (product)
- [Build your first integration](/learn/paths/integration) (course)

[Get an implementation brief](/learn/workspace?topic=whatsapp-templates)
