Understanding Templates
WhatsApp message templates are pre-approved message formats required by Meta for initiating conversations outside the 24-hour messaging window. This guide explains how templates work and how to manage them through the SendSeven API.
Meta's Template Library holds ready-made templates in many languages. Adopt one unchanged and it is created in your WABA already APPROVED — no review wait. Writing your own template (below) is the right choice when you need MARKETING templates or your own wording.
Required Scopes
| Scope | Purpose |
|---|---|
channels:read | List and view templates |
channels:admin | Create, update, delete, and sync templates |
Template Structure
A template consists of components that define the message layout:
| Component | Description | Variables |
|---|---|---|
| HEADER | Top section: text, image, video, or document | Yes (text only) |
| BODY | Main message content | Yes ({{1}}, {{2}}, ... or {{name}}, {{order_number}}, ... -- see Parameter Formats) |
| FOOTER | Smaller text below the body | No |
| BUTTONS | URL buttons or quick replies | Yes (URL suffix) |
Example Template
HEADER: Order Confirmed
BODY: Hi {{1}}, your order #{{2}} has been confirmed. Estimated delivery: {{3}}.
FOOTER: Thank you for your purchase
BUTTONS: [Track Order -> https://example.com/track/{{1}}]
Parameter Formats
A template's body can contain placeholders that are filled in at send time. Meta supports two parameter formats, and each template's format is fixed at creation time:
| Format | Placeholder syntax | Example |
|---|---|---|
positional | {{1}}, {{2}}, {{3}}, ... | Hi {{1}}, your order #{{2}} ships {{3}}. |
named | {{name}}, {{order_number}}, ... (letters, digits, underscores) | Hi {{name}}, your order #{{order_number}} ships {{eta}}. |
The format is chosen when the template is created -- either in WhatsApp Manager (Meta Business Suite) or via our POST /api/v1/whatsapp-templates endpoint -- and cannot be changed afterwards. To switch a template from positional to named (or vice versa), you must create a new template.
Every template returned by the API exposes its format on the top-level parameter_format field:
{
"id": "tpl_abc123",
"name": "order_confirmation",
"parameter_format": "named",
"...": "..."
}
Named templates require Meta Graph API v22.0 or higher. SendSeven uses v23.0, so all named templates created in WhatsApp Manager will sync correctly into SendSeven.
When sending a template, the shape of variable_values you pass must match the template's parameter_format. See Send a Template Message for full examples and the exact request shape for each format.
Template Categories
Meta classifies templates into categories that affect review time and per-message pricing:
| Category | Use Case | Examples |
|---|---|---|
UTILITY | Transaction-related | Order confirmations, shipping updates, appointment reminders |
MARKETING | Promotional | Offers, product announcements, newsletters |
AUTHENTICATION | Login/verification | OTP codes, two-factor authentication |
UTILITY templates are typically reviewed faster than MARKETING templates. AUTHENTICATION templates have specific format requirements set by Meta.
Template Statuses
| Status | Description |
|---|---|
APPROVED | Ready to use for sending messages |
PENDING | Submitted and awaiting Meta review |
REJECTED | Declined by Meta (see rejection reason) |
DISABLED | Temporarily disabled by Meta |
Language Support
Templates can have multiple language variants. Each variant is submitted to Meta separately and may have different approval statuses.
Common language codes:
| Code | Language |
|---|---|
en_US | English (US) |
en_GB | English (UK) |
de_DE | German |
fr_FR | French |
es_ES | Spanish |
pt_BR | Portuguese (Brazil) |
it_IT | Italian |
nl_NL | Dutch |
ar | Arabic |
When sending a template, the specified language variant must be in APPROVED status. If it is not, the API returns a 400 error.
List Templates
Retrieve all templates for your WhatsApp Business Account.
GET /api/v1/whatsapp-templates
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
channel_id | string | -- | Filter by WhatsApp channel (UUID). Also triggers an auto-sync from Meta when that channel has pending templates |
status | string | -- | Filter: APPROVED, PENDING, REJECTED, DISABLED |
limit | integer | 100 | Max results to return (1--500) |
offset | integer | 0 | Number of results to skip |
This endpoint uses limit/offset and returns a templates array with a total count -- not the items + pagination envelope used by conversations, contacts, and most other list endpoints. Each language variant of a template is its own row, keyed by the top-level language field.
curl
curl -X GET "https://api.sendseven.com/api/v1/whatsapp-templates?status=APPROVED&limit=50" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
Response
{
"templates": [
{
"id": "tpl_abc123",
"tenant_id": "9f3a1c7e-5b2d-4e8a-91c4-7d6f0b3e2a15",
"channel_id": "71a1351f-4d6a-4444-9c6b-1cc8d63d7408",
"waba_id": "109876543210987",
"template_id": "1234567890123456",
"name": "order_confirmation",
"language": "en_US",
"status": "APPROVED",
"category": "UTILITY",
"quality_score": "GREEN",
"parameter_format": "positional",
"header_type": "TEXT",
"header_text": "Order Confirmed",
"body_text": "Hi {{1}}, your order #{{2}} has been confirmed. Estimated delivery: {{3}}.",
"footer_text": "Thank you for your purchase",
"buttons": [
{
"type": "URL",
"text": "Track Order",
"url": "https://example.com/track/{{1}}",
"phone_number": null,
"example": null
}
],
"quick_reply_buttons": [],
"variable_mapping": {
"1": "contact.first_name",
"2": "contact.company"
},
"default_header_media_url": null,
"default_header_document_filename": null,
"last_synced_at": "2026-01-20T09:55:00Z",
"created_at": "2026-01-20T10:00:00Z",
"updated_at": "2026-01-20T10:00:00Z"
}
],
"total": 12,
"channel_id": null,
"status_filter": "APPROVED"
}
channel_id and status_filter echo the filters you sent, so a client can tell which slice of templates it is looking at.
Get Template Details
GET /api/v1/whatsapp-templates/{template_id}
Required Scope: channels:read
Returns a single template object with the same flat shape as the entries in the list response above.
curl -X GET "https://api.sendseven.com/api/v1/whatsapp-templates/tpl_abc123" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
Create Template
Submits a new template to Meta for approval. Review typically takes 24--48 hours; the template starts in PENDING.
To skip the review entirely, adopt a pre-approved entry from Meta's Template Library instead — those are created as APPROVED as long as the wording is unchanged.
POST /api/v1/whatsapp-templates
Required Scope: channels:admin
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
channel_id | string | Yes | The WhatsApp channel (and therefore WABA) to create the template on |
name | string | Yes | Lowercase letters, digits and underscores only (^[a-z0-9_]+$), max 512 chars |
category | string | Yes | UTILITY, MARKETING, or AUTHENTICATION |
language | string | No | ISO language code, default en |
components | array | Yes | The template layout — see below |
parameter_format | string | No | positional (default) or named. Fixed at creation |
body_named_examples | object | No | Required when parameter_format is named: example value per placeholder name |
allow_category_change | boolean | No | Default true — lets Meta reclassify the template rather than rejecting it |
default_header_media_url | string | No | Fallback header media for IMAGE/VIDEO/DOCUMENT templates, used when a send call omits header_media_url. Typically the URL returned by POST /whatsapp-templates/upload-media |
default_header_document_filename | string | No | Filename shown to the recipient for DOCUMENT headers (include the extension, e.g. invoice.pdf) |
Each entry in components has type (HEADER, BODY, FOOTER, BUTTONS), plus format for headers, text for text content, example for sample values, and buttons for the buttons component.
curl -X POST "https://api.sendseven.com/api/v1/whatsapp-templates" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"channel_id": "a1b2c3d4-5678-9abc-def0-1234567890ab",
"name": "order_confirmation",
"category": "UTILITY",
"language": "en",
"parameter_format": "positional",
"components": [
{ "type": "HEADER", "format": "TEXT", "text": "Order Update" },
{
"type": "BODY",
"text": "Hi {{1}}, your order #{{2}} has been shipped! Estimated delivery: {{3}}.",
"example": { "body_text": [["John", "12345", "March 5"]] }
},
{ "type": "FOOTER", "text": "Reply STOP to unsubscribe" },
{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "Track Order", "url": "https://example.com/track/{{1}}" }
]
}
],
"allow_category_change": true
}'
Response (201 Created)
{
"success": true,
"id": "tpl_abc123",
"template_id": "1234567890123456",
"status": "PENDING",
"error": null
}
On a Meta-side failure, success is false and the response carries the parsed Graph error context: error, error_code, error_subcode, error_category.
For a named template, drop example.body_text from the BODY component and send body_named_examples instead:
{
"parameter_format": "named",
"components": [
{ "type": "BODY", "text": "Hi {{first_name}}, order #{{order_id}} has shipped." }
],
"body_named_examples": { "first_name": "John", "order_id": "ORD-123" }
}
Update Template
PATCH /api/v1/whatsapp-templates/{template_id}
Required Scope: channels:admin
Only the local-only fields default_header_media_url and default_header_document_filename are mutable. Template content (body, header, footer, buttons) is approved by Meta and cannot be edited through this API — create a new template instead.
curl -X PATCH "https://api.sendseven.com/api/v1/whatsapp-templates/tpl_abc123" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{"default_header_media_url": "https://cdn.example.com/header.jpg"}'
Returns the updated template object.
Delete Template
DELETE /api/v1/whatsapp-templates/{template_id}
Required Scope: channels:admin
Deletes the template from both Meta and SendSeven and returns 204 No Content with an empty body. An approved template becomes unavailable for sending immediately.
curl -X DELETE "https://api.sendseven.com/api/v1/whatsapp-templates/tpl_abc123" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"
Sync Templates from Meta
If you create or modify templates directly in the Meta Business Manager, sync them to SendSeven. channel_id is a required query parameter — sync runs per channel, not per account.
POST /api/v1/whatsapp-templates/sync?channel_id={channel_id}
Required Scope: channels:admin
curl -X POST "https://api.sendseven.com/api/v1/whatsapp-templates/sync?channel_id=71a1351f-4d6a-4444-9c6b-1cc8d63d7408" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
Response
{
"synced": 15,
"added": 2,
"updated": 3,
"removed": 0,
"errors": []
}
removed counts templates that no longer exist in WhatsApp and were dropped locally.
Manual syncs share a per-channel 5-minute cooldown with the automatic sync. Calling this endpoint again inside that window returns 429 Too Many Requests ("Templates were synced recently"). A sync that fails outright clears the cooldown so you can retry immediately.
Next Steps
- Meta Template Library -- adopt pre-approved templates with instant approval
- Send a Template Message -- sending templates with variable values
- Getting Started with WhatsApp -- WhatsApp integration overview
- 24-Hour Messaging Window -- when templates are required