mcpField
W
whatsapp-templates

whatsapp-templates

github.com/zavudevマーケティング・グロース1265 回インストール今日更新
リポジトリ

whatsapp-templates について

Zavu を使う開発者向けに、WhatsApp テンプレートメッセージの作成、申請、管理、送信方法を説明します。カテゴリ、チャネル別本文、Meta の承認、状態同期も扱います。

主な機能

  1. 01変数やボタン付きテンプレートの作成
  2. 02ユーティリティ、マーケティング、認証カテゴリの利用
  3. 03チャネル別メッセージ本文の設定
  4. 04Meta へのテンプレート審査申請
  5. 05WhatsApp の状態とカテゴリの同期
  6. 06承認済みテンプレートへの変数指定と送信

活用シーン

  1. 01注文や配送状況の通知
  2. 02販促や一斉配信
  3. 03OTP や認証コードの送信
  4. 04Meta Business Manager で作成したテンプレートの同期

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zavudev/zavu-skills --skill whatsapp-templates

インストール後、Claude Code で/whatsapp-templatesを入力して読み込まれたか確認します。

詳細

WhatsApp テンプレート

使用するタイミング

WhatsApp テンプレートメッセージを作成、管理、または送信するコードを構築するときに、このスキルを使用します。24 時間のウィンドウ外で会話を開始するには、テンプレートが必要です。

テンプレートが必要な場合

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

テンプレートのカテゴリ

カテゴリ使用例例
UTILITY取引に関する更新注文確認、配送状況の更新、予約のリマインダー
MARKETINGプロモーションコンテンツセール、オファー、製品のお知らせ
AUTHENTICATIONOTP/認証コードログインコード、2FA、パスワードのリセット

テンプレートの作成

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:

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:

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:

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:

$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'],
]);

チャネル固有の本文

テンプレートでは、チャネルごとに異なる本文を設定できます。デフォルトの body は WhatsApp で使用されます。チャネル固有の本文が設定されていない場合、SMS、Telegram、Instagram では body が使用されます。

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 は WhatsApp の body にのみ適用されます。チャネル固有の本文にはカテゴリは必要ありません。

ボタン付きテンプレート

// 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" },
  ],
});

// Contact info request button — asks the recipient to share their phone number.
// Label is fixed by WhatsApp ("Share Contact Info"), so `text` is not required.
// Useful for contacts who adopted a WhatsApp username (known only by BSUID).
const template = await zavu.templates.create({
  name: "callback_request",
  language: "en",
  body: "Hi {{1}}, we need a phone number to schedule your callback.",
  whatsappCategory: "UTILITY",
  variables: ["customer_name"],
  buttons: [
    { type: "request_contact_info" },
  ],
});

OTP 認証テンプレート

// 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",
    },
  ],
});

Meta の承認に申請する

テンプレートは使用前に Meta の承認が必要です。

// Submit template for review
const submitted = await zavu.templates.submit({
  templateId: "tpl_abc123",
  senderId: "snd_abc123",
  category: "UTILITY",
});
console.log(submitted.status); // "pending"

Webhook(template.status_changed イベント)またはポーリングで承認状況を確認します。

const template = await zavu.templates.get({ templateId: "tpl_abc123" });
console.log(template.status); // draft | pending | approved | rejected

カテゴリを決めるのは Meta です

申請するカテゴリはリクエストです。適用されるカテゴリは Meta が決定し、変更されることがあります。承認時、またはすでに公開済みのテンプレートで数か月後に変更されることもあり、特に UTILITY から MARKETING への変更がよくあります。この変更によって、そのテンプレートを使ったすべての送信の料金が変わります。

template.category はMeta が現在割り当てているカテゴリを返すため、申請時のカテゴリが今も有効だと思い込まず、値を読み取ってください。

const template = await zavu.templates.get({ templateId: "tpl_abc123" });
console.log(template.category); // UTILITY | MARKETING | AUTHENTICATION

