Skip to main content
Templates are pre-approved message formats required for contacting users outside the 24-hour conversation window. They must be submitted to Meta for approval before use.

Why Templates?

  • Required by WhatsApp - Only way to message users outside 24-hour window
  • Consistency - Ensure uniform messaging across your team
  • Compliance - Meta reviews content for quality and policy compliance
  • Analytics - Track performance by template

Quick Start: Send a Template Message

If you already have an approved template, here’s how to send it with variables:
const message = await zavu.messages.send({
  to: "+56912345678",
  messageType: "template",
  content: {
    templateId: "tpl_abc123",
    templateVariables: {
      "1": "John",
      "2": "ORD-12345",
      "3": "January 20, 2025"
    }
  }
});

How Variables Work

Template variables use positional numbering: {{1}}, {{2}}, {{3}}, etc. When sending, pass the values as an object where keys are the position numbers:
Template body:  "Hi {{1}}, your order #{{2}} is confirmed. Delivery: {{3}}."
                     ^              ^                              ^
                     |              |                              |
Variables:      "1": "John"   "2": "ORD-12345"          "3": "January 20, 2025"
You must provide values for all variables defined in the template. Missing variables will cause the message to fail.

Full Workflow

Templates follow a 3-step process: Create -> Submit for Approval -> Send.

Step 1: Create a Template

const template = await zavu.templates.create({
  name: "order_confirmation",
  language: "en",
  body: "Hi {{1}}, your order #{{2}} has been confirmed! Estimated delivery: {{3}}.",
  whatsappCategory: "UTILITY",
  variables: ["customer_name", "order_id", "delivery_date"]
});

console.log(template.id);     // "tpl_abc123"
console.log(template.status); // "draft"
The variables array is optional and purely for documentation - it helps you remember what each position represents.

Step 2: Submit for Approval

Templates start in draft status. You need to explicitly submit them to Meta for review:
const submitted = await zavu.templates.submit("tpl_abc123", {
  senderId: "sender_12345",
  category: "UTILITY"
});

console.log(submitted.status); // "pending"
The senderId must be a sender with a WhatsApp Business Account connected. The template is submitted to Meta through that WABA.

Step 3: Check Approval Status

curl https://api.zavu.dev/v1/templates/tpl_abc123 \
  -H "Authorization: Bearer zv_live_xxx"
{
  "id": "tpl_abc123",
  "name": "order_confirmation",
  "status": "approved",
  "category": "UTILITY",
  "body": "Hi {{1}}, your order #{{2}} has been confirmed! Estimated delivery: {{3}}.",
  "variables": ["customer_name", "order_id", "delivery_date"]
}
StatusDescription
draftCreated but not yet submitted to Meta
pendingSubmitted, awaiting Meta review
approvedReady to use
rejectedNot approved - check rejection reason
Only approved templates can be used to send messages. Attempting to use draft, pending, or rejected templates will fail.

Step 4: Send the Template

Once approved, send it using the positional variables (see Quick Start above).

Template Categories

CategoryUse CaseApproval Speed
UTILITYOrder updates, shipping, account alertsFast (hours)
MARKETINGPromotions, offers, newslettersSlower (days)
AUTHENTICATIONOTPs, verification codesFast (hours)
Choose the category that best matches your use case. Miscategorization can lead to rejection.

Templates with Buttons

Add call-to-action or quick reply buttons:
curl -X POST https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "order_delivered",
    "language": "en",
    "body": "Hi {{1}}, your order has been delivered!",
    "whatsappCategory": "UTILITY",
    "variables": ["customer_name"],
    "buttons": [
      {
        "type": "url",
        "text": "Track Order",
        "url": "https://example.com/track/{{1}}"
      },
      {
        "type": "quick_reply",
        "text": "Rate Delivery"
      }
    ]
  }'

Button Types

TypeDescriptionMax
quick_replyUser response button3 buttons
urlOpens a URL (can include variables)-
phoneInitiates a phone call-
otpCopy code / one-tap autofill for authentication-

Authentication Templates (OTP)

For verification codes, use AUTHENTICATION category with OTP buttons:
curl -X POST https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "login_otp",
    "language": "en",
    "body": "{{1}} is your verification code.",
    "whatsappCategory": "AUTHENTICATION",
    "variables": ["otp_code"],
    "buttons": [
      {
        "type": "otp",
        "text": "Copy Code",
        "otpType": "COPY_CODE"
      }
    ],
    "addSecurityRecommendation": true,
    "codeExpirationMinutes": 5
  }'
Send the OTP:
curl -X POST https://api.zavu.dev/v1/messages \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+56912345678",
    "messageType": "template",
    "content": {
      "templateId": "tpl_otp123",
      "templateVariables": {
        "1": "482910"
      }
    }
  }'
See the OTP Templates guide for more details.

Managing Templates

List Templates

curl https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx"

Delete Template

curl -X DELETE https://api.zavu.dev/v1/templates/tpl_abc123 \
  -H "Authorization: Bearer zv_live_xxx"

Best Practices

Naming Conventions

Use descriptive, lowercase names with underscores:
order_confirmation
shipping_update
password_reset
appointment_reminder
promotional_offer

Content Guidelines

Do:
  • Use clear, concise language
  • Include dynamic variables for personalization
  • Provide value to the recipient
  • Test with real data before production use
Don’t:
  • Use placeholder text like “[insert name]”
  • Include excessive capitalization or punctuation
  • Send promotional content without consent
  • Use misleading or clickbait content

Common Rejection Reasons

ReasonSolution
Variable syntax errorUse {{1}}, {{2}} positional format
Category mismatchChoose correct category for content
Promotional in UTILITYUse MARKETING category for promotions
Missing opt-outInclude unsubscribe option for marketing
Policy violationReview Meta’s commerce and messaging policies

Testing Templates

Test with your own phone number before sending to customers:
curl -X POST https://api.zavu.dev/v1/messages \
  -H "Authorization: Bearer zv_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+your_phone_number",
    "messageType": "template",
    "content": {
      "templateId": "tpl_abc123",
      "templateVariables": {
        "1": "Test User",
        "2": "TEST-001",
        "3": "Tomorrow"
      }
    }
  }'
Use test mode API keys (zv_test_xxx) during development to avoid charges.