How do I create a template?
Call POST /api/v2/templates with the template category, language, body text, and any supported buttons or examples.
Create MARKETING templates for offers, promotions, launches, and customer engagement campaigns.
Create MARKETING templates for promotions, offers, announcements, and campaign messages that require Meta review.
Use MARKETING templates for offers, announcements, product launches, coupons, events, and promotional journeys. Whats91 validates the template locally, stores the request, uploads any media header privately, and submits only Meta-supported fields to Meta for review.
Endpoint: POST /api/v2/templates.
| Header | Required | Description |
|---|---|---|
| Authorization | Yes | Use Authorization: Bearer w91_public_token_here. Compatibility body fields authToken, auth_token, or token are also accepted. |
| Content-Type | Yes | Use application/json for text and public media URL templates. Use multipart/form-data when uploading a local header media file. |
/api/v2/templates| Parameter | Type | Required | Description |
|---|---|---|---|
senderId | string | Optional | WhatsApp sender number. Omit when the token resolves to one default or number-scoped sender. |
template.name | string | Required | Template name. Whats91 normalizes it to lowercase snake_case before submission. |
template.category | string | Required | Must be MARKETING for this page. |
template.language | string | Required | Language code such as en. Use the same language you want Meta to review. |
template.body.text | string | Required | Marketing message body. Variables use positional placeholders such as {{1}}. |
template.body.examples | array | Required | Example values for body placeholders. Required when the body contains variables. |
template.header | object | Optional | Optional TEXT, IMAGE, VIDEO, or DOCUMENT header. Media headers need mediaUrl or multipart mediaFile. |
template.footer.text | string | Optional | Optional short footer text. |
template.buttons | array | Optional | Optional URL, PHONE_NUMBER, or QUICK_REPLY buttons supported by Meta for marketing use cases. |
template.metadata | object | Optional | Local Whats91 metadata stored under temp_data.public_api.metadata and not sent to Meta. |
curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"header": { "type": "TEXT", "text": "Festive offer" },
"footer": { "text": "Whats91" },
"buttons": [
{
"type": "URL",
"text": "Shop now",
"url": "https://example.com/offers"
}
],
"metadata": {
"clientReferenceId": "campaign-festival-2026"
}
}
}'{
"success": true,
"message": "Template submitted to Meta",
"data": {
"templateUid": "0e6fb4f1-5a60-4d1d-8ef2-61a6ec8b7103",
"templateId": "w91_1780300000000_ab12cd34",
"requestedTemplateName": "festival_offer_v1",
"templateName": "festival_offer_v1",
"normalizedTemplateName": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"status": "PENDING",
"senderId": "916268662275",
"phoneNumberId": "1043189608869917",
"wabaId": "643703032991069",
"metaSubmission": {
"submitted": true,
"status": "PENDING",
"metaTemplateId": "1234567890"
}
},
"metadata": {
"apiVersion": "v2",
"requestId": "request-uuid",
"processingTimeMs": 320
}
}{
"success": false,
"message": "Template name already exists",
"error_code": "TEMPLATE_NAME_EXISTS",
"details": {
"templateName": "festival_offer_v1",
"normalizedTemplateName": "festival_offer_v1",
"templateUid": "existing-template-uid",
"status": "APPROVED"
},
"metadata": {
"apiVersion": "v2",
"requestId": "request-uuid"
}
}{
"success": false,
"message": "Meta rejected template body",
"error_code": "META_TEMPLATE_SUBMISSION_FAILED",
"details": {
"templateUid": "0e6fb4f1-5a60-4d1d-8ef2-61a6ec8b7103",
"templateName": "festival_offer_v1",
"meta": {
"message": "Meta rejected template body",
"code": 100,
"subcode": 2388040
}
},
"metadata": {
"apiVersion": "v2",
"requestId": "request-uuid"
}
}| Field | Type | Notes |
|---|---|---|
| template.name | string | Use a unique, readable name. Whats91 normalizes names to lowercase snake_case. |
| template.category | string | Use MARKETING. Unsupported categories return VALIDATION_FAILED. |
| template.language | string | Use a supported Meta language code such as en. |
| template.body.text | string | Must not start or end with a variable. Add examples for every placeholder. |
| template.body.examples | array | Required when body text contains {{1}}, {{2}}, or later placeholders. |
| Field | Type | Notes |
|---|---|---|
| senderId | string | Selects the WhatsApp sender number when the token can access multiple senders. |
| template.header | object | TEXT, IMAGE, VIDEO, or DOCUMENT. Use mediaUrl for public HTTPS media or multipart mediaFile for local files. |
| template.footer.text | string | Short footer shown below the message body. |
| template.buttons | array | Use URL, PHONE_NUMBER, or QUICK_REPLY buttons for clear marketing actions. |
| template.metadata | object | Stored locally by Whats91 and never sent to Meta. |
{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"buttons": [
{ "type": "URL", "text": "Shop now", "url": "https://example.com/offers" }
]
}
}{
"template": {
"name": "flash_sale_alert",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hi {{1}}, flash sale starts at {{2}}. Use code {{3}} before stock runs out.",
"examples": ["Devendar", "6 PM", "FLASH20"]
},
"footer": { "text": "Limited period offer" },
"buttons": [
{ "type": "URL", "text": "View sale", "url": "https://example.com/sale" }
]
}
}{
"template": {
"name": "new_product_launch",
"category": "MARKETING",
"language": "en",
"header": {
"type": "IMAGE",
"mediaUrl": "https://cdn.example.com/products/launch.jpg"
},
"body": {
"text": "Introducing {{1}}. Explore launch benefits and early access pricing today.",
"examples": ["Whats91 Campaign Studio"]
},
"buttons": [
{ "type": "URL", "text": "Explore", "url": "https://example.com/product" }
]
}
}{
"template": {
"name": "cart_recovery_offer",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hi {{1}}, items in your cart are waiting. Complete checkout and get {{2}} off.",
"examples": ["Devendar", "10%"]
},
"buttons": [
{
"type": "URL",
"text": "Checkout",
"url": "https://example.com/cart/{{1}}",
"example": "https://example.com/cart/CART-1001"
}
]
}
}{
"template": {
"name": "loyalty_coupon",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, your loyalty coupon {{2}} is ready. Redeem it before {{3}}.",
"examples": ["Devendar", "LOYAL500", "31 March"]
},
"buttons": [
{ "type": "QUICK_REPLY", "text": "Use coupon" }
]
}
}{
"template": {
"name": "event_invitation",
"category": "MARKETING",
"language": "en",
"header": {
"type": "VIDEO",
"mediaUrl": "https://cdn.example.com/events/invite.mp4"
},
"body": {
"text": "Hi {{1}}, you are invited to {{2}} on {{3}}.",
"examples": ["Devendar", "Whats91 Connect", "Friday"]
},
"buttons": [
{ "type": "URL", "text": "Register", "url": "https://example.com/events" }
],
"metadata": {
"clientReferenceId": "event-template-2026"
}
}
}Use these examples as starting points for server-side implementations.
curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_live_xxx" \
-H "Content-Type: application/json" \
-d 'curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"header": { "type": "TEXT", "text": "Festive offer" },
"footer": { "text": "Whats91" },
"buttons": [
{
"type": "URL",
"text": "Shop now",
"url": "https://example.com/offers"
}
],
"metadata": {
"clientReferenceId": "campaign-festival-2026"
}
}
}''const response = await fetch("https://graph.whats91.com/api/v2/templates", {
method: "POST",
headers: {
"Authorization": "Bearer w91_live_xxx",
"Content-Type": "application/json"
},
body: JSON.stringify(curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"header": { "type": "TEXT", "text": "Festive offer" },
"footer": { "text": "Whats91" },
"buttons": [
{
"type": "URL",
"text": "Shop now",
"url": "https://example.com/offers"
}
],
"metadata": {
"clientReferenceId": "campaign-festival-2026"
}
}
}')
});
const data = await response.json();
console.log(data);$ch = curl_init("https://graph.whats91.com/api/v2/templates");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer w91_live_xxx",
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode(curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"header": { "type": "TEXT", "text": "Festive offer" },
"footer": { "text": "Whats91" },
"buttons": [
{
"type": "URL",
"text": "Shop now",
"url": "https://example.com/offers"
}
],
"metadata": {
"clientReferenceId": "campaign-festival-2026"
}
}
}')
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;import requests
response = requests.request(
"POST",
"https://graph.whats91.com/api/v2/templates",
headers={
"Authorization": "Bearer w91_live_xxx",
"Content-Type": "application/json",
},
json=curl -X POST "https://graph.whats91.com/api/v2/templates" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"senderId": "916268662275",
"template": {
"name": "festival_offer_v1",
"category": "MARKETING",
"language": "en",
"body": {
"text": "Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.",
"examples": ["Devendar", "20%", "Sunday"]
},
"header": { "type": "TEXT", "text": "Festive offer" },
"footer": { "text": "Whats91" },
"buttons": [
{
"type": "URL",
"text": "Shop now",
"url": "https://example.com/offers"
}
],
"metadata": {
"clientReferenceId": "campaign-festival-2026"
}
}
}'
)
print(response.json())using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer w91_live_xxx");
var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.whats91.com/api/v2/templates");
request.Content = new StringContent(
"""curl -X POST \"https://graph.whats91.com/api/v2/templates\" \
-H \"Authorization: Bearer w91_public_token_here\" \
-H \"Content-Type: application/json\" \
-d '{
\"senderId\": \"916268662275\",
\"template\": {
\"name\": \"festival_offer_v1\",
\"category\": \"MARKETING\",
\"language\": \"en\",
\"body\": {
\"text\": \"Hello {{1}}, our festive offer is live. Save {{2}} until {{3}}.\",
\"examples\": [\"Devendar\", \"20%\", \"Sunday\"]
},
\"header\": { \"type\": \"TEXT\", \"text\": \"Festive offer\" },
\"footer\": { \"text\": \"Whats91\" },
\"buttons\": [
{
\"type\": \"URL\",
\"text\": \"Shop now\",
\"url\": \"https://example.com/offers\"
}
],
\"metadata\": {
\"clientReferenceId\": \"campaign-festival-2026\"
}
}
}'""",
Encoding.UTF8,
"application/json"
);
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());Call POST /api/v2/templates with the template category, language, body text, and any supported buttons or examples.
Meta review time varies. Many templates are reviewed quickly, but approval timing depends on Meta systems and policy checks.
Yes. Include variables in the body and provide matching example values for Meta review.
Send approved WhatsApp templates with Whats91-specific fields, aliases, media headers, and button parameters.
Create UTILITY templates for transactional updates, invoices, reminders, appointments, orders, and service notifications.
Create AUTHENTICATION templates for OTP and verification code delivery using Meta copy-code buttons.
Create and manage Whats91 Webhooks v2 event destinations with the canonical public API route.