WhatsApp Template Handler Documentation
Overview
This document describes the WhatsApp template API endpoints, template schema, validation rules, supported languages, component types, and provides real-world examples. It integrates internal gateway-layer logic and official Meta documentation.
Endpoints
POST /v2/whatsapp/templates
Create a new WhatsApp template.DELETE /v2/whatsapp/templates
Delete an existing WhatsApp template.GET /v2/whatsapp/templates
List all WhatsApp templates.POST /v2/whatsapp/templates/update
Update an existing WhatsApp template.
Rules:- Templates with status REJECTED or PAUSED can be updated freely.
- Templates with status APPROVED can only be updated once every 24 hours.
POST /v2/whatsapp/upload
Upload media for use in templates.
Template Schema
CreateTemplateRequest
type CreateTemplateRequest struct {
Name string // Template name
Category string // e.g. "UTILITY", "MARKETING"
Language string // Language code (see Supported Languages)
Compose TemplateCompose // Compose structure for sending
Creation []Component // Components for registration
}
Component
type Component struct {
Type string // "HEADER", "BODY", "FOOTER", "BUTTONS", "CAROUSEL"
Format string // "TEXT", "IMAGE", "VIDEO", "DOCUMENT", "LOCATION"
Text string
Example *Example
Buttons []Button
Cards []Card
}
Button
type Button struct {
Type string // "QUICK_REPLY", "URL", "PHONE_NUMBER", "COPY_CODE"
Text string
URL string
PhoneNumber string
Example interface{}
}
Supported Languages
WhatsApp templates support a wide range of languages.
Reference: Meta Supported Languages
Example codes:
- English (US):
en_US - Arabic:
ar - French:
fr - Turkish:
tr - ... (see full list in the link above)
Component Types & Rules
HEADER
| Property | Description | Example Value |
|---|---|---|
| type | Must be "HEADER" | "HEADER" |
| format | "TEXT", "IMAGE", "VIDEO", "DOCUMENT", "LOCATION" | "TEXT" |
| text | Header text (if format is TEXT) | "Our new sale starts {{1}}!" |
| example.header_text | Required if text contains variables (TEXT format) | ["December 1st"] |
| example.header_handle | Required if format is IMAGE/VIDEO/DOCUMENT, must be valid URL/handle.<br>Allowed sizes: IMAGE: 5MB, VIDEO: 16MB, DOCUMENT: 100MB | ["https://example.com/image.jpg"] |
Rules:
- Only one HEADER per template.
- If using variables in text, must provide
example.header_text. - For media, must provide valid
example.header_handle. - LOCATION format only for UTILITY or MARKETING categories.
BODY
| Property | Description | Example Value |
|---|---|---|
| type | Must be "BODY" | "BODY" |
| text | Body text, supports variables | "Thank you, {{1}}!" |
| example.body_text | Required if text contains variables | [["John", "ORD-12345"]] |
Rules:
- Required. Only one BODY per template.
- If using variables, must provide
example.body_text.
FOOTER
| Property | Description | Example Value |
|---|---|---|
| type | Must be "FOOTER" | "FOOTER" |
| text | Footer text | "Reply to this message for support." |
Rules:
- Optional. Only one FOOTER per template.
- Text only, max 60 characters.
BUTTONS
| Property | Description | Example Value |
|---|---|---|
| type | Must be "BUTTONS" | "BUTTONS" |
| buttons | Array of button objects (see below) | [...] |
Button Types Table:
| Button Type | Required Fields | Limits / Notes | Example Value |
|---|---|---|---|
| QUICK_REPLY | text | Max 10 per template, must be grouped | { "type": "QUICK_REPLY", "text": "Unsubscribe" } |
| URL | text, url, example (if variable) | Max 2 per template | { "type": "URL", "text": "Shop", "url": "https://..." } |
| PHONE_NUMBER | text, phone_number | Max 1 per template | { "type": "PHONE_NUMBER", "text": "Call", "phone_number": "15550051310" } |
| COPY_CODE | example | Max 1 per template, max 15 chars | { "type": "COPY_CODE", "example": "250FF" } |
Rules:
- Optional. Only one BUTTONS component per template.
- Max 10 buttons total, with per-type limits above.
- Quick replies must be grouped together.
- For URL buttons with variables, must provide
example.
CAROUSEL
- Optional. Used for advanced templates (see Meta docs).
Validation Rules
- Only one of each: HEADER, BODY, FOOTER, BUTTONS per template.
- HEADER with variables requires
example.header_text. - Media HEADER requires valid
example.header_handle(must be a valid URL/handle). - BODY with variables requires
example.body_text. - FOOTER must have text.
- BUTTONS:
- QUICK_REPLY: must have text.
- URL: must have text and url; if url has variables, must provide example.
- PHONE_NUMBER: must have text and phone_number.
- COPY_CODE: must provide example.
- Max 10 buttons total, with per-type limits as above.
- Templates with status REJECTED or PAUSED can be updated freely.
- Templates with status APPROVED can only be updated once every 24 hours.
Template Statuses
The following table lists possible statuses for WhatsApp templates:
| Status | Description |
|---|---|
| submitted | The template has been submitted for review. |
| under_review | The template is currently being reviewed by WhatsApp/Meta. |
| rejected | The template was reviewed and rejected. |
| approved | The template was reviewed and approved for use. |
| submit_failed | The template submission failed due to validation or other errors. |
Examples
1. Simple Template
{
"name": "welcome_simple",
"category": "UTILITY",
"language": "en_US",
"creation": [
{
"type": "BODY",
"text": "Welcome to our service! We're glad to have you here."
}
]
}
2. Template with Variables
{
"name": "order_confirmation",
"category": "UTILITY",
"language": "en_US",
"creation": [
{
"type": "HEADER",
"format": "TEXT",
"text": "Order Confirmation"
},
{
"type": "BODY",
"text": "Thank you for your order, {{1}}! Your order number is {{2}} and will be delivered on {{3}}.",
"example": {
"body_text": [["John", "ORD-12345", "May 10th"]]
}
},
{
"type": "FOOTER",
"text": "Reply to this message for support."
}
]
}
3. Template with Buttons
{
"name": "feedback_request",
"category": "MARKETING",
"language": "en_US",
"creation": [
{
"type": "BODY",
"text": "How was your experience with us? We'd love to hear your feedback!"
},
{
"type": "BUTTONS",
"buttons": [
{ "type": "QUICK_REPLY", "text": "Leave Feedback" },
{
"type": "URL",
"text": "Visit Website",
"url": "https://example.com"
},
{
"type": "PHONE_NUMBER",
"text": "Call Us",
"phone_number": "+15551234567"
}
]
}
]
}
4. Template with Media
{
"name": "product_promotion",
"category": "MARKETING",
"language": "en_US",
"creation": [
{
"type": "HEADER",
"format": "IMAGE",
"example": {
"header_handle": ["https://example.com/product.jpg"]
}
},
{
"type": "BODY",
"text": "Check out our new product! Limited time offer: {{1}}% off until {{2}}.",
"example": {
"body_text": [["25", "May 31st"]]
}
},
{
"type": "FOOTER",
"text": "Terms and conditions apply."
},
{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "Shop Now", "url": "https://example.com/shop" }
]
}
]
}
5. Template with Location Header
{
"name": "order_delivery_update",
"category": "UTILITY",
"language": "en_US",
"creation": [
{
"type": "HEADER",
"format": "LOCATION"
},
{
"type": "BODY",
"text": "Good news {{1}}! Your order #{{2}} is on its way to the location above.",
"example": {
"body_text": [["Mark", "566701"]]
}
},
{
"type": "FOOTER",
"text": "To stop receiving delivery updates, tap the button below."
},
{
"type": "BUTTONS",
"buttons": [{ "type": "QUICK_REPLY", "text": "Stop Delivery Updates" }]
}
]
}
Supported Languages Table
| Language | Code |
|---|---|
| Afrikaans | af |
| Albanian | sq |
| Arabic | ar |
| Arabic (EGY) | ar_EG |
| Arabic (UAE) | ar_AE |
| Arabic (LBN) | ar_LB |
| Arabic (MAR) | ar_MA |
| Arabic (QAT) | ar_QA |
| Azerbaijani | az |
| Belarusian | be_BY |
| Bengali | bn |
| Bengali (IND) | bn_IN |
| Bulgarian | bg |
| Catalan | ca |
| Chinese (CHN) | zh_CN |
| Chinese (HKG) | zh_HK |
| Chinese (TAI) | zh_TW |
| Croatian | hr |
| Czech | cs |
| Danish | da |
| Dari | prs_AF |
| Dutch | nl |
| Dutch (BEL) | nl_BE |
| English | en |
| English (UK) | en_GB |
| English (US) | en_US |
| English (UAE) | en_AE |
| English (AUS) | en_AU |
| English (CAN) | en_CA |
| English (GHA) | en_GH |
| English (IRL) | en_IE |
| English (IND) | en_IN |
| English (JAM) | en_JM |
| English (MYS) | en_MY |
| English (NZL) | en_NZ |
| English (QAT) | en_QA |
| English (SGP) | en_SG |
| English (UGA) | en_UG |
| English (ZAF) | en_ZA |
| Estonian | et |
| Filipino | fil |
| Finnish | fi |
| French | fr |
| French (BEL) | fr_BE |
| French (CAN) | fr_CA |
| French (CHE) | fr_CH |
| French (CIV) | fr_CI |
| French (MAR) | fr_MA |
| Georgian | ka |
| German | de |
| German (AUT) | de_AT |
| German (CHE) | de_CH |
| Greek | el |
| Gujarati | gu |
| Hausa | ha |
| Hebrew | he |
| Hindi | hi |
| Hungarian | hu |
| Indonesian | id |
| Irish | ga |
| Italian | it |
| Japanese | ja |
| Kannada | kn |
| Kazakh | kk |
| Kinyarwanda | rw_RW |
| Korean | ko |
| Kyrgyz (Kyrgyzstan) | ky_KG |
| Lao | lo |
| Latvian | lv |
| Lithuanian | lt |
| Macedonian | mk |
| Malay | ms |
| Malayalam | ml |
| Marathi | mr |
| Norwegian | nb |
| Pashto | ps_AF |
| Persian | fa |
| Polish | pl |
| Portuguese (BR) | pt_BR |
| Portuguese (POR) | pt_PT |
| Punjabi | pa |
| Romanian | ro |
| Russian | ru |
| Serbian | sr |
| Sinhala | si_LK |
| Slovak | sk |
| Slovenian | sl |
| Spanish | es |
| Spanish (ARG) | es_AR |
| Spanish (CHL) | es_CL |
| Spanish (COL) | es_CO |
| Spanish (CRI) | es_CR |
| Spanish (DOM) | es_DO |
| Spanish (ECU) | es_EC |
| Spanish (HND) | es_HN |
| Spanish (MEX) | es_MX |
| Spanish (PAN) | es_PA |
| Spanish (PER) | es_PE |
| Spanish (SPA) | es_ES |
| Spanish (URY) | es_UY |
| Swahili | sw |
| Swedish | sv |
| Tamil | ta |
| Telugu | te |
| Thai | th |
| Turkish | tr |
| Ukrainian | uk |
| Urdu | ur |
| Uzbek | uz |
| Vietnamese | vi |
| Zulu | zu |