whatsapp-templates

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WhatsApp Templates

WhatsApp消息模板

When to Use

使用场景

Use this skill when building code to create, manage, or send WhatsApp template messages. Templates are required to initiate conversations outside the 24-hour window.
当你需要编写代码来创建、管理或发送WhatsApp模板消息时,可以使用此技能。在24小时对话窗口之外发起对话时,必须使用模板。

When Templates Are Required

何时需要使用模板

Has user messaged you in the last 24 hours?
  -> YES: Send free-form message (text, image, buttons, etc.)
  -> NO: Must use template message
Need to send bulk/broadcast messages?
  -> YES: Use template (recommended for consistency)
Want proactive outbound notifications?
  -> YES: Must use template
用户在过去24小时内给你发过消息吗?
  -> 是:发送自由格式消息(文本、图片、按钮等)
  -> 否:必须使用模板消息
需要发送批量/广播消息吗?
  -> 是:使用模板(建议保持一致性)
需要主动发送出站通知吗?
  -> 是:必须使用模板

Template Categories

模板分类

CategoryUse CaseExamples
UTILITY
Transactional updatesOrder confirmations, shipping updates, appointment reminders
MARKETING
Promotional contentSales, offers, product announcements
AUTHENTICATION
OTP/verification codesLogin codes, 2FA, password resets
分类使用场景示例
UTILITY
交易类更新订单确认、物流更新、预约提醒
MARKETING
推广内容促销活动、优惠信息、产品公告
AUTHENTICATION
OTP/验证码登录验证码、双因素认证(2FA)、密码重置

Create Template

创建模板

typescript
const template = await zavu.templates.create({
  name: "order_confirmation",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
});
console.log(template.id); // tpl_xxx
Python:
python
template = zavu.templates.create(
    name="order_confirmation",
    language="en",
    body="Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
    whatsapp_category="UTILITY",
    variables=["customer_name", "order_id"],
)
Go:
go
template, err := client.Templates.Create(context.TODO(), zavudev.TemplateCreateParams{
    Name:             zavudev.String("order_confirmation"),
    Language:         zavudev.String("en"),
    Body:             zavudev.String("Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours."),
    WhatsappCategory: zavudev.String("UTILITY"),
    Variables:        []string{"customer_name", "order_id"},
})
Ruby:
ruby
template = client.templates.create(
    name: "order_confirmation",
    language: "en",
    body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
    whatsapp_category: "UTILITY",
    variables: ["customer_name", "order_id"],
)
PHP:
php
$template = $client->templates->create([
    'name' => 'order_confirmation',
    'language' => 'en',
    'body' => 'Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.',
    'whatsappCategory' => 'UTILITY',
    'variables' => ['customer_name', 'order_id'],
]);
typescript
const template = await zavu.templates.create({
  name: "order_confirmation",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
});
console.log(template.id); // tpl_xxx
Python:
python
template = zavu.templates.create(
    name="order_confirmation",
    language="en",
    body="Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
    whatsapp_category="UTILITY",
    variables=["customer_name", "order_id"],
)
Go:
go
template, err := client.Templates.Create(context.TODO(), zavudev.TemplateCreateParams{
    Name:             zavudev.String("order_confirmation"),
    Language:         zavudev.String("en"),
    Body:             zavudev.String("Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours."),
    WhatsappCategory: zavudev.String("UTILITY"),
    Variables:        []string{"customer_name", "order_id"},
})
Ruby:
ruby
template = client.templates.create(
    name: "order_confirmation",
    language: "en",
    body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
    whatsapp_category: "UTILITY",
    variables: ["customer_name", "order_id"],
)
PHP:
php
$template = $client->templates->create([
    'name' => 'order_confirmation',
    'language' => 'en',
    'body' => 'Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.',
    'whatsappCategory' => 'UTILITY',
    'variables' => ['customer_name', 'order_id'],
]);

Channel-Specific Bodies

渠道专属内容

