Skip to main content

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.

Need an approved template right now?

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

ScopePurpose
channels:readList and view templates
channels:adminCreate, update, delete, and sync templates

Template Structure

A template consists of components that define the message layout:

ComponentDescriptionVariables
HEADERTop section: text, image, video, or documentYes (text only)
BODYMain message contentYes ({{1}}, {{2}}, ... or {{name}}, {{order_number}}, ... -- see Parameter Formats)
FOOTERSmaller text below the bodyNo
BUTTONSURL buttons or quick repliesYes (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:

FormatPlaceholder syntaxExample
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",
"...": "..."
}
note

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:

CategoryUse CaseExamples
UTILITYTransaction-relatedOrder confirmations, shipping updates, appointment reminders
MARKETINGPromotionalOffers, product announcements, newsletters
AUTHENTICATIONLogin/verificationOTP codes, two-factor authentication
info

UTILITY templates are typically reviewed faster than MARKETING templates. AUTHENTICATION templates have specific format requirements set by Meta.

Template Statuses

StatusDescription
APPROVEDReady to use for sending messages
PENDINGSubmitted and awaiting Meta review
REJECTEDDeclined by Meta (see rejection reason)
DISABLEDTemporarily 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:

CodeLanguage
en_USEnglish (US)
en_GBEnglish (UK)
de_DEGerman
fr_FRFrench
es_ESSpanish
pt_BRPortuguese (Brazil)
it_ITItalian
nl_NLDutch
arArabic
warning

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

ParameterTypeDefaultDescription
channel_idstring--Filter by WhatsApp channel (UUID). Also triggers an auto-sync from Meta when that channel has pending templates
statusstring--Filter: APPROVED, PENDING, REJECTED, DISABLED
limitinteger100Max results to return (1--500)
offsetinteger0Number of results to skip
Pagination differs here

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.

note

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

FieldTypeRequiredDescription
channel_idstringYesThe WhatsApp channel (and therefore WABA) to create the template on
namestringYesLowercase letters, digits and underscores only (^[a-z0-9_]+$), max 512 chars
categorystringYesUTILITY, MARKETING, or AUTHENTICATION
languagestringNoISO language code, default en
componentsarrayYesThe template layout — see below
parameter_formatstringNopositional (default) or named. Fixed at creation
body_named_examplesobjectNoRequired when parameter_format is named: example value per placeholder name
allow_category_changebooleanNoDefault true — lets Meta reclassify the template rather than rejecting it
default_header_media_urlstringNoFallback 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_filenamestringNoFilename 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.

5-minute cooldown

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