Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.zavu.dev/llms.txt

Use this file to discover all available pages before exploring further.

Templates

Templates are reusable message formats for sending structured messages across WhatsApp, SMS, Telegram, Instagram, and Email. They are especially important for WhatsApp, which requires template approval for business-initiated conversations.

Why Templates?

Templates solve three key problems:
  1. WhatsApp Compliance: Meta requires businesses to use approved templates when initiating conversations outside the 24-hour window
  2. Consistency: Ensure your transactional messages follow a consistent format
  3. Multi-Channel Delivery: Define one template with channel-specific bodies, then send it on any channel

Template Structure

A template consists of:
{
  "id": "tmpl_abc123",
  "name": "order_confirmation",
  "language": "en",
  "body": "Hi {{1}}, your order {{2}} has been confirmed!",
  "category": "UTILITY",
  "variables": ["customer_name", "order_id"],
  "status": "approved"
}

Fields

FieldDescription
nameUnique identifier (lowercase, underscores)
languageLanguage code (e.g., “en”, “es”, “pt”)
bodyMessage text with variable placeholders
categoryWhatsApp category (required for WhatsApp submission, optional for other channels)
variablesList of variable names for documentation
statusApproval status

Template Variables

Templates support dynamic content through variables. Two formats are supported:

Numbered Variables (WhatsApp Native)

Use {{1}}, {{2}}, {{3}} for WhatsApp compatibility:
"Hi {{1}}, your order {{2}} ships on {{3}}"

Named Variables

Use {{name}} for better readability:
"Hi {{customer_name}}, your order {{order_id}} ships on {{date}}"
Named variables are automatically converted to numbered format when sending via WhatsApp.

Contact Variables

Use {{contact.*}} variables to auto-resolve values from the recipient’s contact metadata:
VariableResolved From
{{contact.first_name}}Contact metadata first_name
{{contact.last_name}}Contact metadata last_name
{{contact.phone}}Contact’s phone number
{{contact.email}}Contact’s primary email
{{contact.country}}Contact’s country code
{{contact.custom_field}}Any custom metadata field
"Hola {{contact.first_name}}, tu pedido esta listo."
When the message is sent, Zavu looks up the recipient’s contact record and replaces these variables automatically. If the contact doesn’t exist or the field is empty, the variable is replaced with an empty string.
Contact variables work on all channels: SMS, Telegram, Instagram, and Email. You can also pass explicit values via templateVariables as a fallback.

WhatsApp Categories

WhatsApp requires every template to be categorized:
CategoryUse CaseExamples
UTILITYTransactional messagesOrder confirmations, shipping updates, appointment reminders
MARKETINGPromotional contentSales, offers, newsletters
AUTHENTICATIONVerification codesOTPs, login codes, 2FA
Marketing templates have stricter approval requirements and may have different pricing. Use UTILITY for transactional messages.

Authentication Templates

Authentication templates are used for sending verification codes (OTPs) to users. These templates have special requirements and behavior.

Requirements

Meta requires your WhatsApp Business Account to meet these criteria before you can create AUTHENTICATION templates:
  1. Business Verification: Your business must be verified by Meta
  2. Conversation History: At least 2,000 business-initiated conversations in the last 30 days
If your account doesn’t meet these requirements, AUTHENTICATION templates will fail with a permission error.

How Authentication Templates Work

Unlike regular templates, authentication templates have a pre-defined message format controlled by Meta. When you create an authentication template:
  • The message body is automatically generated by Meta
  • The format is: {{1}} is your verification code.
  • You cannot customize the body text

OTP Button Types

Authentication templates support two types of OTP buttons:
Button TypeDescriptionUse Case
COPY_CODEShows a “Copy Code” buttonUser manually copies and pastes the code
ONE_TAPEnables Android autofillAutomatic code entry on Android devices

ONE_TAP Button Requirements

For ONE_TAP buttons (Android autofill), you must provide:
{
  "buttons": [{
    "type": "otp",
    "text": "Autofill",
    "otpType": "ONE_TAP",
    "packageName": "com.yourapp.package",
    "signatureHash": "your_app_signature_hash"
  }]
}
FieldDescription
packageNameYour Android app’s package name
signatureHashYour Android app’s signature hash for SMS verification

Optional Security Features

Authentication templates can include:
FeatureDescription
addSecurityRecommendationAdds “Do not share this code with anyone” disclaimer
codeExpirationMinutesShows expiration time (1-90 minutes) in footer

Creating an Authentication Template

curl -X POST https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "verification_code",
    "language": "en",
    "body": "",
    "whatsappCategory": "AUTHENTICATION",
    "buttons": [{
      "type": "otp",
      "text": "Copy Code",
      "otpType": "COPY_CODE"
    }],
    "addSecurityRecommendation": true,
    "codeExpirationMinutes": 10
  }'
The body field should be empty or omitted for authentication templates. Meta will automatically generate the message body.

WhatsApp Approval Workflow

WhatsApp templates must be approved by Meta before use:
Create Template (draft)
        |
        v
Submit to WhatsApp (pending)
        |
        v