Templates can have different bodies per channel. The default
body
is used for WhatsApp; SMS, Telegram, and Instagram fall back to
body
if no channel-specific body is set.
typescript
const template = await zavu.templates.create({
  name: "order_confirmation",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
  smsBody: "Order {{2}} confirmed. Ships in 24h.",       // SMS fallback
  telegramBody: "✅ Order {{2}} confirmed for {{1}}.",    // Telegram-specific
  instagramBody: "Order {{2}} confirmed!",               // Instagram-specific
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
});
whatsappCategory
only applies to the WhatsApp
body
. Channel-specific bodies don't require a category.
模板可为不同渠道设置不同内容。默认的
body
适用于WhatsApp;若未设置渠道专属内容,SMS、Telegram和Instagram将回退使用
body
内容。
typescript
const template = await zavu.templates.create({
  name: "order_confirmation",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has been confirmed and will ship within 24 hours.",
  smsBody: "Order {{2}} confirmed. Ships in 24h.",       // SMS回退内容
  telegramBody: "✅ Order {{2}} confirmed for {{1}}.",    // Telegram专属内容
  instagramBody: "Order {{2}} confirmed!",               // Instagram专属内容
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
});
whatsappCategory
仅适用于WhatsApp的
body
内容。渠道专属内容无需设置分类。

Template with Buttons

带按钮的模板

typescript
// Quick reply buttons
const template = await zavu.templates.create({
  name: "feedback_request",
  language: "en",
  body: "Hi {{1}}, how was your experience with order {{2}}?",
  whatsappCategory: "MARKETING",
  variables: ["customer_name", "order_id"],
  buttons: [
    { type: "quick_reply", text: "Great!" },
    { type: "quick_reply", text: "Could be better" },
  ],
});

// URL button
const template = await zavu.templates.create({
  name: "track_order",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has shipped!",
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
  buttons: [
    { type: "url", text: "Track Order", url: "https://example.com/track/{{1}}" },
  ],
});

// Phone button
const template = await zavu.templates.create({
  name: "contact_support",
  language: "en",
  body: "Need help? Call our support team.",
  whatsappCategory: "UTILITY",
  buttons: [
    { type: "phone", text: "Call Support", phoneNumber: "+14155551234" },
  ],
});
typescript
// 快速回复按钮
const template = await zavu.templates.create({
  name: "feedback_request",
  language: "en",
  body: "Hi {{1}}, how was your experience with order {{2}}?",
  whatsappCategory: "MARKETING",
  variables: ["customer_name", "order_id"],
  buttons: [
    { type: "quick_reply", text: "Great!" },
    { type: "quick_reply", text: "Could be better" },
  ],
});

// URL按钮
const template = await zavu.templates.create({
  name: "track_order",
  language: "en",
  body: "Hi {{1}}, your order {{2}} has shipped!",
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id"],
  buttons: [
    { type: "url", text: "Track Order", url: "https://example.com/track/{{1}}" },
  ],
});

// 电话按钮
const template = await zavu.templates.create({
  name: "contact_support",
  language: "en",
  body: "Need help? Call our support team.",
  whatsappCategory: "UTILITY",
  buttons: [
    { type: "phone", text: "Call Support", phoneNumber: "+14155551234" },
  ],
});

OTP Authentication Templates

OTP认证模板

typescript
// Copy code button
const template = await zavu.templates.create({
  name: "login_otp",
  language: "en",
  body: "Your verification code is {{1}}. Do not share this code.",
  whatsappCategory: "AUTHENTICATION",
  variables: ["otp_code"],
  addSecurityRecommendation: true,
  codeExpirationMinutes: 5,
  buttons: [
    { type: "otp", text: "Copy Code", otpType: "COPY_CODE" },
  ],
});

// One-tap autofill (Android)
const template = await zavu.templates.create({
  name: "login_otp_autofill",
  language: "en",
  body: "Your verification code is {{1}}.",
  whatsappCategory: "AUTHENTICATION",
  variables: ["otp_code"],
  addSecurityRecommendation: true,
  codeExpirationMinutes: 10,
  buttons: [
    {
      type: "otp",
      text: "Autofill",
      otpType: "ONE_TAP",
      packageName: "com.example.app",
      signatureHash: "abc123hash",
    },
  ],
});
typescript
// 复制验证码按钮
const template = await zavu.templates.create({
  name: "login_otp",
  language: "en",
  body: "Your verification code is {{1}}. Do not share this code.",
  whatsappCategory: "AUTHENTICATION",
  variables: ["otp_code"],
  addSecurityRecommendation: true,
  codeExpirationMinutes: 5,
  buttons: [
    { type: "otp", text: "Copy Code", otpType: "COPY_CODE" },
  ],
});

// 一键自动填充(安卓)
const template = await zavu.templates.create({
  name: "login_otp_autofill",
  language: "en",
  body: "Your verification code is {{1}}.",
  whatsappCategory: "AUTHENTICATION",
  variables: ["otp_code"],
  addSecurityRecommendation: true,
  codeExpirationMinutes: 10,
  buttons: [
    {
      type: "otp",
      text: "Autofill",
      otpType: "ONE_TAP",
      packageName: "com.example.app",
      signatureHash: "abc123hash",
    },
  ],
});

