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

Creating a Template

Define Your Template

const template = await zavu.templates.create({
  name: "order_confirmation",
  category: "transactional",
  language: "en",
  body: "Hi {{customerName}}, your order #{{orderId}} has been confirmed! Estimated delivery: {{deliveryDate}}."
});

Variable Syntax

Use double curly braces for dynamic content:
Hi {{customerName}}, your order #{{orderId}} has been confirmed!
Variables are automatically extracted and validated when sending.

Template Categories

CategoryUse CaseApproval Speed
transactionalOrder updates, shipping, receiptsFast (hours)
marketingPromotions, offers, newslettersSlower (days)
authenticationOTPs, verification codesFast (hours)
utilityAccount updates, alertsFast (hours)
Choose the category that best matches your use case. Miscategorization can lead to rejection.

Approval Process

1. Submit Template

Templates are automatically submitted to Meta when created through the API.

2. Check Status

curl https://api.zavu.dev/v1/templates/tpl_abc123 \
  -H "Authorization: Bearer zv_live_xxx"
Response:
{
  "id": "tpl_abc123",
  "name": "order_confirmation",
  "status": "pending",
  "category": "transactional",
  "body": "Hi {{customerName}}, your order #{{orderId}} has been confirmed!..."
}

3. Status Values

StatusDescription
pendingSubmitted, awaiting Meta review
approvedReady to use
rejectedNot approved - see rejection reason
Only approved templates can be used to send messages. Attempting to use pending or rejected templates will fail.

Sending Template Messages

Once approved, use the template by ID:
const message = await zavu.messages.send({
  to: "+56912345678",
  messageType: "template",
  content: {
    templateId: "tpl_abc123",
    templateVariables: {
      customerName: "John",
      orderId: "12345",
      deliveryDate: "January 20, 2024"
    }
  }
});

Templates with Media

Include images, videos, or documents in templates:
curl -X POST https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "shipping_update_with_image",
    "category": "transactional",
    "language": "en",
    "header": {
      "type": "image"
    },
    "body": "Hi {{customerName}}, your package is on the way! Track: {{trackingUrl}}"
  }'
When sending, provide the media URL:
{
  "to": "+56912345678",
  "messageType": "template",
  "content": {
    "templateId": "tpl_abc123",
    "header": {
      "mediaUrl": "https://example.com/package-photo.jpg"
    },
    "templateVariables": {
      "customerName": "John",
      "trackingUrl": "https://track.co/abc"
    }
  }
}

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",
    "category": "transactional",
    "language": "en",
    "body": "Hi {{customerName}}, your order has been delivered!",
    "buttons": [
      {
        "type": "url",
        "text": "Track Order",
        "url": "https://example.com/track/{{orderId}}"
      },
      {
        "type": "quick_reply",
        "text": "Rate Delivery"
      }
    ]
  }'

Button Types

TypeDescription
quick_replyUser response button
urlOpens a URL (can include variables)
phone_numberInitiates a phone call

Managing Templates

List Templates

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

Update Template

curl -X PATCH https://api.zavu.dev/v1/templates/tpl_abc123 \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi {{customerName}}! Order #{{orderId}} confirmed. Arriving {{deliveryDate}}."
  }'
Updating an approved template requires re-approval from Meta.

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, consistent names:
order_confirmation
shipping_update
password_reset
appointment_reminder
promotional_offer

Version Control

Include version in template names for updates:
order_confirmation_v1
order_confirmation_v2

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 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": {
        "customerName": "Test User",
        "orderId": "TEST-001"
      }
    }
  }'
Use test mode API keys (zv_test_xxx) during development to avoid charges.