カテゴリの再分類は、data.category を含む template.status_changed Webhook として届きます。承認ステータスが変わらなくても発火するため、再分類時のイベントでは previousStatus と currentStatus が同じ値になります。currentStatus だけでなく、category を基準に分岐してください。

if (event.type === "template.status_changed") {
  const { templateId, currentStatus, category } = event.data;
  if (category !== myStoredCategory(templateId)) {
    // Meta moved the billing category. Reprice before the next send.
  }
}

監視を開始する前に変更されたテンプレートの状態を同期するには、POST /v1/templates/sync を実行してください。詳細は以下をご覧ください。

WhatsApp からテンプレートを同期する

Zavu 以外(Meta Business Manager または別のツール)で作成されたテンプレートは、インポートするまで Zavu に存在しません。template.status_changed Webhook を受信できなかった場合、テンプレートはいつまでも pending のままになります。また、監視が行われていない間に Meta がカテゴリを再分類したテンプレートは、以前のカテゴリを報告し続けます。POST /v1/templates/sync を実行すると、これらの問題をすべて解決できます。Zavu にない Meta のテンプレートをインポート(または同名の既存テンプレートにリンク)し、既存テンプレートのステータスとカテゴリの両方を更新します。

カテゴリは変わったもののステータスは変わっていないテンプレートも、updated にカウントされます。このケースに対処することが、この操作を実行する目的のひとつです。

SDK ではまだ生成されていないため、REST 経由で呼び出してください。

# Sync every WhatsApp sender in the project
curl -X POST https://api.zavu.dev/v1/templates/sync \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

# Or scope it to one sender's WhatsApp Business Account
curl -X POST https://api.zavu.dev/v1/templates/sync \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"senderId": "snd_abc123"}'
{
  "accountsSynced": 1,
  "imported": 2,
  "linked": 1,
  "updated": 3,
  "skipped": 12,
  "errors": []
}
  • この呼び出しは同期処理です。Meta からの応答を待つため、アカウントごとに数秒かかることがあります。結果を確認するには、直後にテンプレート一覧を取得してください。
  • skipped は処理対象外となった Meta のテンプレート数です。すでにリンク済みのもの、または Meta 側で拒否/無効化されているものが該当します(これらはインポートされません)。
  • HTTP 200 でも errors が空でない場合は、1 つのアカウントでエラーが発生しています。その他のアカウントの同期は完了しています。
  • プロジェクト内の送信元に WhatsApp Business Account がない場合は、400 を返します。

テンプレートメッセージの送信

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

Python:

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

テンプレートのライフサイクル

draft -> pending (submitted to Meta) -> approved (ready to use)
                                     -> rejected (edit and resubmit)

その他の操作

// 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" });

制約

  • テンプレート名:小文字とアンダースコアのみを使用してください(例:order_confirmation)。プロジェクト内で一意である必要があります。同じ名前のテンプレートを2つ目に作成すると、409 conflict が返されます
  • 変数には位置形式を使用します:{{1}}、{{2}}、{{3}}
  • WhatsApp の変数値には、改行、タブ、または4つを超える連続したスペースを含められません。Meta は配信時にこれらを拒否するため、Zavu は送信を拒否し、400 invalid_request を返して details.field に該当する値を示します。送信前に(例:· に)置き換えてください。SMS と Telegram のテンプレートでは使用できます
  • テンプレートあたりボタンは最大3つです
  • ボタンのテキスト:最大25文字(request_contact_info では使用されません。WhatsApp がラベルを固定します)
  • OTP の ONE_TAP には Android の packageName と signatureHash が必要です
  • addSecurityRecommendation は AUTHENTICATION テンプレートでのみ使用できます
  • codeExpirationMinutes:1~90。AUTHENTICATION でのみ使用できます
  • Meta の承認には通常、数分から数時間かかりますが、最大24時間かかる場合があります
  • 拒否されたテンプレートは編集して再送信できます

コメント