Submit for Meta Approval

提交Meta审核

Templates must be approved by Meta before use:
typescript
// Submit template for review
const submitted = await zavu.templates.submit({
  templateId: "tpl_abc123",
  senderId: "snd_abc123",
  category: "UTILITY",
});
console.log(submitted.status); // "pending"
Track approval via webhooks (
template.status_changed
event) or polling:
typescript
const template = await zavu.templates.get({ templateId: "tpl_abc123" });
console.log(template.status); // draft | pending | approved | rejected
模板在使用前必须经过Meta审核:
typescript
// 提交模板审核
const submitted = await zavu.templates.submit({
  templateId: "tpl_abc123",
  senderId: "snd_abc123",
  category: "UTILITY",
});
console.log(submitted.status); // "pending"
可通过Webhook(
template.status_changed
事件)或轮询跟踪审核状态:
typescript
const template = await zavu.templates.get({ templateId: "tpl_abc123" });
console.log(template.status); // draft | pending | approved | rejected

Send Template Message

发送模板消息

typescript
await zavu.messages.send({
  to: "+14155551234",
  messageType: "template",
  content: {
    templateId: "tpl_abc123",
    templateVariables: { "1": "John", "2": "ORD-12345" },
  },
});
Python:
python
zavu.messages.send(
    to="+14155551234",
    message_type="template",
    content={
        "templateId": "tpl_abc123",
        "templateVariables": {"1": "John", "2": "ORD-12345"},
    },
)
typescript
await zavu.messages.send({
  to: "+14155551234",
  messageType: "template",
  content: {
    templateId: "tpl_abc123",
    templateVariables: { "1": "John", "2": "ORD-12345" },
  },
});
Python:
python
zavu.messages.send(
    to="+14155551234",
    message_type="template",
    content={
        "templateId": "tpl_abc123",
        "templateVariables": {"1": "John", "2": "ORD-12345"},
    },
)

Template Lifecycle

模板生命周期

draft -> pending (submitted to Meta) -> approved (ready to use)
                                     -> rejected (edit and resubmit)
draft(草稿)-> pending(已提交至Meta审核)-> approved(已通过,可使用)
                                     -> rejected(已拒绝,编辑后重新提交)

Other Operations

其他操作

typescript
// List templates
const templates = await zavu.templates.list({ limit: 50 });
for (const tpl of templates.items) {
  console.log(tpl.id, tpl.name, tpl.status);
}

// Get template
const tpl = await zavu.templates.get({ templateId: "tpl_abc123" });

// Delete template (draft only)
await zavu.templates.delete({ templateId: "tpl_abc123" });
typescript
// 列出模板
const templates = await zavu.templates.list({ limit: 50 });
for (const tpl of templates.items) {
  console.log(tpl.id, tpl.name, tpl.status);
}

// 获取模板详情
const tpl = await zavu.templates.get({ templateId: "tpl_abc123" });

// 删除模板(仅草稿状态可删除)
await zavu.templates.delete({ templateId: "tpl_abc123" });

Constraints

约束条件

  • Template names: lowercase, underscores only (e.g.,
    order_confirmation
    )
  • Variables use positional format:
    {{1}}
    ,
    {{2}}
    ,
    {{3}}
  • Max 3 buttons per template
  • Button text: max 25 characters
  • OTP
    ONE_TAP
    requires Android
    packageName
    and
    signatureHash
  • addSecurityRecommendation
    only for AUTHENTICATION templates
  • codeExpirationMinutes
    : 1-90, only for AUTHENTICATION
  • Meta approval typically takes minutes to hours, but can take up to 24h
  • Rejected templates can be edited and resubmitted
  • 模板名称:仅允许小写字母和下划线(例如:
    order_confirmation
  • 变量使用位置格式:
    {{1}}
    ,
    {{2}}
    ,
    {{3}}
  • 每个模板最多支持3个按钮
  • 按钮文本:最多25个字符
  • OTP
    ONE_TAP
    功能需要安卓的
    packageName
    signatureHash
  • addSecurityRecommendation
    仅适用于AUTHENTICATION类模板
  • codeExpirationMinutes
    :取值范围1-90,仅适用于AUTHENTICATION类模板
  • Meta审核通常需要几分钟到几小时,最长可能需要24小时
  • 被拒绝的模板可编辑后重新提交