We are making changes to the WhatsApp Business Platform pricing model. See Pricing Updates on the WhatsApp Business Platform.
Templates are used when sending template messages with either the Cloud API, hosted by Meta, or the On-Premises API. Cloud API reviews templates and variable parameters using machine learning to protect the security and integrity of Cloud API services. When Cloud API reviews templates and variable text, no information is shared with WhatsApp.
Templates can be created using the Business Management API or the WhatsApp Business Manager. 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.
You will need:
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. See the Why am I seeing 'structure unavailable' errors in my callback? help center article for more information.
Send a POST request to the WhatsApp Business Account > Message Templates endpoint to create a template.
POST /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates
{ "name": "<NAME>", "category": "<CATEGORY>", "allow_category_change": <ALLOW_CATEGORY_CHANGE>, "language": "<LANGUAGE>", "components": [<COMPONENTS>] }
Placeholder | Description | Sample Value |
---|---|---|
String | Required. Template name. Maximum 512 characters. |
|
Enum | Required. Template category. See Template Categories below. |
|
Boolean | Optional. Set to true to allow us to automatically assign a category. If omitted, the template may be rejected due to miscategorization. |
|
Enum | Required. Template language and locale code. |
|
String | Optional. The exact name of the Utility Template Library template. Learn how to create templates using Utility Template Library |
|
Array of objects | Required. Components that make up the template. See Template Components below. | See Template Components below. |
Placeholder | Description | Sample Value |
---|---|---|
JSON Object | Optional. Optional data during creation of a template from Template Library. These are optional fields for the button component. Note: For utility templates that contain buttons, this property is not optional. |
|
enum | The button type QUICK_REPLY, URL, PHONE_NUMBER, OTP, MPM, CATALOG, FLOW, VOICE_CALL, APP Required |
|
String | Phone number for the button. Optional |
|
JSON Object | View JSON object URL paramters Optional | |
boolean | Wether the zero tap terms were accepted by the user or not. Optional |
|
enum | The OTP type. COPY_CODE, ONE_TAP, ZERO_TAP Optional |
|
Array of JSON Object | View JSON object Supported App paramters Optional |
Placeholder | Description | Sample Value |
---|---|---|
JSON Object | Optional. Optional data during creation of a template from Template Library. These are optional fields for the button component. | |
boolean | Boolean value to add information to the template about contacting business on their phone number. Optional |
|
boolean | Boolean value to add information to the template about learning more information with a url link. Not widely available and will be ignored if not available. Optional |
|
boolean | Boolean value to add information to the template about not sharing authentication codes with anyone. Optional |
|
boolean | Boolean value to add information to the template to track delivery packages. Not widely available and will be ignored if not available. Optional |
|
int64 | Integer value to add information to the template on when the code will expire. Optional |
|
Templates must be categorized as one of the following categories. Categories factor into pricing and the category you designate will be validated at the time of template creation.
AUTHENTICATION
MARKETING
UTILITY
Refer to our Template Categorization document to determine which category to use when creating templates.
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 components 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.
Note that templates categorized as AUTHENTICATION
have unique component requirements. See Authentication Templates.
When you send a template creation request, we immediately validate its category using our template categorization guidelines.
status
to PENDING
. The template then undergoes template review.status
to REJECTED
and trigger 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:
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.
Note that automatic categorization is only possible when creating a template.
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.
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 get the reason.See that WhatsApp Message Template endpoint reference for all possible fields and statuses.
Upon success, the API responds with the newly created template's ID, status, and category. There are three possible outcomes:
status
is PENDING
).status
is REJECTED
)status
is APPROVED
). This is only possible for authentication templates with one-time password buttons.{ "id": "<ID>", "status": "<STATUS>", "category": "<CATEGORY>" }
Placeholder | Description | Sample Value |
---|---|---|
| Template ID. |
|
|
| |
| The template category that you designated, or that we assigned. |
|
Here's an example request to create a seasonal promotion template composed of the following components:
For additional examples, see Example Requests.
curl 'https://graph.facebook.com/v21.0
/102290129340398/message_templates' \
-H 'Authorization: Bearer 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"
}
]
}
]
}'
{ "id": "572279198452421", "status": "PENDING", "category": "MARKETING" }
Use the Cloud API or On-Premises API to send a template in a template message.
If we are unable to deliver a message to a WhatsApp user, we will retry the delivery for a period of time known as a time-to-live, TTL, or the message validity period.
You can customize the default TTL for authentication, utility, and marketing templates.
We encourage you to set a TTL for all of your authentication templates, preferably equal to or less than your code expiration time, to ensure your customers only get a message when a code is still usable.
Authentication | Utility | Marketing | |
---|---|---|---|
Default TTL | 10 minutes | 30 days | 30 days |
Compatibility | Cloud API + On-Premise API | Cloud API only | Marketing Messages (MM) Lite API |
Customizable range | 30 seconds to 15 minutes | 30 seconds to 12 hours | 12 hours to 30 days |
Authentication templates created before October 23, 2024, have a default TTL of 30 days.
To set a custom TTL on an authentication, utility, or marketing template, include and set the value of the message_send_ttl_seconds
property in the POST /<PHONE_NUMBER_ID>/messages
call.
TTL can be customized in 1 second increments.
message_send_ttl_seconds
property values30
to 900
seconds (30 secs to 15 mins) 30
to 43200
seconds (30 secs to 12 hours)43200
to 2592000
(12 hours to 30 days)For authentication and utility templates, you can set the message_send_ttl_seconds
property value to -1
, which will set a custom TTL of 30 days.
Messages that are unable to be delivered within the default or customized TTL are dropped.
If you do not receive a delivered message webhook before the TTL is exceeded, assume the message was dropped.
If you send a message that fails to deliver, there could be a minor delay before you receive the webhook, so you may wish to build in a small buffer before assuming the message was dropped.
We recommend that you add a Quick Reply button to templates categorized as MARKETING
that makes it easy for customers to opt-out of your marketing messages. This gives your customers the option to opt-out of your marketing messages without having to block your business. As a result, you may be able to scale messaging volume faster. Please refer to this article for further details on the benefits of adding an opt-out button to your marketing templates.
Your business must take the necessary steps to stop sending marketing messages to customers who have chosen to opt-out of receiving them. Not doing so will negatively impact your block rate and quality score.
Send a GET request to the WhatsApp Business Account > Message Templates endpoint to get a list of templates owned by a WhatsApp Business Account.
GET /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates ?fields=<FIELDS> &limit=<LIMIT>
Placeholder | Description | Sample Value |
---|---|---|
Comma-separated list | Optional. List of template fields you want returned. |
|
Integer | Optional. The maximum number of templates you want returned in each page of results. |
|
curl 'https://graph.facebook.com/v21.0
/102290129340398/message_templates?fields=name,status&limit=3' \
-H 'Authorization: Bearer EAAJB...'
{
"data": [
{
"name": "seasonal_promotion_text_only",
"status": "APPROVED",
"id": "564750795574598"
},
{
"name": "seasonal_promotion_video",
"status": "PENDING",
"id": "1252715608684590"
},
{
"name": "seasonal_promotion_image_header",
"status": "PENDING",
"id": "1372429296936443"
}
],
"paging": {
"cursors": {
"before": "MAZDZD",
"after": "MgZDZD"
},
"next": "https://graph.facebook.com/v21.0
/102290129340398/message_templates?fields=name%2Cstatus&limit=3&after=MgZDZD"
}
}
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://graph.facebook.com/v21.0
/104996122399160/message_templates?fields=name,status&status=REJECTED' \
-H 'Authorization: Bearer EAAJB...'
{ "data": [ { "name": "seasonal_promotion_text_only_v4", "status": "REJECTED", "id": "564750795574598" }, { "name": "discount_qualifier", "status": "REJECTED", "id": "163917509772674" }, { "name": "limited_time_offer_tuscan_getaway_2023", "status": "REJECTED", "id": "202389039167147" }, { "name": "2023_mar_promo_2", "status": "REJECTED", "id": "1116034925734553" }, { "name": "2023_mar_promo", "status": "REJECTED", "id": "952600926095321" } ] }
The message template namespace is required to send messages using the message templates.
To get the namespace for a template, send a GET
request to the /{whatsapp-business-account-ID}
endpoint and include the message_template_namespace
field.
curl -i -X GET "https://graph.facebook.com/v21.0
/{whatsapp-business-account-ID}
?fields=message_template_namespace
&access_token={system-user-access-token}"
On success, a JSON object with the WhatsApp Business Account ID and namespace is returned:
{ "id": "1972385232742141", "message_template_namespace": "12abcdefghijk_34lmnop" }
Send a POST request to the WhatsApp Message Template endpoint to edit a template. You can also edit a template manually using the WhatsApp Manager > Account tools > Message templates panel.
APPROVED
, REJECTED
, or PAUSED
status can be edited.category
or components
.category
of an approved template.POST /<WHATSAPP_MESSAGE_TEMPLATE_ID>
{ "category": "<CATEGORY>", "components": [<COMPONENTS>] }
Placeholder | Description | Sample Value |
---|---|---|
String | Required if components property is omitted. Template category. |
|
Array | Required if category property is omitted. Array of template components objects. | See Example Request (Editing Components) below. |
Example request to a template's body text which contained both marketing and utility content to only contain marketing content.
curl 'https://graph.facebook.com/v21.0
/564750795574598' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer EAAJB...' \
-d '
{
"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 to change template's category from UTILITY
to MARKETING
.
curl 'https://graph.facebook.com/v21.0
/1252715608684590' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer EAAJB...' \
-d '
{
"category": "MARKETING"
}'
Example response upon success.
{ "success": true }
Use the WhatsApp Business Account > Message Templates endpoint to delete a template by name or by ID.
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.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).
DELETE /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates ?name=<NAME>
curl -X DELETE 'https://graph.facebook.com/v16.0/102290129340398/message_templates?name=order_confirmation' \ -H 'Authorization: Bearer EAAJB...'
{ "success": true }
To delete a template by ID, include the template's ID along with its name in your request; only the template with the matching template ID will be deleted.
DELETE /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates ?hsm_id=<HSM_ID>, &name=<NAME>
curl -X DELETE 'https://graph.facebook.com/v21.0
/102290129340398/message_templates?hsm_id=1407680676729941&name=order_confirmation' \
-H 'Authorization: Bearer EAAJB...'
{ "success": true }