Meta Reviews (24-48 hours)
        |
    +---+---+
    |       |
Approved  Rejected
    |       |
    v       v
Ready    Fix & Resubmit

Template Statuses

StatusDescription
draftCreated but not submitted
pendingSubmitted, awaiting Meta review
approvedReady to use
rejectedRejected by Meta (see reason)

Creating Templates

Via API

curl -X POST https://api.zavu.dev/v1/templates \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "order_shipped",
    "language": "en",
    "body": "Hi {{1}}, your order {{2}} has shipped and will arrive by {{3}}.",
    "whatsappCategory": "UTILITY",
    "variables": ["customer_name", "order_id", "delivery_date"]
  }'

Response

{
  "id": "tmpl_xyz789",
  "name": "order_shipped",
  "language": "en",
  "body": "Hi {{1}}, your order {{2}} has shipped...",
  "category": "UTILITY",
  "status": "draft",
  "variables": ["customer_name", "order_id", "delivery_date"],
  "createdAt": "2025-01-15T10:30:00Z"
}

Rich Template Components

WhatsApp templates can include rich components: Add a header with text, image, video, or document:
{
  "headerType": "image",
  "headerContent": "https://example.com/logo.png"
}
Add a footer text:
{
  "footer": "Reply STOP to unsubscribe"
}

Buttons

Add interactive buttons:
{
  "buttons": [
    {
      "type": "quick_reply",
      "text": "Track Order"
    },
    {
      "type": "url",
      "text": "View Details",
      "url": "https://example.com/orders/{{1}}"
    }
  ]
}

Sending Template Messages

To send a template message, specify the template ID and variables:
await client.messages.send({
  to: "+14155551234",
  messageType: "template",
  content: {
    templateId: "tmpl_abc123",
    templateVariables: {
      "1": "John",
      "2": "ORD-12345",
      "3": "January 20th"
    }
  }
});

Templates with Dynamic URL Buttons

If your template has a URL button with a {{1}} placeholder (e.g., https://example.com/orders/{{1}}), pass the value through templateButtonVariables. Keys are the button index (0-based) in the template’s buttons array.
curl -X POST https://api.zavu.dev/v1/messages \
  -H "Authorization: Bearer zv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155551234",
    "messageType": "template",
    "content": {
      "templateId": "tmpl_abc123",
      "templateVariables": {
        "1": "John"
      },
      "templateButtonVariables": {
        "0": "ORD-12345"
      }
    }
  }'
FieldKeysWhat it substitutes
templateVariablesPosition in body ("1", "2", …)Body placeholders
templateButtonVariablesButton index ("0", "1", "2")The {{1}} placeholder inside that button’s URL
WhatsApp URL buttons only accept {{1}} (positional, single digit, no whitespace, no name). Named or padded placeholders like {{token}} or {{ 1 }} are stored as literal text and cannot be substituted. See the WhatsApp templates guide for the full ruleset.

Multi-Channel Templates

Templates support channel-specific bodies. When a message is sent, Zavu uses the channel-specific body if available, falling back to the default body.
{
  "name": "order_confirmation",
  "body": "Hi {{1}}, your order {{2}} is confirmed!",
  "smsBody": "Order {{2}} confirmed for {{1}}. Track at example.com",
  "telegramBody": "Hi {{1}}, your order {{2}} is confirmed! Check your Telegram for updates.",
  "instagramBody": "Hi {{1}}! Order {{2}} confirmed.",
  "emailSubject": "Order {{2}} Confirmed",
  "emailHtmlBody": "<h1>Order Confirmed</h1><p>Hi {{1}}...</p>"
}
FieldChannelFallback
bodyDefault for all channels-
smsBodySMS, SMS One-Waybody
telegramBodyTelegrambody
instagramBodyInstagrambody
emailSubjectEmail subject-
emailHtmlBodyEmail HTML bodybody (plain text)

Sending Templates on Different Channels

curl -X POST https://api.zavu.dev/v1/messages \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "123456789",
    "channel": "telegram",
    "messageType": "template",
    "content": {
      "templateId": "tmpl_abc123",
      "templateVariables": { "1": "John", "2": "ORD-12345" }
    }
  }'
WhatsApp templates require Meta approval before use. Templates on SMS, Telegram, and Instagram do not require external approval.

Managing Templates

List Templates

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

Get Template

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

Delete Template

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

Best Practices

Keep It Short

WhatsApp has character limits. Keep your templates concise and actionable.

Use UTILITY Category

For transactional messages, always use UTILITY to improve approval chances.

Test Before Launch

Create templates early in development. Approval can take 24-48 hours.

Handle Rejections

If rejected, review Meta’s guidelines, fix the issue, and resubmit.

Common Rejection Reasons

ReasonSolution
Promotional content in UTILITYChange category to MARKETING or remove promotional language
Missing variable examplesProvide clear example values for each variable
Inappropriate contentReview WhatsApp commerce policy
Poor grammar/spellingProofread and fix language errors

Next Steps

WhatsApp Templates

Deep dive into WhatsApp template features

Senders

Learn how templates work with senders