Learn all about how to create and manage message templates, allowing businesses to send predefined messages to customers on WhatsApp in compliance with WhatsApp's policies.
Templates are used for sending WhatsApp template messages via either the Cloud API (hosted by Meta) or the On-Premises API. These templates are essential for businesses to initiate a new conversation with users on WhatsApp, when the interaction occurs outside the 24-hour customer service window.
The number of templates a WhatsApp Business Account can have is determined by its parent business. If a parent business is unverified, each of its WhatsApp Business Accounts is limited to 250 templates. However, if the parent business is verified and at least one of its WhatsApp Business Accounts has a business phone number with an approved display name, each of its WhatsApp Business Accounts can have up to 6,000 templates.
Ensure that your templates meet Meta's strict Message Template Guidelines.
You can create templates using the Digital Connect Template Manager or the EOcean Template API. This article focuses on using the API to create and manage templates.
Before You Start
You will need:
The API key associated with your account to authenticate the API request. The API key can be found in the Developer Settings of your Digital Connect account.
Please note that access to the Developer Settings is restricted to the platform administrator only.
Limitations
- The message template name field is limited to 512 characters.
- The message template content field is limited to 1024 characters.
- A template can only be edited when it is in a state of Approved, Rejected, or Paused. A template can be edited once per day, up to 10 times per month.
- WhatsApp Business Accounts can only create 100 message templates per hour.
- Templates composed of 4 or more buttons, or a quick reply button and one or more buttons of another type, cannot be viewed on WhatsApp desktop clients. WhatsApp users who receive one of these template messages will be prompted to view the message on a phone instead.
Localization
You can add a message template in a specific language when creating a template. These templates count against your limit. Be consistent when providing translations.
Getting Templates
Send a GET request to the Eocean's Template API endpoint to get a list of templates owned by a WhatsApp Business Account.
Request Syntax
GET /template?category=<CATEGORY>,
&content=<CONTENT>,
&language=<LANGUAGE>,
&name=<NAME>,
&name_or_content=<NAME_OR_CONTENT>,
&quality_score=<QUALITY_SCORE>,
&status=<STATUS>
Sample Request
GET https://eoceandigitalconnect.com/v2/api/outgoing/template?category=MARKETING&name=my_template_name&language=en
Parameters
Parameter | Description |
category array<enum {ACCOUNT_UPDATE, PAYMENT_UPDATE, PERSONAL_FINANCE_UPDATE, SHIPPING_UPDATE, RESERVATION_UPDATE, ISSUE_RESOLUTION, APPOINTMENT_UPDATE, TRANSPORTATION_UPDATE, TICKET_UPDATE, ALERT_UPDATE, AUTO_REPLY, TRANSACTIONAL, OTP, UTILITY, MARKETING, AUTHENTICATION}> |
The category for a template |
content string | The content for a template |
language array<string> |
A list of supported languages that are available for each template |
name string | The name for a message template |
name_or_content string |
Returns a list of message templates where the value for name or content match this value |
quality_score array<enum {GREEN, YELLOW, RED, UNKNOWN}> |
The quality score for a template |
status |
The review status for a template |
Example Request (Rejected Templates)
You can return only templates with specific field values by including the field and the desired value in your request. For example, include status=REJECTED to only get templates that have been rejected.
curl https://eoceandigitalconnect.com/v2/api/outgoing/template?fields=name,status&status=REJECTED' \
-H 'token: EAAJB...'
Example Response{
"data": [
{
"name": "seasonal_promotion_text_only",
"status": "APPROVED",
"id": "564750795574598"
},
{
"name": "seasonal_promotion_video",
"status": "PENDING",
"id": "1252715608684590"
3
},
{
"name": "seasonal_promotion_image_header",
"status": "PENDING",
"id": "1372429296936443"
}
],
"paging": {
"cursors": {
"before": "MAZDZD",
"after": "MgZDZD"
},
}
}
Example Request (Rejected Templates)
You can return only templates with specific field values by including the field and the desired value in your request. For example, include status=REJECTED to only get templates that have been rejected.
GET https://eoceandigitalconnect.com/v2/api/outgoing/template?fields=name,status&status=REJECTED
Get Template Insights
Send a GET request to the Eocean's Template Insight API endpoint to get a list of templates owned by your WhatsApp Business Account.
Request Syntax
GET /template/insights?fields=analytics&start=<startDate>&end=<endDate>&granularity=<granularity>
Example Request
https://eoceandigitalconnect.com/v2/api/outgoing/template/insights?fields=analytics&start=01-01-2024&end=05-11-2024&granularity=DAILY
Parameters
Parameter | Description |
end datetime/timestamp |
The end timestamp for the date range you are retrieving analytics for. As template analytics are being provided with a daily granularity in the UTC timezone, an end timestamp other than 0:00 UTC would be corrected to its next 0:00 UTC. Required |
granularity enum {DAILY} | The granularity by which you would like to retrieve the analytics. Required |
start datetime/timestamp | The start timestamp for the date range you are retrieving analytics for. As template analytics are being provided with a daily granularity in the UTC timezone, a start timestamp other than 0:00 UTC would be corrected to its prior 0:00 UTC. Required |
Fields
Reading from this edge will return a JSON formatted result:
{
"data": [],
"paging": {}
}
Error Codes
Error | Description |
100 | Invalid parameter |
200005 | Template Insights are not available yet for this WhatsApp Business account |
105 | The number of parameters exceeded the maximum for this operation |
Creating Templates
Send a POST request to the Eocean’s Template API endpoint to create a template.
Request Syntax
POST https://eoceandigitalconnect.com/v2/api/outgoing/template
Post Body{
"allow_category_change": <ALLOW_CATEGORY_CHANGE>,
"name": "<NAME>",
"language": "<LANGUAGE>",
"category": "<CATEGORY>",
"components": [<COMPONENTS>]
}
Body Properties
Placeholder | Description | Sample Value |
<NAME> String |
Required. Template name. Maximum 512 characters |
order_confirmation |
<CATEGORY> Enum |
Required. Template category. See Template Categories below. |
UTIILITY |
<ALLOW_CATEGORY_CHANGE> Boolean |
Optional. |
true |
<LANGUAGE> Enum |
Required. Template language and locale code. |
en_US |
<COMPONENTS> Array of objects |
Required. Components that make up the template. See Template Components below. |
See Template Components below. |
<LIBRARY_TEMPLATE_BUTTON_INPUTS> JSON Object |
Optional. |
“[ {'type': 'URL', 'url': {'base_url' : 'https://www.example.com/1', 'url_suffix_example' : 'https://www.example.com/demo'}}, {type: 'PHONE_NUMBER', 'phone_number': '+16315551010'} ]" |
type enum |
Required. The button type |
OTP |
phone_number String |
Optional. Phone number for the button. |
"+13057652345" |
url JSON Object |
Optional. View JSON object URL paramters base_url and url_suffix_example |
|
zero_tap_terms_accepted boolean |
Optional. Whether the zero tap terms were accepted by the user or not. |
true |
otp_type enum |
Optional. The OTP type. |
true |
supported_apps Array of JSON Object |
Optional. View JSON object Supported App paramters package_name and signature_hash |
|
<LIBRARY_TEMPLATE_BODY_INPUTS> JSON Object |
Optional. Optional data during creation of a template from Template Library. |
|
add_contact_number boolean |
Optional. Boolean value to add information to the template about contacting business on their phone number. |
true |
add_learn_more_link boolean |
Optional. Boolean value to add information to the template about learning more information with a url link. |
true |
add_security_recommendation boolean |
Optional. Boolean value to add information to the template about not sharing authentication codes with anyone. |
true |
add_track_package_link boolean |
Optional. Boolean value to add information to the template to track delivery packages. |
true |
code_expiration_minutes int64 |
Optional. Integer value to add information to the template on when the code will expire. |
5 |
Template Categories
Templates must be assigned to one of the predefined categories. These categories are important because they influence pricing. The category you select will be reviewed and validated during the template creation process.
- AUTHENTICATION
- MARKETING
- UTILITY
Refer to Meta’s Template Categorization document to determine which category to use when creating templates.
Template Components
Templates are composed of various text, media, and interactive components, based on your business needs. Refer to the Template Components document for a list of all possible components and their requirements as well as samples and example queries.
When creating a template, define its components by assigning an array of component objects to the component’s property in the body of the request.
For example, here's an array containing a text body component with two variables and sample values, a phone number button component, and a URL button component:
[ { "type": "BODY",
"text": "Thank you for your order, 1! Your confirmation number is 2. If you have any questions, please use the buttons below to contact support. Thank you for being a customer!",
"example": {
"body_text":
[
"Pablo","860198-230332"
]
]
}
},
{
"type": "BUTTONS",
"buttons": [
{
"type": "PHONE_NUMBER",
"text": "Call",
"phone_number": "15550051310"
},
{ "type": "URL",
"text": "Contact Support",
"url": "https://www.luckyshrub.com/support"
}
]
}
]
Refer to the Template Components document for a list of all possible components and their requirements as well as samples and example queries.
Templates categorized as AUTHENTICATION have unique component requirements. See Authentication Templates.
Category Validation
When you send a template creation request, Meta immediately validate its category using the template categorization guidelines.
- If Meta agrees with the category you designated, template is created and its status is set as PENDING. The template then undergoes template review.
- If Meta disagrees with your category designation, template is created, but its status is set as REJECTED and triggers a message template status update webhook with reason set to INCORRECT_CATEGORY. We recommend that you listen for this webhook to identify rejected templates, or request the rejected_reason field on newly created templates, which will have the value TAG_CONTENT_MISMATCH.
In both cases, the template's initial status is returned as part of the API response.
If your template status has been set to REJECTED as part of category validation, you have several options:
- Edit the template's components so they align with our guidelines.
- Edit the template's category so it aligns with our guidelines.
- Create a new template.
Automatic Categorization
You can include the allow_category_change property in your request to have us automatically assign a category based on your template's contents and our template categorization guidelines. This can prevent your template's status from immediately being set to REJECTED due to miscategorization.
Automatic categorization is only possible when creating a template.
Template Review
Templates with a status of PENDING are undergoing template review. We review the contents of each newly created or edited template to make sure it adheres to our content guidelines and policies. Based upon the outcome of this review, we automatically change its status to APPROVED or REJECTED, which triggers a message template status update webhook.
Template Status
Based on the outcome of category validation and template review, we set or change your template's status to one of the following values:
- APPROVED — The template has passed template review and been approved, and can now be sent in template messages.
- PENDING — The template passed category validation and is undergoing template review.
- REJECTED — The template failed category validation or template review. You can request the rejected_reason field on the template to
Response
Upon success, the API responds with the newly created template's ID, status, and category. There are three possible outcomes:
- We agreed with the category you designated and the template is now undergoing template review (status is PENDING).
- We disagreed with the category you designated (status is REJECTED)
- We automatically approved the template (status is APPROVED). This is only possible for authentication templates with one-time password buttons.
{ "id": "<ID>",
"status": "<STATUS>",
"category": "<CATEGORY>"
}
Response Properties
Placeholder | Description | Sample Value |
<ID> | Template ID. | 572279198452421 |
<STATUS> | Template status | PENDING |
<CATEGORY> | The template category that you designated, or that Meta assigned. | MARKETING |
Example Request
Here's an example request to create a seasonal promotion template composed of the following components:
- a text header
- a text body
- a footer
- two quick-reply buttons
For additional examples, see Example Requests.
curl 'https://eoceandigitalconnect.com/v2/api/outgoing/template\
-H token: EAAJB...' \
-H 'Content-Type: application/json' \
-d '
{
"name": "seasonal_promotion",
"language": "en_US",
"category": "MARKETING",
"components": [
{
"type": "HEADER",
"format": "TEXT",
"text": "Our 1 is on!",
"example": {
"header_text": [
"Summer Sale"
]
}
},
{
"type": "BODY",
"text": "Shop now through 1 and use code 2 to get 3 off of all merchandise.",
"example": {
"body_text": [
[ "the end of August","25OFF"
,"25%"
]
]
}
},
{
"type": "FOOTER",
"text": "Use the buttons below to manage your marketing subscriptions"
},
{
"type":"BUTTONS",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "Unsubscribe from Promos"
},
{
"type":"QUICK_REPLY",
"text": "Unsubscribe from All"
}
]
}
]
}'
Example Response
{ "id": "572279198452421",
"status": "PENDING",
"category": "MARKETING"
Editing Templates
Send a POST request to the Eocean Template API endpoint to edit a template.
Limitations
- Only templates with an APPROVED, REJECTED, or PAUSED status can be edited.
- You can only edit a template's category or components.
- You cannot edit the category of an approved template.
- Approved templates can be edited up to 10 times in a 30 day window, or 1 time in a 24 hour window. Rejected or paused templates can be edited an unlimited number of times.
- After editing an approved or paused template, it will automatically be approved unless it fails template review.
Request Syntax
PUT https://eoceandigitalconnect.com/v2/api/outgoing/template
Post Body
{
"templateId": "{templateId}",
"templateDetails": {
"category": "{category}",
"components": [<COMPONENTS>]
}
}
Properties
Placeholder | Description | Sample Value |
<CATEGORY> String |
Required if components property is omitted. Template Category |
AUTHENTICATION |
<COMPONENTS> Array |
Required if components property is omitted. Array of template components objects |
See Example Request (Editing Components) below. |
Example Request (Editing Components)
Example request to a template's body text which contained both marketing and utility content to only contain marketing content.
curl --location --globoff --request PUT 'https://eoceandigitalconnect.com/v2/api/outgoing/template' \
--header 'token: ' \
--header 'Content-Type: application/json' \
--data '{
"templateId": "",
"templateDetails": {
"category": "",
"components": [<COMPONENTS>]
}
}'
Example Payload
{
"components": [
{
"type": "HEADER",
"format": "TEXT",
"text": "Our 1 is on!",
"example": {
"header_text": [
"Spring Sale"
]
}
},
{
"type": "BODY",
"text": "Shop now through 1 and use code 2 to get 3
off of all merchandise.",
"example": {
"body_text": [
[
"the end of April",
"25OFF",
"25%"
]
]
}
},
{
"type": "FOOTER",
"text": "Use the buttons below to manage your marketing subscriptions" },
{
"type":
"BUTTONS",
"buttons": [
{
"type": "QUICK_REPLY",
"text": "Unsubcribe from Promos"
},
{
"type": "QUICK_REPLY",
"text": "Unsubscribe from All"
}
]
}
]
}'
Example Request (Editing Category Only)
Example request to change template's category from UTILITY to MARKETING.curl 'https://eoceandigitalconnect.com/v2/api/outgoing/template
-H 'Content-Type: application/json' \
-H 'token: EAAJB...' \
-d '
{
"category": "MARKETING"
}'
Example Response
Example response upon success.
{
"success": true
}
Deleting Templates
You can dissociate a WhatsApp Message Template from a WhatsApp Business Account by making a DELETE request to
https://eoceandigitalconnect.com/v2/api/outgoing/template?name={template_name}
- If you delete a template that has been sent in a template message but has yet to be delivered (e.g. because the customer's phone is turned off), the template's status will be set to PENDING_DELETION and we will attempt to deliver the message for 30 days. After this time you will receive a "Structure Unavailable" error and the customer will not receive the message.
- Name of an approved template that has been deleted cannot be used again for 30 days.
Deleting by name
Deleting a template by name deletes all templates that match that name (meaning templates with the same name but different languages will also be deleted).
Request Syntax
DELETE /template?name=<NAME>
Example Request
curl –location --request DELETE 'https://eoceandigitalconnect.com/v2/api/outgoing/template?name={template_name}' \
--header 'token: {token}' \
--header 'Content-Type: application/json'
Example Response
{
"success": true
}
Example Postman Request
Step 1 - Setup request type to "POST"
Step 2 - Setup URL
Step 3 - Choose body type "raw"
Step 4 - Select "JSON" type
Step 5 - Set content of the request
You can find more examples here - Open in Postman
Prerequisites
1. You must have a verified WhatsApp Business Account.
2. If you want to send Template Messages, it must be approved first.
Meta Official Documentation: https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates/
Meta Official Documentation
https://developers.facebook.com/docs/whatsapp/business-management-api/message-templates/