Create and Manage Templates

Authentication Templates

Starting April 1, 2024, any existing authentication template that is not an authentication template with a one-time password button cannot be sent, edited, or appealed.

Authentication templates will be available in India on July 1, 2024.


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.

Before You Start

You will need:

  • A System User access token that is linked to the business
  • The whatsapp_business_management permission
  • The WhatsApp Business Account ID for the business
  • The media asset handle for any document, image, or video file to be used in a media template. To get a media asset handle you must upload the media asset using the Resumable Upload API.

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. See the Why am I seeing 'structure unavailable' errors in my callback? help center article for more information.

Creating Templates

Send a POST request to the WhatsApp Business Account > Message Templates endpoint to create a template.

Request Syntax

POST /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates

Post Body

{
  "name": "<NAME>",
  "category": "<CATEGORY>",
  "allow_category_change": <ALLOW_CATEGORY_CHANGE>,
  "language": "<LANGUAGE>",
  "components": [<COMPONENTS>]
}

Body Properties

PlaceholderDescriptionSample Value

<NAME>

String

Required.


Template name.

Maximum 512 characters.

order_confirmation

<CATEGORY>

Enum

Required.


Template category.

See Template Categories below.

UTILITY

<ALLOW_CATEGORY_CHANGE>

Boolean

Optional.


Set to true to allow us to automatically assign a category. If omitted, the template may be rejected due to miscategorization.

true

<LANGUAGE>

Enum

Required.


Template language and locale code.

en_US

<LIBRARY_TEMPLATE_NAME>

String

Optional.


The exact name of the Utility Template Library template.

Learn how to create templates using Utility Template Library

delivery_update_1

<COMPONENTS>

Array of objects

Required.


Components that make up the template.

See Template Components below.

See Template Components below.

PlaceholderDescriptionSample Value

<LIBRARY_TEMPLATE_BUTTON_INPUTS>

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.

Learn how to create templates using Template Library

“[ {'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

The button type

QUICK_REPLY, URL, PHONE_NUMBER, OTP, MPM, CATALOG, FLOW, VOICE_CALL, APP

Required

OTP

phone_number

String

Phone number for the button.

Optional

"+13057652345"

url

JSON Object

View JSON object URL paramters base_url and url_suffix_example here

Optional

zero_tap_terms_accepted

boolean

Wether the zero tap terms were accepted by the user or not.

Optional

TRUE

otp_type

enum

The OTP type.

COPY_CODE, ONE_TAP, ZERO_TAP

Optional

TRUE

supported_apps

Array of JSON Object

View JSON object Supported App paramters package_name and signature_hash here

Optional

PlaceholderDescriptionSample Value

<LIBRARY_TEMPLATE_BODY_INPUTS>

JSON Object

Optional.


Optional data during creation of a template from Template Library. These are optional fields for the button component.


Learn how to create templates using Template Library

add_contact_number

boolean

Boolean value to add information to the template about contacting business on their phone number.

Optional

TRUE

add_learn_more_link

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

TRUE

add_security_recommendation

boolean

Boolean value to add information to the template about not sharing authentication codes with anyone.

Optional

TRUE

add_track_package_link

boolean

Boolean value to add information to the template to track delivery packages.

Not widely available and will be ignored if not available.

Optional

TRUE

code_expiration_minutes

int64

Integer value to add information to the template on when the code will expire.

Optional

5

Template Categories

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.

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 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.

Category Validation

When you send a template creation request, we immediately validate its category using our template categorization guidelines.

  • If we agree with the category you designated, we create the template and set its status to PENDING. The template then undergoes template review.
  • If we disagree with your designation, we create the template, but set its 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:

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.

Note that 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 get the reason.

See that WhatsApp Message Template endpoint reference for all possible fields and statuses.

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

PlaceholderDescriptionSample Value

<ID>

Template ID.

572279198452421

<STATUS>

Template status.

PENDING

<CATEGORY>

The template category that you designated, or that we 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://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"
        }
      ]
    }
  ]
}'

Example Response

{
    "id": "572279198452421",
    "status": "PENDING",
    "category": "MARKETING"
}

Sending Templates

Use the Cloud API or On-Premises API to send a template in a template message.

Customizing Time-To-Live

You can customize the default time-to-live (TTL) for authentication and utility template messages by setting a custom TTL on authentication and utility templates.

By default, messages that use an authentication template* have a default TTL of 10 minutes, and messages that use a utility template have a default TTL of 30 days.

To set a custom TTL on an authentication or utility template, include the message_send_ttl_seconds property. Set its value between 60 and 600 seconds (i.e., 1 to 10 minutes) for authentication templates, or 60 and 3600 seconds (i.e, 1 to 60 minutes) for utility templates (Cloud API only). Alternatively, you can set this value to -1, which will set a custom TTL of 30 days for either type of template.

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 templates created before October 23, 2024, have a default TTL of 30 days.

Best Practices for Marketing Templates

Marketing Opt-Out Button

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.

Getting Templates

Send a GET request to the WhatsApp Business Account > Message Templates endpoint to get a list of templates owned by a WhatsApp Business Account.

Request Syntax

GET /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates
  ?fields=<FIELDS>
  &limit=<LIMIT>

Query String Parameters

PlaceholderDescriptionSample Value

<FIELDS>

Comma-separated list

Optional.


List of template fields you want returned.

name,status

<LIMIT>

Integer

Optional.


The maximum number of templates you want returned in each page of results.

10

Example Request

curl 'https://graph.facebook.com/v21.0/102290129340398/message_templates?fields=name,status&limit=3' \
-H 'Authorization: Bearer EAAJB...'

Example Response

{
  "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"
  }
}

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://graph.facebook.com/v21.0/104996122399160/message_templates?fields=name,status&status=REJECTED' \
-H 'Authorization: Bearer EAAJB...'

Example Response

{
  "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"
    }
  ]
}

Retrieve a Template Namespace

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.

Example Request

Formatted for readability.
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" 
}

Editing Templates

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.

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

POST /<WHATSAPP_MESSAGE_TEMPLATE_ID>

Post Body

{
  "category": "<CATEGORY>",
  "components": [<COMPONENTS>]
}

Properties

PlaceholderDescriptionSample Value

<CATEGORY>

String

Required if components property is omitted.


Template category.

AUTHENTICATION

<COMPONENTS>

Array

Required if category 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 '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 (Editing Category Only)

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

Example response upon success.

{
  "success": true
}

Deleting Templates

Use the WhatsApp Business Account > Message Templates endpoint to delete a template by name or by ID.

Notes

  • 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.
  • Names 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 /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates
  ?name=<NAME>

Example Request

curl -X DELETE 'https://graph.facebook.com/v16.0/102290129340398/message_templates?name=order_confirmation' \
-H 'Authorization: Bearer EAAJB...'

Example Response

{
  "success": true
}

Deleting by ID

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.

Request Syntax

DELETE /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates
  ?hsm_id=<HSM_ID>,
  &name=<NAME>

Example Request

curl -X DELETE 'https://graph.facebook.com/v21.0/102290129340398/message_templates?hsm_id=1407680676729941&name=order_confirmation' \
-H 'Authorization: Bearer EAAJB...'

Example Response

{
  "success": true
}