Skip to content

API Cloud (TEMPLATES)

Templates are used in template messages to open marketing, utility and authentication conversations with customers. Unlike free-form messages, templates are the only message type that can be sent to customers who have not yet started a conversation with you or who have not sent you any message in the last 24 hours.

For Meta’s guidelines, see Message Templates Guidelines.

The endpoints can be queried with several Meta versions. Set the VERSION in each URL (e.g. v16.0, v17.0, v18.0, v19.0).

Template fundamentals

Templates are WhatsApp Business Account assets that are sent in template messages via Cloud API or Marketing Messages API for WhatsApp. They are the only message type that can be sent to WhatsApp users outside of a customer service window. They are commonly used for bulk messaging or when no customer service window is open.

Creation

You can create templates with the Message Templates API or from the message templates panel in WhatsApp Manager. You can create a maximum of 100 templates per hour in a WhatsApp Business Account.

Template creation via API uses a common syntax. The main variation occurs in the category string, which assigns the category, and the components array, which defines the template components.

Common syntax:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "<NAME>",
    "category": "<CATEGORY>",
    "language": "<LANGUAGE>",
    "parameter_format": "<PARAMETER_FORMAT>",
    "components": [<COMPONENTS>]
  }'

Names

Every template must have a name, but names are not unique. This flexibility allows you to create multiple templates with the same name in different languages.

Template names are limited to 512 characters, consisting of lowercase alphanumeric characters and underscores.

Categories

Each template must be categorized as authentication, marketing, or utility. Template categories also factor into pricing.

Template categorization

Category guidelines

Marketing

Marketing templates are the most flexible. The following are also considered marketing:

  • Templates with mixed content (e.g. an order update with a promo or a survey with promotional content).
  • Templates with unclear content (e.g. only {{1}} or Congratulations!).
Message objectiveBusiness goalExamples
AwarenessGenerate awareness of your business, products, or services.New tower installed, event invitation, resort opening.
SalesSend promotional offers, coupons, or content to drive sales or renewals.Loyalty discount, donations, subscription upgrade, pre-approved credit card.
RetargetingPromote offers or recommendations; renew subscriptions; CTA to engaged users. Marketing even if requested by users.Subscription renewal, abandoned cart, pending loan, saved-search car, delay credit.
App PromotionRequest install or a specific app action.In-app checkout, new feature, in-app discount, community welcome.
Build Customer RelationshipsStrengthen relationships with personalized messages.Birthday, year-end thanks, virtual assistant.
Utility

Utility templates are typically triggered by a user action or request. To be categorized as utility, a template must meet both criteria:

  • Must be non-promotional, without any promotional or persuasive intent.
  • Must also be specific to or requested by the user (related to their order, account, services, or transactions) OR essential or critical to the user (e.g. user safety).
Message objectiveBusiness goalExamples
Opt-In ManagementConfirm opt-in/opt-out collected via other channels.Opt-in confirmation, opt-out confirmation.
Order ManagementConfirm, update, or cancel orders with specific details. No promoting, recommending, upselling, cross-selling, or offers.Order confirmation, tracking, backorder, refund.
Account Alerts or UpdatesTime-sensitive updates for purchased/subscribed products or services. No promotions or offers.Account balance, payment reminder, minutes remaining, profile setup, new support number.
Feedback SurveysCollect feedback on previous orders, transactions, or engagements. Specificity is necessary; a generic survey is not approved as utility.Delivery survey, visit feedback, support survey.
Continue a ConversationMove an interaction begun in another channel to WhatsApp. Not without the user requesting it.Continue online chat support, follow up on a support call.

Essential or critical utility — to be deemed essential or critical, it must reflect one of these use cases and be non-promotional:

Use case categoryUse caseExample
Public SafetySevere weatherTornado alert, stay indoors.
Public SafetyCrisis responseSupport services activated, live updates.
Public ServiceHealth awarenessFree COVID-19 vaccination.
Public ServiceHealth emergencyHealth emergency declared by the city.
Public ServiceVoting registrationVoter registration card check.
Public ServiceDisbursementsWelfare disbursement balance.
Public DisruptionSystem outagesSystem outage impacting a zip code.
Public DisruptionOperational disruptionTrains halted due to an issue.
Account/Product ProtectionFraud awarenessATM fraud increase, update PIN.
Account/Product ProtectionProduct recallsRecalled product.
Account/Product ProtectionWarranty alertsActive warranty, manuals.
Legal/Regulatory ComplianceIdentity complianceUpgrade identification card.
Legal/Regulatory CompliancePrivacy disclosuresUpdated privacy policy.
Legal/Regulatory ComplianceWarranty alertsActive warranty, manuals.
Authentication

Note: Only authentication templates can be used to send a one-time passcode for identity verification. Marketing and utility templates cannot be used for this purpose.

Authentication templates enable businesses to verify user identity (usually with alphanumeric codes) at various steps: new account creation, account integrity/access/recovery, and new or existing orders/transactions.

They are the most restrictive category. To be classified as authentication, a business must:

  • Use Cloud API authentication templates from the Template Library (including optional add-ons like security disclaimers and expiry warnings).
  • Configure a one-time password button: copy-code or one-tap.
  • Follow content restrictions: no URLs, media, or emojis; parameters limited to 15 characters.

How WhatsApp assigns a category during template creation

When you create a template, you indicate its category per the guidelines. WhatsApp validates the indicated category against the template content and guidelines, and sets the status based on the outcome:

  • APPROVED: WhatsApp agrees with the chosen category and the template passed review. It can be used to send. Notified via email, WhatsApp Manager alert, and message_template_status_update webhook with event: APPROVED.
    • Warning (since Apr 9, 2025): if you selected UTILITY and WhatsApp determined it should be MARKETING, the template is approved as MARKETING. You can request a review up to 60 days from the category update.
    • Warning (since Apr 9, 2025): allow_category_change now defaults to true in creation.
  • PENDING: WhatsApp agrees with the category but the template is under review. On completion, a message_template_status_update webhook with event: APPROVED or REJECTED.
  • REJECTED: WhatsApp disagrees with the category you designated. Webhook message_template_status_update with event: REJECTED and reason: INCORRECT_CATEGORY. Options: create a new one, edit the category, or request a review.

Duplicated templates from phone number migration: all eligible templates are automatically duplicated in the destination WABA and category checks are performed to ensure correct categorization.

Automatic category updates

WhatsApp introduced a recurring process to identify and update approved templates that should be of a different category.

For templates approved as utility but that should be marketing:

  • Notice period: 1-day advance notice before updating to marketing. Since Apr 16, 2025, if you are warned for categorization misuse, the 24h notice is not given and the change is instant.
  • Category: changes to MARKETING.
  • Status: no change; remains APPROVED and can continue sending.

For templates approved as marketing or utility but that should be authentication (since Oct 1, 2024):

  • Advance notice provided.
  • Category: no change.
  • Status: on the first day of the following month, status changes to REJECTED and can no longer be used to send.

Notifications:

ChannelDetail
EmailTo people with full control of the portfolio over the WABA. Contains a link to the Manage Templates panel.
Webhooktemplate_category_update with correct_category (what it should be) and new_category (current category). When action is taken: new_category (new) and previous_category (previous).
WhatsApp ManagerManage Templates panel with banner and downloadable CSV.

Your options in this process: you can create a new template; for utility→marketing you can request a review (if approved, the category is not updated; if not, it is); for marketing/utility→authentication you cannot request a review (browse the template library). You have 60 days to review and appeal in Business Support Home.

Learn which templates will be or have been updated:

  • Via API: GET /{waba-id}/message_templates?fields=category,correct_category. If they match → already updated; if they mismatch and correct_category is non-empty → will be updated on the 1st of next month; if correct_category is empty/null → not impacted.
  • Via WhatsApp Manager: the Manage Templates panel identifies templates whose categories will be updated.

How to update a template category or request a category review

Edit your template’s category:

  • Via API: you can edit the content or just the category. The template undergoes validation and review again; if approved, a template_category_update webhook fires with new_category.
  • Via WhatsApp Manager: in the Manage Templates tab, edit the content to align with the guidelines and resubmit for approval.

Qualifications and outcomes for category review: you can request Meta to review the category if it is UTILITY or MARKETING with status REJECTED, or MARKETING with status APPROVED. Outcomes: approved (category updated) or rejected (no change).

How to request a category review:

  1. In WhatsApp Manager, select the Message Templates dropdown, then Message Templates. You should see a rejection banner. Click Go to Business Support.
  2. Click Template Category Updates, select the templates to review, and click Request Review.

How to view templates submitted for review: in the Business Support sidebar, click Template Category Updates, then the In review tab.

How to view category decisions: if the change is not approved, the template is under Template category updates > Unchanged; if approved, under Reversed (reverted if already changed).

Restrictions on businesses misusing the categorization system

If a business consistently misclassifies marketing templates as utility, WhatsApp may apply escalating restrictions:

LevelWhat happensDuration
WarningWritten warning to WABA admins. After a warning, utility→marketing changes become instant.Ongoing
Rate limitingUtility message volume on the WABA is capped in a 24h rolling window. Exceeding messages are rejected. Marketing and authentication are unaffected.Minimum 7 days
Utility restrictionAll approved utility templates on the WABA are recategorized to MARKETING. New utility creation and category reviews are disabled.7 days (30 for repeat violations)
Business portfolio restrictionIf misuse persists across multiple WABAs, all approved utility templates across all WABAs are recategorized to MARKETING.30 days

Warning: if continued misuse is detected after a prior restriction, enforcement may be reintroduced for longer periods and at a higher level.

Notifications:

  • Email: to all WABA admins (full control) when a warning, restriction, or lift occurs.
  • Webhook: an account_update webhook with the restriction_info object reflecting the current enforcement state.

Webhook events (whatsapp_business_account subscription):

{
  "field": "account_update",
  "value": {
    "event": "ACCOUNT_RESTRICTION",
    "violation_info": {
      "violation_type": "<violation_type>"
    },
    "restriction_info": [
      {
        "restriction_type": "<restriction_type>",
        "expiration": "<unix_timestamp>"
      }
    ]
  }
}

restriction_info is only present when an active restriction is applied; it is omitted for warnings and recovery events.

Scenarioviolation_typerestriction_inforestriction_type
WarningUTILITY_TEMPLATE_ABUSEOmitted
Utility template suspensionUTILITY_TEMPLATE_ABUSEPresentRESTRICTED_UTILITY_TEMPLATES
Suspension removedUTILITY_TEMPLATE_ABUSE_UNBANOmitted
Utility messages rate limitedUTILITY_TEMPLATE_ABUSE_RATE_LIMITPresentRATE_LIMITED_UTILITY_TEMPLATE_MESSAGING
Rate limit removedUTILITY_TEMPLATE_ABUSE_RATE_LIMIT_RECOVERYOmitted

If you believe specific templates were incorrectly recategorized, you can appeal at the template level via Business Support > Template Category Updates > Request Review.

Components

Templates are made up of various text, media, and interactive UI components, which you define upon template creation. See the template components guide for all possible components.

Languages

You must assign a template language code upon template creation. Meta does not translate template strings or variables: you are responsible for supplying strings and example parameters in the appropriate language.

If you create multiple templates with the same name but in different languages, each one counts against your template limit.

Supported languages:

LanguageCode
Afrikaansaf
Albaniansq
Arabicar
Arabic (EGY)ar_EG
Arabic (UAE)ar_AE
Arabic (LBN)ar_LB
Arabic (MAR)ar_MA
Arabic (QAT)ar_QA
Azerbaijaniaz
Belarusianbe_BY
Bengalibn
Bengali (IND)bn_IN
Bulgarianbg
Catalanca
Chinese (CHN)zh_CN
Chinese (HKG)zh_HK
Chinese (TAI)zh_TW
Croatianhr
Czechcs
Danishda
Dariprs_AF
Dutchnl
Dutch (BEL)nl_BE
Englishen
English (UK)en_GB
English (US)en_US
English (UAE)en_AE
English (AUS)en_AU
English (CAN)en_CA
English (GHA)en_GH
English (IRL)en_IE
English (IND)en_IN
English (JAM)en_JM
English (MYS)en_MY
English (NZL)en_NZ
English (QAT)en_QA
English (SGP)en_SG
English (UGA)en_UG
English (ZAF)en_ZA
Estonianet
Filipinofil
Finnishfi
Frenchfr
French (BEL)fr_BE
French (CAN)fr_CA
French (CHE)fr_CH
French (CIV)fr_CI
French (MAR)fr_MA
Georgianka
Germande
German (AUT)de_AT
German (CHE)de_CH
Greekel
Gujaratigu
Hausaha
Hebrewhe
Hindihi
Hungarianhu
Indonesianid
Irishga
Italianit
Japaneseja
Kannadakn
Kazakhkk
Kinyarwandarw_RW
Koreanko
Kyrgyz (Kyrgyzstan)ky_KG
Laolo
Latvianlv
Lithuanianlt
Macedonianmk
Malayms
Malayalamml
Marathimr
Norwegiannb
Pashtops_AF
Persianfa
Polishpl
Portuguese (BR)pt_BR
Portuguese (POR)pt_PT
Punjabipa
Romanianro
Russianru
Serbiansr
Sinhalasi_LK
Slovaksk
Sloveniansl
Spanishes
Spanish (ARG)es_AR
Spanish (CHL)es_CL
Spanish (COL)es_CO
Spanish (CRI)es_CR
Spanish (DOM)es_DO
Spanish (ECU)es_EC
Spanish (HND)es_HN
Spanish (MEX)es_MX
Spanish (PAN)es_PA
Spanish (PER)es_PE
Spanish (SPA)es_ES
Spanish (URY)es_UY
Swahilisw
Swedishsv
Tamilta
Telugute
Thaith
Turkishtr
Ukrainianuk
Urduur
Uzbekuz
Vietnamesevi
Zuluzu

Parameter formats

Some template components allow you to define strings with one or more parameters (described as “variables” in WhatsApp Manager), which are replaced with values in your send payload.

Upon template creation, if a string includes parameters, you can specify their format — named or positional — and you must include an example value for each parameter. If you do not specify a format, the template uses positional by default.

Named parameters

Parameters using the named format must be unique, single strings, composed of lowercase characters and underscores, wrapped in double curly brackets, for example {{first_name}}. Example and real values can appear in any order.

Example template creation payload with named parameters:

{
  "name": "order_confirmation",
  "language": "en_US",
  "category": "utility",
  "parameter_format": "named",
  "components": [
    {
      "type": "body",
      "text": "Thank you, {{first_name}}! Your order number is {{order_number}}.",
      "example": {
        "body_text_named_params": [
          { "param_name": "first_name", "example": "Pablo" },
          { "param_name": "order_number", "example": "860198-230332" }
        ]
      }
    }
  ]
}

Example template send payload with named parameters:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+16505551234",
  "type": "template",
  "template": {
    "name": "order_confirmation",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "first_name", "text": "Jessica" },
          { "type": "text", "parameter_name": "order_number", "text": "SKBUP2-4CPIG9" }
        ]
      }
    ]
  }
}
Positional parameters

Positional parameters must be ordered array index numbers, starting from 1, wrapped in double curly brackets: {{1}}, {{2}}, and so on. Example and real values must appear in the order of their corresponding placeholders in the component text.

Example template creation payload with a positional parameter:

{
  "name": "order_confirmation",
  "language": "en_US",
  "category": "utility",
  "parameter_format": "positional",
  "components": [
    {
      "type": "body",
      "text": "Hi {{1}}! Your order number is {{2}}. Thank you.",
      "example": {
        "body_text": [["Pablo", "860198-230332"]]
      }
    }
  ]
}

Example template send payload with a positional parameter:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+16505551234",
  "type": "template",
  "template": {
    "name": "order_confirmation",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Jessica" },
          { "type": "text", "text": "SKBUP2-4CPIG9" }
        ]
      }
    ]
  }
}

Media

Template header components can display media assets. If you are creating a template with a media header, you must use the Resumable Upload API to obtain an asset handle and include it in your template creation request. The example asset is reviewed as part of template review.

Template review

Templates are automatically reviewed upon creation or after editing. If your template is approved, its status is set to APPROVED and you can begin sending it. If it is rejected, or its status changes to any other value, it cannot be sent in template messages.

Template status

Templates must have a status of APPROVED before they can be sent. A template’s status is initially set by the review process, but can change based on usage and quality feedback.

Status changes are communicated via message_template_status_update webhooks, but you can use the Template API and request the status field to query it at any time.

Statuses in WhatsApp Manager (with quality ratings for active templates):

  • In-Review: still under review (up to 24h).
  • Rejected: rejected during review or violates one or more policies.
  • Active - Quality pending: no quality feedback yet. Sendable.
  • Active - High Quality: little to no negative feedback. Sendable.
  • Active - Medium Quality: negative feedback from multiple customers or low read-rates. Sendable, but may soon be paused.
  • Active - Low Quality: negative feedback or low read-rates. Sendable but at risk of pause/disable.
  • Paused: paused due to recurring negative feedback. Not sendable.
  • Disabled: disabled due to recurring negative feedback. Not sendable.
  • Appeal Requested: an appeal has been requested.

Template limits

The number of templates a WhatsApp Business Account can have is determined by its parent business portfolio.

  • If the parent portfolio is unverified: each WABA is limited to 250 templates.
  • If the portfolio is verified and at least one of its WABAs has a phone number with an approved display name: each WABA can have up to 6,000 templates.

Additionally, there are send limits and processes that affect delivery:

Time-to-live (TTL)

If a message cannot be delivered, the system continues attempting delivery for a period known as time-to-live (TTL). You can customize the TTL upon template creation.

Quality rating

Template quality rating evaluates template quality based on usage, customer feedback, and engagement. See Template quality rating for how it affects status and how to be notified of changes.

Delivery sequence of multiple messages

When sending a series of messages, the delivery order is not guaranteed to match the order of your API requests. To ensure the sequence, confirm receipt of a delivered status in a status webhook before sending the next message.

Template components

Templates are made up of up to four primary components you define when you create a template: header, body, footer, and buttons. The only required component is the body. Choose components based on your business needs. Some components support variables, whose values you supply when sending the template; if your templates use variables, you must include sample variable values upon creation.

Text header

Text headers are optional elements added to the top of template messages. Each template may include only one text header. Do not use Markdown special characters in this component.

Text headers support 1 parameter.

Creation syntax:

{
  "type": "header",
  "format": "text",
  "text": "<HEADER_TEXT>",
  "example": {
    "header_text_named_params": [
      { "param_name": "<NAMED_PARAMETER_NAME>", "example": "<PARAMETER_EXAMPLE_VALUE>" }
    ]
  }
}
PlaceholderDescriptionExample
<HEADER_TEXT>Required. Header body text. Supports 1 parameter. If it contains a parameter, you must include example. Maximum 60 characters.Our new sale starts {{sale_start_date}}!
<NAMED_PARAMETER_NAME>Required if using a named parameter. Parameter name.{{sale_start_date}}
<PARAMETER_EXAMPLE_VALUE>Required if using a parameter. Example value.December 1st

Media header

Media headers can be an image, video, gif, or a document such as a PDF. You must upload all media with the Resumable Upload API. The syntax is the same for all media types.

Note: Gifs are only available for Marketing Messages API for WhatsApp. They are mp4 files with a max size of 3.5MB; WhatsApp displays larger files as video messages.

Creation syntax:

{
  "type": "HEADER",
  "format": "<FORMAT>",
  "example": {
    "header_handle": ["<HEADER_HANDLE>"]
  }
}
PlaceholderDescriptionExample
<FORMAT>Media asset type. IMAGE, VIDEO, GIF, or DOCUMENT.IMAGE
<HEADER_HANDLE>Uploaded media asset handle via Resumable Upload API.4::aW...

Send media-based template

Use the Messages API to send a media-based template message. Set the type property to template and use the template property to define your template object and its media object.

When defining your media object, you can:

  • Upload your media asset to Meta’s servers and use its media ID (id property).
  • Host the asset on your server and use its URL (link property). If using link, your asset must be on a publicly accessible server or the message will fail.

To reduce the likelihood of errors and avoid unnecessary requests to your public server, Meta recommends that you upload your media assets and use their IDs when sending messages.

You can also cache media assets. See Media HTTP Caching.

Request syntax:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{VERSION}/{did}/messages' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": "PHONE_NUMBER",
    "type": "template",
    "template": {
      "name": "TEMPLATE_NAME",
      "language": { "code": "LANGUAGE_AND_LOCALE_CODE" },
      "components": [
        {
          "type": "header",
          "parameters": [
            { "type": "image", "image": { "link": "https://URL" } }
          ]
        },
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "TEXT-STRING" },
            {
              "type": "currency",
              "currency": { "fallback_value": "VALUE", "code": "USD", "amount_1000": NUMBER }
            },
            {
              "type": "date_time",
              "date_time": { "fallback_value": "MONTH DAY, YEAR" }
            }
          ]
        }
      ]
    }
  }'

A successful response includes an object with an identifier prefixed with wamid. Use the ID after wamid to track your message status.

{
  "messaging_product": "whatsapp",
  "contacts": [{
    "input": "PHONE_NUMBER",
    "wa_id": "WHATSAPP_ID"
  }],
  "messages": [{
    "id": "wamid.ID"
  }]
}

Location header

Location headers appear as generic maps at the top of the template. They are useful for order tracking, delivery updates, ride-hailing pickup/dropoff, and locating physical stores. When tapped, the user’s default map app opens with the specified location. You specify locations when you send the template.

Location headers can only be used in UTILITY or MARKETING templates. Real-time locations are not supported.

Creation syntax:

{
  "type": "header",
  "format": "location"
}

Send syntax:

{
  "type": "header",
  "parameters": [
    {
      "type": "location",
      "location": {
        "latitude": "<LATITUDE>",
        "longitude": "<LONGITUDE>",
        "name": "<NAME>",
        "address": "<ADDRESS>"
      }
    }
  ]
}
PlaceholderDescriptionExample
<ADDRESS>Location address.101 Forest Ave, Palo Alto, CA 94301
<LATITUDE>Latitude in decimal degrees.37.44211676562361
<LONGITUDE>Longitude in decimal degrees.122.16155960083124
<NAME>Location name.Philz Coffee

Body

The body is the core text of your message template and is a text-only component. Templates are limited to one body component. The body text accepts multiple parameters.

Creation syntax (named parameters):

{
  "type": "body",
  "text": "<BODY_TEXT>",
  "example": {
    "body_text_named_params": [
      { "param_name": "<NAMED_PARAMETER_NAME>", "example": "<PARAMETER_EXAMPLE_VALUE>" }
    ]
  }
}

Creation syntax (positional parameters):

{
  "type": "body",
  "text": "<BODY_TEXT>",
  "example": {
    "body_text": ["<PARAMETER_EXAMPLE_VALUE>"]
  }
}
PlaceholderDescriptionExample
<BODY_TEXT>Required. Body text. Supports multiple parameters. Maximum 1024 characters.Thank you, {{first_name}}! Your order number is {{order_number}}.
<NAMED_PARAMETER_NAME>Required if using a named parameter. Parameter name.{{order_number}}
<PARAMETER_EXAMPLE_VALUE>Required if using a parameter. Example value.December 1st

Footer

Footers are optional text-only components that appear immediately after the body component. Templates are limited to one footer component.

Syntax:

{
  "type": "FOOTER",
  "text": "<TEXT>"
}
PlaceholderDescriptionExample
<TEXT>Footer text. Maximum 60 characters.Use the buttons below to manage your marketing subscriptions

Buttons

Buttons are optional interactive components that perform specific actions when tapped.

Templates can have a combination of up to 10 button components in total, although there are per-type and combination limits. Templates with 4 or more buttons, or a quick reply button and one or more of another type, cannot be viewed on WhatsApp desktop clients; users are prompted to view the message on a phone instead.

Buttons are defined within a single buttons component, packed into a buttons array. If a template has more than three buttons, two appear in the delivered message, and WhatsApp replaces the rest with a See all options button.

Copy code buttons

Copy code buttons copy a text string (defined when the template is sent) to the device’s clipboard when tapped. Templates are limited to one copy code button.

{
  "type": "COPY_CODE",
  "example": "<EXAMPLE>"
}
PlaceholderDescriptionExample
<EXAMPLE>String copied to the clipboard when tapped. Maximum 20 characters.250FF

Multi-product message buttons (MPM)

Special non-customizable buttons that, when tapped, display up to 30 products from your ecommerce catalog, organized in up to 10 sections, in a single message.

One-time password buttons (OTP)

Special type of URL button used with authentication templates.

Voice call buttons

Make a WhatsApp call to the business when tapped. See Create and send WhatsApp call button template message.

Phone number buttons

Call the specified business phone number when tapped. Templates are limited to one phone number button.

{
  "type": "PHONE_NUMBER",
  "text": "<TEXT>",
  "phone_number": "<PHONE_NUMBER>"
}
PlaceholderDescriptionExample
<PHONE_NUMBER>Business phone number. Maximum 20 characters. Note: some countries have numbers with leading zeros after the country code (e.g. +55-0-955-585-95436). The leading zero is stripped; if your number does not work without it, use an alternate number or add it as body text.15550051310
<TEXT>Button label text. Maximum 25 characters.Call

Quick reply buttons

Custom text-only buttons that message you with the specified text when tapped. A common use case is an opt-out button for marketing messages.

Templates are limited to 10 quick reply buttons. If used with other buttons, they must be organized into two groups: quick reply and non-quick reply. If grouped incorrectly, the API returns an invalid combination error.

  • Valid groupings: Quick Reply, Quick Reply, Quick Reply, Quick Reply, URL, Phone, URL, Phone, Quick Reply, Quick Reply.
  • Invalid groupings: Quick Reply, URL, Quick Reply, URL, Quick Reply, URL.

When sending a template with multiple quick reply buttons, use the index property to designate their order.

{
  "type": "QUICK_REPLY",
  "text": "<TEXT>"
}
PlaceholderDescriptionExample
<TEXT>Button label text. Maximum 25 characters.Unsubscribe

SPM buttons (single-product)

Special non-customizable buttons mapped to a product in your catalog. When tapped, they load the product details from the catalog. Users can add the product to their cart and place an order.

URL buttons

Load the specified URL in the device’s default browser when tapped. Templates are limited to two URL buttons.

{
  "type": "URL",
  "text": "<TEXT>",
  "url": "<URL>",
  "example": ["<EXAMPLE>"]
}
PlaceholderDescriptionExample
<EXAMPLE>Sample value if the URL contains a variable.https://www.luckyshrub.com/shop?promo=summer2023
<TEXT>Button label text. Maximum 25 characters.Shop Now
<URL>URL that loads in the browser. Supports 1 variable appended at the end. Maximum 2000 characters.https://www.luckyshrub.com/shop?promo={{1}}
URL encoding

If your URL button parameter values contain special characters, percent-encode them before including them in your send request. Unencoded special characters can cause the generated URL to fail validation.

CharacterEncoded valueExample
Space%20New YorkNew%20York
:%3Ax:keyx%3Akey
|%7C9|DL9%7CDL
ç%C3%A7GonçalvesGon%C3%A7alves
ñ%C3%B1PeñaPe%C3%B1a

For example, if your template URL is https://example.com/order?name={{customer_name}} and the parameter value is Gonçalves, you must send the value as Gon%C3%A7alves:

{
  "type": "button",
  "sub_type": "url",
  "index": "0",
  "parameters": [
    { "type": "text", "parameter_name": "customer_name", "text": "Gon%C3%A7alves" }
  ]
}

Limited-time offer

Limited-Time Offer components are special components used to create limited-time offer templates.

Webhooks

Subscribe to the message_template_components_update webhook field to be notified of changes to a template’s components.

Template Library

Template Library makes it faster and easier for businesses to create utility templates for common use cases (payment reminders, delivery updates) and authentication templates for common identity verification use cases.

These pre-written templates have already been categorized as utility or authentication. They contain fixed content that cannot be edited and parameters you can adapt for business or user-specific information.

Warning: When a template contains the value library_template_name in the GET /{waba-id}/message_templates?name=<NAME> response, it is a template created from the Template Library and is subject to type checks and restrictions.

Parameters and restrictions

Parameters represent spaces where variable information can be inserted (names, addresses, phone numbers). Messages sent using templates from the library are subject to parameter checks at send time. Values outside the established ranges will cause the message send to fail.

Warning: All parameters are length restricted. If you receive an error, try again with a shorter value.

Parameter typeDescriptionSample value
ADDRESSA location address. Must be valid.1 Hacker Way, Menlo Park, CA 94025
TEXTBasic text.regarding your order.
AMOUNTA number signifying a quantity. May have monetary prefix/suffix (USD, RS), decimals, commas, and currency symbols ($, €).USD $375.32
DATEA standard calendar date.2021-04-19
PHONE NUMBERA telephone number. May contain numbers, spaces, dashes, parentheses, and plus symbols.+1 4256789900
EMAILA standard email address. Must be valid.1hackerway@meta.com
NUMBERA number. Cannot contain spaces.23444

Forms

Warning: Forms are only available to accounts who have had their message limits increased.

Some templates in Template Library are interactive forms powered by WhatsApp Flows. In WhatsApp Manager they are identified by the “Form” label. The currently supported use cases are Customer Feedback and Delivery Failure.

When calling GET /message_template_library, the type key in the buttons array will show "FORMS" to identify them.

{
  "name": "delivery_failed_2_form",
  "language": "en_US",
  "category": "UTILITY",
  "topic": "ORDER_MANAGEMENT",
  "usecase": "DELIVERY_FAILED",
  "industry": ["E_COMMERCE"],
  "body": "We were unable to deliver order {{1}} today.\n\nPlease {{2}} to schedule another delivery attempt.",
  "body_params": ["#12345", "try a redelivery"],
  "body_param_types": ["TEXT", "TEXT"],
  "buttons": [{ "type": "FLOW", "text": "Reschedule" }],
  "id": "7138055039625658"
}

Using the API

The Template Library API has two endpoints:

GET /message_template_library                        // Browse available library templates
POST /<WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates   // Create a template from the library

Searching and filtering available templates

Warning: Templates with Header parameter types of Document only support PDFs.

Request syntax:

GET /message_template_library
GET /message_template_library?search=<SEARCH_KEY>       // substring in content, name, header, body or footer
GET /message_template_library?topic=<TOPIC>
GET /message_template_library?usecase=<USECASE>
GET /message_template_library?industry=<INDUSTRY>
GET /message_template_library?language=<LANGUAGE>
GET /message_template_library?name=<NAME>

Query string parameters:

PlaceholderDescriptionSample value
<SEARCH_KEY>A substring you are searching for in the content, name, header, body, or footer.payments
<TOPIC>The topic of the template.ORDER_MANAGEMENT
<USECASE>The use case of the template.SHIPMENT_CONFIRMATION
<INDUSTRY>The industry of the template.E_COMMERCE
<LANGUAGE>The template language locale code.en_US
<NAME>The name of the template you are searching for.verify_otp_usecase

Template filters:

  • Industry: E_COMMERCE, FINANCIAL_SERVICES.
  • Topic: ACCOUNT_UPDATE, CUSTOMER_FEEDBACK, ORDER_MANAGEMENT, PAYMENTS.
  • Use case: ACCOUNT_CREATION_CONFIRMATION, AUTO_PAY_REMINDER, DELIVERY_CONFIRMATION, DELIVERY_FAILED, DELIVERY_UPDATE, FEEDBACK_SURVEY, FRAUD_ALERT, LOW_BALANCE_WARNING, ORDER_ACTION_NEEDED, ORDER_CONFIRMATION, ORDER_DELAY, ORDER_OR_TRANSACTION_CANCEL, ORDER_PICK_UP, PAYMENT_ACTION_REQUIRED, PAYMENT_CONFIRMATION, PAYMENT_DUE_REMINDER, PAYMENT_OVERDUE, PAYMENT_REJECT_FAIL, PAYMENT_SCHEDULED, RECEIPT_ATTACHMENT, RETURN_CONFIRMATION, SHIPMENT_CONFIRMATION, STATEMENT_ATTACHMENT, STATEMENT_AVAILABLE, TRANSACTION_ALERT.

Creating templates from the library

To create a new template using the Template Library, call the existing <WHATSAPP_BUSINESS_ACCOUNT_ID>/message_templates endpoint with the body properties below:

{
  "name": "<NAME>",
  "category": "UTILITY",
  "language": "en_US",
  "library_template_name": "<LIBRARY_TEMPLATE_NAME>",
  "library_template_button_inputs": "[
    {'type': 'URL', 'url': {'base_url' : 'https://www.example.com/{{1}}',
    'url_suffix_example' : 'https://www.example.com/demo'}},
    {type: 'PHONE_NUMBER', 'phone_number': '+16315551010'}
]"
}

Body properties:

PlaceholderDescriptionSample value
<NAME>Required. The name you are providing for your template. Maximum 512 characters.my_payment_template
<CATEGORY>Required. The template category. Must be UTILITY for use with Template Library.UTILITY
<LANGUAGE>Required. The template language locale code.en_US
<LIBRARY_TEMPLATE_NAME>Required. The exact name of the Template Library template.delivery_update_1
<LIBRARY_TEMPLATE_BUTTON_INPUTS>Optional. The website and/or phone number of the business. Note: for utility templates with button inputs, this property is not optional.Array of objects

Library template button inputs:

PlaceholderDescriptionSample value
typeThe button type: QUICK_REPLY, URL, PHONE_NUMBER, OTP, MPM, CATALOG, FLOW, VOICE_CALL, APP. RequiredOTP
phone_numberPhone number for the button. Optional"+13057652345"
urlJSON object with base_url and url_suffix_example. Optional
zero_tap_terms_acceptedWhether zero tap terms were accepted. OptionalTRUE
otp_typeThe OTP type: COPY_CODE, ONE_TAP, ZERO_TAP. OptionalCOPY_CODE
supported_appsArray of objects with package_name and signature_hash. Optional

Library template body inputs:

PlaceholderDescriptionSample value
add_contact_numberAdd info about contacting the business by phone. OptionalTRUE
add_learn_more_linkAdd a “learn more” URL link. OptionalTRUE
add_security_recommendationAdd info about not sharing authentication codes. OptionalTRUE
add_track_package_linkAdd a package tracking link. OptionalTRUE
code_expiration_minutesMinutes until the code expires. Optional5

Example request:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "my_delivery_update",
    "language": "en_US",
    "category": "UTILITY",
    "library_template_name": "delivery_update_1",
    "library_template_button_inputs": "[{'type': 'URL', 'url': {'base_url': 'https://www.example.com/{{1}}', 'url_suffix_example': 'https://www.example.com/order_update'}}]"
  }'

Example response:

{
  "id": "{hsm-id}",
  "status": "APPROVED",
  "category": "UTILITY"
}

Template archival

Templates that have been inactive for 12 months or more are automatically archived. Archived templates cannot be sent in template messages and are scheduled for deletion after 28 days. You can unarchive a template within the 28-day window to restore it to its previous status.

Auto-archival

All WhatsApp Business accounts have auto-archival enabled. You cannot opt out of auto-archival.

A template is eligible for auto-archival when all of the following are true:

  • The template status is not PENDING_DELETION, DELETED, or ARCHIVED.
  • The template has been inactive for longer than 12 months.

Template activity includes creating, editing, sending, appealing, or unarchiving a template.

Post-archival deletion

WhatsApp automatically deletes archived templates 28 days after archival. Once deleted, the template cannot be recovered. If you unarchive a template before the 28-day window expires, the scheduled deletion is cancelled.

Notifications

When templates are archived, you are notified through the following channels:

  • Webhook — A message_template_status_update webhook is sent for each template that is archived or unarchived.
  • Email — An email is sent when templates are archived, listing the affected templates with a link to view and unarchive them in WhatsApp Manager.

Marketing Messages API (MM API)

MM API for WhatsApp is an API for sending marketing messages on WhatsApp that optimizes delivery to reach more of the people most likely to find your messages relevant.

Requirements

Accept Terms of Service

  1. Navigate to the App Dashboard > WhatsApp > Quickstart panel.
  2. Locate the “Improve ROI with marketing messages with optimizations” module and click the “Get started” button.
  3. Click on “Continue to integration guide” and accept the Terms of Service.

Send marketing messages

Marketing Messages API for WhatsApp allows you to send marketing template messages only. To send other message types or receive messages, use Cloud API in parallel with MM API on the same business phone number.

Prerequisites:

  • A WABA with MM API onboarding complete.
  • At least one registered business phone number associated with your WABA.
  • At least one approved marketing template.
  • An access token with the whatsapp_business_messaging permission.
  • A Meta Pixel or Conversions API integration (required for conversion measurement).

Template sync: new marketing templates take up to 10 minutes to sync with the corresponding Ad account (enables optimization and click/conversion measurement). Templates inactive for longer than 7 days also require 10 minutes after first use. Wait 10 minutes after creating new marketing templates or reactivating dormant templates before sending marketing traffic.

Endpoint: send all marketing traffic to POST /{v}/{did}/marketing_messages. The endpoint supports only marketing template messages for MM API and Cloud API; all other types (freeform, authentication, service, utility) produce an error. If onboarding requirements are not met, the message routes via Cloud API (disable with product_policy: STRICT).

Optional payload fields:

  • product_policy: CLOUD_API_FALLBACK (default — send via Cloud API if onboarding not complete) or STRICT (never fallback).
  • message_activity_sharing: enables/disables sharing message activity (e.g., reads) for that message with Meta. If not provided, the default WABA-level setting applies.

Sending by BSUID (business-scoped user ID): the recipient field (BSUID or parent BSUID) is optional alongside to (now optional). At least one required; if both provided, to takes precedence. Sending by BSUID disables MM API delivery optimization, and dynamic pricing (bid_spec) is NOT supported → error 131062 (“Business-scoped User ID (BSUID) recipients are not supported”). Authentication templates also error 131062 with BSUID. The response adds user_id (BSUID) and omits wa_id when sent by BSUID.

Disable marketing messages on Cloud API: set disable_marketing_messages_on_cloud_api: true|false via POST /{waba-id} (WhatsApp Business Account API). When true, the /messages endpoint rejects Marketing templates with error 131063 (“Marketing templates disabled for Cloud API”). No effect on WABAs that have not onboarded to MM API. With product_policy: STRICT no Cloud API fallback is attempted regardless of this setting.

Automatic creative optimizations: enabled by default at template level; all disabled by default at WABA level. Configure per-template or per-WABA via degrees_of_freedom_spec.creative_features_spec with enroll_status: OPT_IN|OPT_OUT per feature. Features: image_brightness_and_contrast, image_touchups, add_text_overlay, image_animation, image_background_gen, auto_promotion_tag, text_extraction_for_headline, text_extraction_for_tap_target, product_extensions, text_formatting_optimization. Paused/deprecated (won’t be applied): image cropping, text overlays, image animation, image background generation. Average +13.9% CTR (A/B test on 50M messages, Dec 2025–Jan 2026). Read statuses: GET /{template-id}?fields=degrees_of_freedom_spec or GET /{waba-id}?fields=degrees_of_freedom_spec.

Text truncation (no content changed; original accessible via “Read more”): messages without CTA but with a link in body → 5 lines; messages with media header (image/video/document/location/GIF) → 3 lines; messages without header (text) → 4 lines.

MM API is send-only: it does not receive incoming messages — use Cloud API in parallel on the same phone number.

Key benefits

  1. Boost and measure business results: with automatic delivery optimizations, you can reach more people who will find your messages valuable, which drove more reads and clicks in testing. You can also access measurement insights:

    • Performance benchmarks, to understand how your message performed compared to similar businesses.
    • Tailored recommendations, to improve campaign performance.
  2. Enhance customer experience and engagement: MM API helps deliver more relevant and timely marketing messages with features like:

    • Automatic creative optimizations (in testing), to apply creative treatments like image animation and filtering.
    • Richer media formats, like GIFs.
    • Time-to-live, to avoid irrelevant or delayed delivery for time-sensitive campaigns.
  3. Upgrade easily, with consistent reliability and security: MM API offers a similar technical schema and same billing model as Cloud API, and businesses can use existing phone numbers and MM templates.

Send all your marketing traffic to the /marketing_messages endpoint for automatic routing of eligible business messages.

ISV endpoint:

POST /{v}/{did}/marketing_messages

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{VERSION}/{did}/marketing_messages' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
    "messaging_product": "whatsapp",
    "recipient_type": "individual",
    "to": "PHONE_NUMBER",
    "type": "template",
    "template": {
      "name": "MARKETING_TEMPLATE_NAME",
      "language": { "code": "LANGUAGE_AND_LOCALE_CODE" },
      "components": []
    }
  }'

Note: per Meta, an AB test with approximately 12 million delivered marketing messages in India (January 2025) showed MM API optimized delivery outperformed standard Cloud API delivery for high-engagement messages (more reads, clicks, and so on).

Verify message was sent through the status webhook

MM API for WhatsApp triggers status messages webhooks for events such as sent, delivered, and read. When a message is sent via MM API, the webhook payload will have category and conversation.origin.type set to marketing_lite:

{
  "conversation": {
    "id": "<CONVERSATION_ID>",
    "origin": {
      "type": "marketing_lite"
    }
  },
  "pricing": {
    "billable": true,
    "pricing_model": "PMP",
    "category": "marketing_lite"
  }
}

Geographic availability of features

Some advanced features and reporting capabilities of MM API are available only in particular geographies due to Meta policy and/or local regulation.

European Economic Area, United Kingdom, Japan, South Korea, Nigeria, South Africa

  • Messages sent from a business phone number in these countries, or to a WhatsApp user in these countries, will not receive delivery optimizations. Note that per-user marketing message template limits are also not active in these countries, so a lack of delivery optimizations will not have any effect on message delivery.
  • No click and conversion reporting metrics available.
  • Metrics are not available on Ads Manager UI or Insights API. As with Cloud API, metrics will be available via Business Management API and WhatsApp Manager UI ‘conversation’ metrics.

United States

  • Starting April 1, 2025, marketing messages sent to WhatsApp users in the United States will not be delivered (error code 131049). This policy is not specific to MM API — it applies across all Business Messaging APIs.
  • Business phone numbers in the US can still use MM API to message users outside the United States.

Cuba, Iran, North Korea, Syria, Venezuela, and three sanctioned regions in the Ukraine (Crimea, Donetsk, Luhansk)

  • Businesses in these regions are not eligible to onboard, and messages cannot be sent to a WhatsApp user in these regions. Applies across all Business Messaging APIs.

Russia, Belarus

Starting June 20, 2025, businesses in Russia and Belarus can use MM API with the following feature exceptions:

  • Messages sent by a business with a Meta business profile in Russia or Belarus, or using a payment method with a Russia or Belarus address, will not receive delivery optimizations.
  • No click and conversion reporting metrics. Metrics continue to be available via Business Management API and WhatsApp Manager conversation metrics.
  • Messages sent to a WhatsApp user in these countries will not use optimization features such as max pricing.
  • All other MM API features continue to be available.

Feature comparison with Cloud API

MM API offers added features not available on Cloud API, such as performance benchmarks and recommendations, time-to-live, and automated creative optimizations (pilot).

Optimization features

DescriptionMM API (Marketing)Cloud API (Auth, Utility, Service, Marketing)
Quality-based delivery: improving deliveries of high engagement messages.Yes: MM API factors whether a message is high engagement into delivery decisions, delivering up to 9% more messages vs Cloud API. A high engagement message is expected, relevant, and timely.No: message quality does not factor into per-user marketing message limits.
Automated creative optimizations: automatic image and text adjustments to increase performance.Yes (pilot): applies automatic image and text adjustments to marketing templates.No

Marketing message formats

DescriptionMM API (Marketing)Cloud API
Animated image (GIF) headerYesNo
Android app deep links: links that open a specified app on a customer’s Android device.YesNo
Customizable message validity periods: time-to-live so messages expire.Yes: TTL from 12 hours to 30 days.Limited: only Authentication and Utility.
Basic marketing message formats: media, carousel, product catalog, flow, interactive list, interactive reply.YesYes

Guidance

DescriptionMM API (Marketing)Cloud API
Benchmarks: comparison of read and click rates versus similar templates from other businesses in your region.YesNo
Recommendations: data-derived recommendations to improve performance.YesNo

Metrics

DescriptionMM API (Marketing)Cloud API
Conversion metrics: conversions on Web and App (e.g. “Add to Cart”, “Checkout Initiated”, “Purchase”).Yes: measure app events.No
Cost metrics: spend per template, cost per click, cost per delivery.YesYes
Basic metrics: sent, delivered, read, clicked, errors.YesYes

Enterprise, security, and compliance

DescriptionMM API (Marketing)Cloud API
Local Storage supportYesYes
Compliance certification: LGPD, GDPR, System Audit Report, SOC, ISO27001.YesYes
Automatic throughput upgrades (with webhook notifications)YesYes
Real-time service status: uptime metrics on metastatus.com.YesYes

Onboarding

DescriptionMM API (Marketing)Cloud API
Onboarding options: Embedded Signup, Intent API, Intent UI.Yes (all)Limited: Embedded Signup only.
Error codes: MM API-specific codes.YesYes
Onboarding status via API: eligibility field.YesLimited
WhatsApp Business app user onboardingYesYes

Marketing templates

Marketing templates are typically used to drive engagement, brand awareness, and sales. They are the only template type that can be used with both Cloud API and Marketing Messages API for WhatsApp.

Custom templates

You can use the Message Templates API to create custom marketing templates that suit your business needs from any supported components.

Supported components in a custom marketing template:

ComponentCountRequired
Header1Optional (all types supported)
Body1Required
Footer1Optional
ButtonsUp to 10Optional (all types supported)

Step 1 — Create: POST /message_templates/{VERSION}/{did} with category: "marketing" and parameter_format: "named" to use named parameters ({{name}}):

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "welcome_discount_template",
  "language": "en_US",
  "category": "marketing",
  "parameter_format": "named",
  "components": [
    {
      "type": "header",
      "format": "image",
      "example": {
        "header_handle": ["4::aW1h..."]
      }
    },
    {
      "type": "body",
      "text": "Welcome to Lucky Shrub, {{first_name}}!\n\nUse code *{{discount_code}}* to get {{discount_amount}} off of your first purchase!",
      "example": {
        "body_text_named_params": [
          { "param_name": "first_name", "example": "Pablo" },
          { "param_name": "discount_code", "example": "WELCOME20" },
          { "param_name": "discount_amount", "example": "20%" }
        ]
      }
    },
    {
      "type": "footer",
      "text": "Lucky Shrub: Your gateway to succulents!"
    },
    {
      "type": "buttons",
      "buttons": [
        { "type": "url", "text": "View deals", "url": "https://www.luckyshrub.com/deals" },
        { "type": "phone_number", "text": "Call us", "phone_number": "+15550051310" },
        { "type": "quick_reply", "text": "Unsubscribe" }
      ]
    }
  ]
}'

Step 2 — Send: the template must be APPROVED. When sending, named parameters go in the body with parameter_name (in any order) and the media header uses the uploaded asset id:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "16505551234",
  "type": "template",
  "template": {
    "name": "welcome_discount_template",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "id": "1339522734477770" } }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "first_name", "text": "Jessica" },
          { "type": "text", "parameter_name": "discount_code", "text": "WELCOME25" },
          { "type": "text", "parameter_name": "discount_amount", "text": "25%" }
        ]
      }
    ]
  }
}'

Specialty templates

Some templates use a special component that requires or excludes additional components, or require additional configuration:

Call permission request template

Call permission request templates allow you to request permission to call WhatsApp users. They include a required body component and a call_permission_request component. When a WhatsApp user receives the message, they can grant or deny your business permission to call them.

These templates can be categorized as MARKETING or UTILITY. This example uses MARKETING. For a UTILITY-category example, see utility call permission request templates.

Limitations:

  • Only templates categorized as MARKETING or UTILITY can include a call permission request component.
  • You must include body text, and it must not be empty.
  • You can’t combine the call permission request component with other interactive components.

Create: POST /message_templates/{VERSION}/{did} with parameter_format: "named":

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "vip_early_access_call",
  "language": "en_US",
  "category": "MARKETING",
  "parameter_format": "named",
  "components": [
    {
      "type": "body",
      "text": "Hi {{first_name}}, as a Lucky Shrub VIP, get a first look at our rare new succulents before anyone else. Can we give you a quick call?",
      "example": {
        "body_text_named_params": [
          { "param_name": "first_name", "example": "Pablo" }
        ]
      }
    },
    {
      "type": "call_permission_request"
    }
  ]
}'

Send: the template must be APPROVED. Named parameters go in the body with parameter_name:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+15551234567",
  "type": "template",
  "template": {
    "name": "vip_early_access_call",
    "language": { "policy": "deterministic", "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "first_name", "text": "Pablo" }
        ]
      }
    ]
  }
}'

Coupon code template

Coupon code templates are marketing templates that display a single copy code button. When the app user taps the button, WhatsApp copies the coupon code to the clipboard.

Limitations:

  • Currently not supported by the WhatsApp web client.
  • Copy code button text cannot be customized.
  • Templates are limited to one copy code button.

Properties set at creation vs. send:

  • Creation only: header text, body text (with parameter placeholders), quick reply button label, copy code button example code.
  • Send only: body parameter values (coupon_code, discount), the coupon code (copy code button value).
  • Both: template name, language (referenced at both steps).

Create: POST /message_templates/{VERSION}/{did} with parameter_format: "named":

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "winter_sale_coupon",
  "language": "en_US",
  "category": "MARKETING",
  "parameter_format": "named",
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Our Winter Sale is on!"
    },
    {
      "type": "BODY",
      "text": "Shop now through the end of December and use the one-time use code {{coupon_code}} to get {{discount}} off of your entire order!",
      "example": {
        "body_text_named_params": [
          { "param_name": "coupon_code", "example": "WINTER25" },
          { "param_name": "discount", "example": "30%" }
        ]
      }
    },
    {
      "type": "BUTTONS",
      "buttons": [
        { "type": "QUICK_REPLY", "text": "Unsubscribe" },
        { "type": "COPY_CODE", "example": "WINTER25" }
      ]
    }
  ]
}'

Send: the template must be APPROVED. The coupon code is supplied in the button component with sub_type: "copy_code" and its index (zero-indexed):

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "to": "16505551234",
  "type": "template",
  "template": {
    "name": "winter_sale_coupon",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "coupon_code", "text": "WINTER25" },
          { "type": "text", "parameter_name": "discount", "text": "30%" }
        ]
      },
      {
        "type": "button",
        "sub_type": "copy_code",
        "index": 1,
        "parameters": [
          { "type": "coupon_code", "coupon_code": "WINTER25" }
        ]
      }
    ]
  }
}'

Limited-time offer template

Limited-time offer templates display expiration dates and running countdown timers for offer codes in template messages.

Limitations:

  • Only templates categorized as MARKETING are supported.
  • Footer components are not supported.
  • Users who view a limited-time offer template message using the WhatsApp web app or desktop app will not see the offer; instead they see a message indicating that the limited-time offer is not supported.

Create: POST /message_templates/{VERSION}/{did} with the limited_time_offer component:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "limited_time_offer_caribbean_pkg_2023",
  "language": "en_US",
  "category": "marketing",
  "components": [
    {
      "type": "header",
      "format": "image",
      "example": { "header_handle": ["4::aW..."] }
    },
    {
      "type": "limited_time_offer",
      "limited_time_offer": {
        "text": "Expiring offer!",
        "has_expiration": true
      }
    },
    {
      "type": "body",
      "text": "Good news, {{1}}! Use code {{2}} to get 25% off all Caribbean Destination packages!",
      "example": { "body_text": [["Pablo", "CARIBE25"]] }
    },
    {
      "type": "buttons",
      "buttons": [
        { "type": "copy_code", "example": "CARIBE25" },
        {
          "type": "url",
          "text": "Book now!",
          "url": "https://awesomedestinations.com/offers?code={{1}}",
          "example": ["https://awesomedestinations.com/offers?ref=n3mtql"]
        }
      ]
    }
  ]
}'

Send: the template must be APPROVED. The offer code and its expiration timestamp are supplied at send time:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "16505555555",
  "type": "template",
  "template": {
    "name": "limited_time_offer_caribbean_pkg_2023",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "id": "1602186516975000" } }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Pablo" },
          { "type": "text", "text": "CARIBE25" }
        ]
      },
      {
        "type": "limited_time_offer",
        "parameters": [
          {
            "type": "limited_time_offer",
            "limited_time_offer": { "expiration_time_ms": 1209600000 }
          }
        ]
      },
      {
        "type": "button",
        "sub_type": "copy_code",
        "index": 0,
        "parameters": [
          { "type": "coupon_code", "coupon_code": "CARIBE25" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": 1,
        "parameters": [
          { "type": "text", "text": "n3mtql" }
        ]
      }
    ]
  }
}'

Combining with payment request buttons: only for businesses based in Brazil using payment request CTA buttons (Pix, Boleto, or Payment Link). Enables time-sensitive payment requests that display a countdown timer alongside payment options within the message. See Payment Request CTA Templates (Brazil).

Location template

Location templates send a marketing message that includes a map header displaying a specific location. When a WhatsApp user taps the map, their default map app opens to those coordinates. Useful for promoting store openings, event invitations, pop-up shops, and other location-based promotions.

Categorize a location template as MARKETING or UTILITY. This example uses MARKETING. For a UTILITY-category example (e.g., order tracking, delivery updates, ride-hailing pickup and drop-off, locating physical stores), see utility location templates.

Limitations:

  • Only templates categorized as UTILITY or MARKETING can include a location header.
  • Real-time locations are not supported.
  • The location (latitude, longitude, name, address) is specified at send time, not at template creation time.

Supported components:

  • 1 location header (required)
  • 1 body (required; supports named parameters)
  • 1 footer (optional)
  • Buttons (optional)

Create: POST /message_templates/{VERSION}/{did} with parameter_format: "named":

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "store_grand_opening",
  "language": "en_US",
  "category": "MARKETING",
  "parameter_format": "named",
  "components": [
    {
      "type": "HEADER",
      "format": "LOCATION"
    },
    {
      "type": "BODY",
      "text": "Hi {{customer_name}}! We are opening a new store near you. Visit us on opening day for {{discount}} off your first purchase!",
      "example": {
        "body_text_named_params": [
          { "param_name": "customer_name", "example": "Lisa" },
          { "param_name": "discount", "example": "20%" }
        ]
      }
    },
    {
      "type": "FOOTER",
      "text": "Reply STOP to unsubscribe."
    },
    {
      "type": "BUTTONS",
      "buttons": [
        { "type": "QUICK_REPLY", "text": "Unsubscribe from Promos" }
      ]
    }
  ]
}'

Send: the template must be APPROVED. You must specify the location coordinates at send time in the header component:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+16505551234",
  "type": "template",
  "template": {
    "name": "store_grand_opening",
    "language": { "policy": "deterministic", "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "location",
            "location": {
              "latitude": "34.01881798498779",
              "longitude": "-118.46708679200001",
              "name": "Lucky Shrub - Santa Monica",
              "address": "3250 Ocean Park Blvd, Santa Monica, CA 90405"
            }
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "customer_name", "text": "Maria" },
          { "type": "text", "parameter_name": "discount", "text": "15%" }
        ]
      }
    ]
  }
}'

Latitude and longitude are required; name and address are optional. Send-time values are independent of the examples used at creation.

Media card carousel template

Media card carousel templates allow you to send a single marketing template message accompanied by a set of up to 10 product media cards in a horizontally scrollable view.

When a WhatsApp user taps a media card’s URL button to buy a product, the URL mapped to the button is loaded in the device’s default web browser, taking the user out of the WhatsApp client experience. If you prefer to keep the user in the WhatsApp client, see Product Card Carousel Templates. Carousel cards are only available for marketing template messages.

Media cards:

  • A message body text plus up to 10 product media cards.
  • Each card: image or video header asset + optional body text (max 160 characters) + up to two buttons (mix of quick reply, phone number, and URL buttons).
  • All cards defined on a template must have the same components; if any card includes a card body text, then all cards must include one (to ensure consistent card heights).
  • When WhatsApp users place an order, they do so outside of the WhatsApp client, so no webhooks are triggered describing their order.

Create: define the exact number of cards (minimum 2, maximum 10) when you create the template. An approved template can only be used to send the same number of cards as defined during its creation. POST /message_templates/{VERSION}/{did}:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "carousel_template_media_cards_v1",
  "language": "en_US",
  "category": "marketing",
  "components": [
    {
      "type": "body",
      "text": "Rare succulents for sale! {{1}}, add these unique plants to your collection. Each of these rare succulents are {{2}} if you checkout using code {{3}}. Shop now and add some unique and beautiful plants to your collection!",
      "example": { "body_text": [["Pablo", "30%", "30OFF"]] }
    },
    {
      "type": "carousel",
      "cards": [
        {
          "components": [
            {
              "type": "header",
              "format": "image",
              "example": { "header_handle": ["4::an..."] }
            },
            {
              "type": "buttons",
              "buttons": [
                { "type": "quick_reply", "text": "Send me more like this!" },
                {
                  "type": "url",
                  "text": "Shop",
                  "url": "https://www.luckyshrub.com/rare-succulents/{{1}}",
                  "example": ["BLUE_ELF"]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}'

Send: the template must be APPROVED. You supply the same body variables and the contents of each card (card_index zero-indexed, header asset ID, quick reply payload, and text to inject into the URL):

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+16505551234",
  "type": "template",
  "template": {
    "name": "carousel_template_media_cards_v1",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Pablo" },
          { "type": "text", "text": "20%" },
          { "type": "text", "text": "20OFF" }
        ]
      },
      {
        "type": "carousel",
        "cards": [
          {
            "card_index": 0,
            "components": [
              {
                "type": "header",
                "parameters": [
                  { "type": "image", "image": { "id": "1558081531584829" } }
                ]
              },
              {
                "type": "button",
                "sub_type": "quick_reply",
                "index": "0",
                "parameters": [ { "type": "payload", "payload": "more-aloes" } ]
              },
              {
                "type": "button",
                "sub_type": "url",
                "index": "1",
                "parameters": [ { "type": "text", "text": "blue-elf" } ]
              }
            ]
          }
        ]
      }
    ]
  }
}'

Note on indexes: if any buttons use variables, the type and order of buttons must match the type and order defined on the template. You can’t use the index values to rearrange the order of the buttons in the sent template; the index must map the order defined on the template.

Per-user marketing template message limits

WhatsApp may limit the number of marketing template messages a person receives from any business in a given period, starting with delivering fewer marketing conversations to users who are less likely to engage. In most WhatsApp markets, this is determined based on a number of factors, including a dynamic view of an individual’s marketing message read rate.

Refer to per-user marketing template message limits for more information.

User preferences for marketing messages

WhatsApp provides a setting, Offers and announcements, that allows WhatsApp users to indicate their interest level in marketing messages and to stop or resume delivery of marketing messages from your business entirely.

Interested/not interested feedback

Users can use the Offers and announcements setting to indicate how interested they are in receiving marketing template messages from your business.

If a user chooses Not interested, it can affect per-user marketing template messaging limits. Choosing this option also displays a second modal that gives the user the option to stop delivery of marketing messages from your business.

Note: Interested and Not interested feedback does not trigger the user_preferences webhook. Only stop and resume actions trigger the webhook.

Stop/resume controls

Users can use the Offers and announcements setting to stop or resume delivery of marketing template messages from your business.

If you attempt to send a marketing template to a user who has stopped marketing template messages from your business, the API will process the request but not send the message. Instead, the API will trigger a status messages webhook with:

  • status set to failed,
  • code set to 131050,
  • title set to Unable to deliver the message. This recipient has chosen to stop receiving marketing messages on WhatsApp from your business.

To be notified whenever a user stops or resumes delivery of marketing template messages, subscribe to the user_preferences webhook.

Accounts linked with the WhatsApp Business app

To improve the experience for WhatsApp Business Users, marketing messages sent to business customers will not bump chat threads to the top of the inbox. These messages will still be delivered and visible, but the thread will only move to the top if the customer responds.

Note: This feature is currently limited and not generally available (GA) to all users.

Utility templates

Utility templates are typically sent in response to a user action or request, such as an order confirmation or update.

Utility templates have strict content requirements, particularly around marketing material. If you attempt to create or update a utility template with marketing material, the template will automatically be re-categorized as a marketing template. See our template categorization documentation for content guidelines.

Supported components:

  • 1 header (optional; all types supported)
  • 1 body
  • 1 footer (optional)
  • Up to 10 buttons (optional). Supported types:
    • Call request
    • Copy code
    • Phone number
    • Quick-reply
    • URL

Create: POST /message_templates/{VERSION}/{did} with category: "utility":

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "reservation_confirmation",
  "language": "en_US",
  "category": "utility",
  "parameter_format": "named",
  "components": [
    {
      "type": "header",
      "format": "image",
      "example": { "header_handle": ["4::aW..."] }
    },
    {
      "type": "body",
      "text": "*You'\''re all set!*\n\nYour reservation for {{number_of_guests}} at Lucky Shrub Eatery on {{day}}, {{date}}, at {{time}}, is confirmed. See you then!",
      "example": {
        "body_text_named_params": [
          { "param_name": "number_of_guests", "example": "4" },
          { "param_name": "day", "example": "Saturday" },
          { "param_name": "date", "example": "August 30th, 2025" },
          { "param_name": "time", "example": "7:30 pm" }
        ]
      }
    },
    {
      "type": "footer",
      "text": "Lucky Shrub Eatery: The Luckiest Eatery in Town!"
    },
    {
      "type": "buttons",
      "buttons": [
        {
          "type": "url",
          "text": "Change reservation",
          "url": "https://www.luckyshrubeater.com/reservations"
        },
        {
          "type": "phone_number",
          "text": "Call us",
          "phone_number": "+15550051310"
        },
        {
          "type": "quick_reply",
          "text": "Cancel reservation"
        }
      ]
    }
  ]
}'

Send: the template must be APPROVED. Named parameters go in the body with parameter_name:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "16505551234",
  "type": "template",
  "template": {
    "name": "reservation_confirmation",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "header",
        "parameters": [
          { "type": "image", "image": { "id": "2871834006348767" } }
        ]
      },
      {
        "type": "body",
        "parameters": [
          { "type": "text", "parameter_name": "number_of_guests", "text": "4" },
          { "type": "text", "parameter_name": "day", "text": "Saturday" },
          { "type": "text", "parameter_name": "date", "text": "August 30th, 2025" },
          { "type": "text", "parameter_name": "time", "text": "7:30 pm" }
        ]
      }
    ]
  }
}'

Authentication templates

If your mobile app offers users the option to receive one-time passwords or verification codes via WhatsApp, you must use an authentication template.

Authentication template composition:

  • Fixed, non-customizable preset text: <VERIFICATION_CODE> is your verification code.
  • An optional security disclaimer: For your security, do not share this code. (add_security_recommendation)
  • An optional expiration warning: This code expires in <NUM_MINUTES> minutes. (code_expiration_minutes, 1–90)
  • A button: one-tap autofill, copy code, or no button at all (zero-tap).

Button types:

  • One-tap autofill: opens your app and delivers the code without leaving WhatsApp. Requires Android app code changes (supported_apps with package_name + signature_hash).
  • Copy code: copies the code to the clipboard when tapped.
  • Zero-tap: broadcasts the code; your app captures it with a broadcast receiver. Android only.

Linked device security: authentication messages are only delivered to the user’s primary device. Messages sent to linked devices are masked with a prompt to view them on the primary device. Enabled by default, requires no code changes, not configurable. Cloud API only.

Keyboard suggestions (iOS): effective June 15, 2026, enabled by default for all authentication templates. On iOS 26+, iOS detects the OTP in the push notification and presents a one-tap autofill prompt in the keyboard. No integration changes required. Only detects numeric codes of 3 to 8 digits; doesn’t trigger when WhatsApp is in the foreground.

Create: POST /message_templates/{VERSION}/{did} with category: "authentication":

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "verification_code",
  "language": "en_US",
  "category": "authentication",
  "message_send_ttl_seconds": 60,
  "components": [
    {
      "type": "body",
      "add_security_recommendation": true
    },
    {
      "type": "footer",
      "code_expiration_minutes": 10
    },
    {
      "type": "buttons",
      "buttons": [
        {
          "type": "otp",
          "otp_type": "one_tap",
          "text": "Copy Code",
          "autofill_text": "Autofill",
          "supported_apps": [
            { "package_name": "com.example.luckyshrub", "signature_hash": "K8a/AINcGX7" }
          ]
        }
      ]
    }
  ]
}'

Note: in the creation request you designate the button type as otp, but upon creation it is set to url (verifiable with a GET of the template).

Send: the template must be APPROVED. The OTP is sent twice: in the body and in the button:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "12015553931",
  "type": "template",
  "template": {
    "name": "verification_code",
    "language": { "code": "en_US" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "J$FpnYnP" }
        ]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": 0,
        "parameters": [
          { "type": "text", "text": "J$FpnYnP" }
        ]
      }
    ]
  }
}'

Previews: you can generate previews of the authentication template text in various languages with GET /message_template_previews (category=AUTHENTICATION, add_security_recommendation, code_expiration_minutes, button_types=OTP).

Bulk management: create or update authentication templates in multiple languages with POST /{waba-id}/upsert_message_templates (uses languages instead of language; text and autofill_text not supported).

Service messages

Service messages are free-form messages that you can send to WhatsApp users during a customer service window. Unlike template messages, they do not require pre-approval — you can compose and send them as needed in response to a WhatsApp user’s message or call.

Service messages can only be sent via the Messages API. To message users outside of a customer service window, use template messages instead.

Customer service windows

When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window starts. If the user messages or calls you again before the timer expires, the timer resets to 24 hours.

While the window is open, you can send any of the service message types listed below. When the window closes, you can only send pre-approved template messages.

Remember: you can only send messages to WhatsApp users who have opted in to receiving messages from you.

Pricing

Service messages are billed under the SERVICE pricing category. See Pricing.

Message types

Type (type)Description
textText body with optional link preview (preview_url, body max 4096 chars).
imageA single image with optional caption.
videoVideo thumbnail with optional caption.
audioAudio icon + link to audio file. voice: true for voice message (.ogg OPUS).
documentDownloadable document icon, with optional filename.
stickerAnimated or static sticker (.webp).
contactsRich contact info (names, phones, addresses, emails).
locationLatitude/longitude coordinates, with optional name and address.
interactiveInteractive messages: button (reply buttons, up to 3), list (up to 10 sections/10 rows), cta_url, carousel (2–10 media cards), location_request_message, address_message (India only).
reactionEmoji-reaction on a received message.

Common request:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/messages/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "+16505551234",
  "type": "text",
  "text": {
    "preview_url": true,
    "body": "As requested, here'\''s the link to our latest product: https://www.meta.com/quest/quest-3/"
  }
}'

Important notes:

  • Phone number formats: +, -, (, ) and spaces are supported. Always include + and the country calling code; if the + is omitted, your business number’s country calling code is prepended (can result in undelivered/misdelivered messages).
  • Media caching: assets hosted by link are cached 10 minutes; append a random query string to force a re-fetch.
  • Delivery sequence: delivery order is not guaranteed; confirm the delivered status webhook before sending the next message if you need sequencing.
  • TTL: 30 days for all messages except authentication templates (10 minutes). If you don’t receive delivered before the TTL, assume the message was dropped.
  • Mark as read: POST /messages with {"status":"read","message_id":"<wamid>"} (within 30 days). Add typing_indicator: {"type":"text"} to show a typing indicator (dismissed on response or after 25 seconds).
  • Contextual replies: include context: {"message_id":"<wamid>"} to quote the previous message in a contextual bubble.
  • Message quality: based on how messages were received over the past 7 days (blocks, reports, mutes, archives). Follow the WhatsApp Business Messaging Policy, only send to opt-ins, personalize, and avoid open-ended welcome messages.

Create a template

Text-only template

Request

POST /message_templates/{VERSION}/{did}

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "pedido_cancelado_reembolso",
  "language": "es",
  "category": "UTILITY",
  "allow_category_change": true,
  "components": [
    {
      "type": "BODY",
      "text": "Su pedido ha sido cancelado; su reembolso se procesará en 7-10 días"
    }
  ]
}'

Properties:

FieldTypeDescription
nameStringTemplate name. Max 512 characters.
categoryEnumTemplate categories.
allow_category_changebooleanAllows automatically assigning a category. If omitted, the template may be rejected for incorrect categorization.
languageEnumLanguage code.
componentsObjectTemplate components.

Response

Success (200)

{
  "id": "<ID>",
  "status": "<STATUS>",
  "category": "<CATEGORY>"
}

Template with image header and text body

Request

POST /message_templates/{VERSION}/{did}

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "isv_template",
  "language": "es_ES",
  "category": "MARKETING",
  "components": [
    {
      "type": "HEADER",
      "format": "IMAGE",
      "example": {
        "header_handle": [
          "4::aW1h"
        ]
      }
    },
    {
      "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" }
      ]
    }
  ]
}'
The header_handle value (4::...) is obtained when uploading the image to Meta (see Upload multimedia).

Response

Success (200)

{
  "id": "<ID>",
  "status": "<STATUS>",
  "category": "<CATEGORY>"
}

Edit a template

Request

PUT /message_templates/{VERSION}/{did}/{message_template_id}

curl --request PUT \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/{message_template_id}' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{}'

Limitations

  • Only templates in APPROVED, REJECTED or PAUSED status can be edited.
  • Only the category or components properties can be edited.
  • The category of an approved template cannot be edited.
  • Approved templates can be edited a maximum of ten times in 30 days or once every 24 hours. Rejected or paused templates have no limit.
  • After editing an approved or paused template, it will be approved automatically unless it fails review.

Body:

{
  "category": "<CATEGORY>",
  "components": [
    {
      "type": "HEADER",
      "format": "TEXT",
      "text": "Hola y bienvenido"
    }
  ]
}

Response

Success (200)

{
  "success": true
}

Get templates

List templates

Request

GET /message_templates/{VERSION}/{did}?fields=format,rejected_reason,quality_score,status,name,language,components,category,previous_category&limit=5

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?fields=format,rejected_reason,quality_score,status,name,language,components,category,previous_category&limit=5' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "data": [
    {
      "id": "2606927862810126",
      "name": "un_template",
      "components": [{ "type": "BODY", "text": "this is" }],
      "language": "es",
      "status": "REJECTED",
      "category": "UTILITY",
      "rejected_reason": "INCORRECT_CATEGORY",
      "quality_score": { "score": "UNKNOWN" }
    },
    {
      "id": "402086912569912",
      "name": "test_template_dev",
      "components": [{ "type": "BODY", "text": "this is a test" }],
      "language": "es",
      "status": "APPROVED",
      "category": "MARKETING",
      "rejected_reason": "NONE",
      "quality_score": { "score": "UNKNOWN" }
    }
  ],
  "paging": {
    "cursors": { "before": "MAZDZD", "after": "MQZDZD" }
  }
}

Get template summary

Request

GET /message_templates/{VERSION}/{did}?fields=id&limit=1&summary=total_count,message_template_count,message_template_limit,are_translations_complete

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?fields=id&limit=1&summary=total_count,message_template_count,message_template_limit,are_translations_complete' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "data": [{ "id": "2606927862810126" }],
  "paging": {
    "cursors": { "before": "MAZDZD", "after": "MAZDZD" }
  },
  "summary": {
    "total_count": 169,
    "message_template_count": 148,
    "message_template_limit": 6000,
    "are_translations_complete": false
  }
}

Get template by name or content

Request

GET /message_templates/{VERSION}/{did}?name_or_content=tpl_flow_demo_preview&limit=1

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?name_or_content=tpl_flow_demo_preview&limit=1' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "data": [
    {
      "id": "210800678688659",
      "name": "tpl_flow_demo_preview",
      "components": [
        {
          "type": "BODY",
          "text": "Hola y bienvenido a la demo de flow.\nPuedes responder a continuación las preguntas iniciales."
        },
        {
          "type": "BUTTONS",
          "buttons": [
            {
              "type": "FLOW",
              "text": "Responder",
              "flow_id": 2033644160334325,
              "flow_action": "NAVIGATE",
              "navigate_screen": "REGISTER"
            }
          ]
        }
      ],
      "language": "es",
      "status": "APPROVED",
      "category": "MARKETING"
    }
  ],
  "paging": {
    "cursors": { "before": "MAZDZD", "after": "MAZDZD" }
  }
}

Get template by name

Request

GET /message_templates/{VERSION}/{did}?name=tpl_flow_demo_preview&limit=1

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?name=tpl_flow_demo_preview&limit=1' \
  --header 'Authorization: <JWT>'

Response

Success (200)

The response is identical to get template by name or content (name_or_content).

Upload multimedia

To upload a new image to Meta, query the following endpoint:

Request

POST /{VERSION}/{did}/uploads

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{VERSION}/{did}/uploads' \
  --header 'Authorization: <JWT>' \
  -F 'file=@/path/image.jpg'
FieldTypeRequiredDescription
fileFileYesImage to upload.

Response

Success (200)

{
  "h": "4::aW1hZ2............."
}

Template metrics

Request

GET /message_templates/{VERSION}/{did}/analytics?granularity=DAILY&metric_types=["CLICKED","DELIVERED","READ","SENT"]&start=1709769600&end=1709841600&template_ids=[776614587250474]

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/analytics?granularity=DAILY&metric_types=["CLICKED","DELIVERED","READ","SENT"]&start=1709769600&end=1709841600&template_ids=[776614587250474]' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "data": [
    {
      "granularity": "DAILY",
      "data_points": [
        {
          "template_id": "776614587250474",
          "start": 1709769600,
          "end": 1709856000,
          "sent": 2,
          "delivered": 2,
          "read": 2,
          "clicked": [
            {
              "type": "url_button",
              "button_content": "Visitar el sitio web",
              "count": 1
            }
          ]
        }
      ]
    }
  ],
  "paging": {
    "cursors": { "before": "MAZDZD", "after": "MjQZD" }
  }
}

Delete a template

By name

Request

DELETE /message_templates/{VERSION}/{did}?name=test_name

curl --request DELETE \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?name=test_name' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "success": true
}

By ID and name

Request

DELETE /message_templates/{VERSION}/{did}?hsm_id=1723223958184989&name=test_name

curl --request DELETE \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}?hsm_id=1723223958184989&name=test_name' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "success": true
}

Enable template analytics

You must confirm template analytics in the WhatsApp Business account to get the data, either with the WhatsApp Manager or the API.

Request

POST /message_templates/{VERSION}/{did}/enable_analytics

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/enable_analytics' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{}'
Once confirmed, template analytics cannot be disabled.

Response

Success (200)

{
  "id": 102290129340398
}

Disable button click analytics

You can disable button click tracking on an individual template by setting its cta_url_link_tracking_opted_out field to true. Once disabled, the API no longer returns the clicked property in template analytics.

Request

POST /message_templates/{VERSION}/{did}/{message_template_id}?cta_url_link_tracking_opted_out=true&category=marketing

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/{message_template_id}?cta_url_link_tracking_opted_out=true&category=marketing' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{}'

Query parameters:

FieldTypeDescription
cta_url_link_tracking_opted_outbooleanIndicates whether click tracking is disabled. Set to false when creating the template.
categorystringIf the category changes, the status becomes PENDING and the template must undergo review.

Response

Success (200)

{
  "id": 102290129340398
}

Get template namespace

The message template namespace is needed to send messages with templates.

Request

GET /message_templates/{VERSION}/{did}/message_template_namespace

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/message_template_namespace' \
  --header 'Authorization: <JWT>' \

Response

Success (200)

{
  "id": "1972385232742141",
  "message_template_namespace": "12abcdefghijk_34lmnop"
}

Migrate a template

Request

POST /message_templates/{VERSION}/{did}/migrate_message_templates?source_waba_id=102290129340398&page_number=0

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/migrate_message_templates?source_waba_id=102290129340398&page_number=0' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{}'

Query parameters:

FieldTypeDescription
source_waba_idStringSource WhatsApp Business Account ID.
page_numbernumberTemplates to migrate in sets of 2500. Zero-indexed. E.g. to migrate 5000 templates, send two requests with values 0 and 1.

Response

Success (200)

{
  "migrated_templates": [
    "1473688840035974",
    "6162904357082268",
    "6147830171896170"
  ],
  "failed_templates": {
    "1019496902803242": "Incorrect category",
    "259672276895259": "Formatting error - dangling parameter",
    "572279198452421": "Incorrect category"
  }
}

Compare templates

You can compare two templates by examining how often each one is sent, which one has the lower ratio of blocks to sends, and each template’s top reason for being blocked.

Requirements

Limitations

  • Only two templates can be compared at a time.
  • Both templates must be in the same WhatsApp Business account.
  • Templates must have been sent at least 1,000 times in the query’s specified timeframe.
  • Lookback windows are limited to 7, 30, 60, and 90 days from the time of the request.

Request

GET /message_templates/{VERSION}/{did}/{message_template_id}/compare?template_ids=[776614587250474]&start=1709742142450&end=1709749918450

curl --request GET \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/{message_template_id}/compare?template_ids=[776614587250474]&start=1709742142450&end=1709749918450' \
  --header 'Authorization: <JWT>' \

Query parameters:

FieldTypeDescription
template_idsStringID of the template to compare with.
starttimestampUNIX start timestamp. See Timeframes.
endtimestampUNIX end timestamp. See Timeframes.

Timeframes

Lookback windows are limited to 7, 30, 60, and 90 days from the time of the request. To define a timeframe, set your end date to the current time as a Unix timestamp, then subtract the number of seconds for your desired window:

WindowSeconds to subtract
7 days604800
30 days2592000
60 days5184000
90 days7776000

Response

Success (200)

Upon success, the API returns a list of nodes describing each template’s block rate, number of times sent, and top reason for being blocked.

{
  "data": [
    {
      "metric": "BLOCK_RATE",
      "type": "RELATIVE",
      "order_by_relative_metric": ["1533406637136032", "5289179717853347"]
    },
    {
      "metric": "MESSAGE_SENDS",
      "type": "NUMBER_VALUES",
      "number_values": [
        { "key": "5289179717853347", "value": 1273 },
        { "key": "1533406637136032", "value": 1042 }
      ]
    },
    {
      "metric": "TOP_BLOCK_REASON",
      "type": "STRING_VALUES",
      "string_values": [
        { "key": "5289179717853347", "value": "UNKNOWN_BLOCK_REASON" },
        { "key": "1533406637136032", "value": "UNKNOWN_BLOCK_REASON" }
      ]
    }
  ]
}

Response contents:

PlaceholderDescription
<ORDER_BY_RELATIVE_METRIC>Array of template ID strings, in increasing order of block rate (ratio of blocks to sends).
<NUMBER_VALUES>Array of message send number value objects. Each object has key (String, template ID) and value (Integer, times sent).
<STRING_VALUES>Array of top block reason string value objects. Each object has key (String, template ID) and value (String, block reason).

Possible block reasons:

  • NO_LONGER_NEEDED
  • NO_REASON
  • NO_REASON_GIVEN
  • NO_SIGN_UP
  • OFFENSIVE_MESSAGES
  • OTHER
  • OTP_DID_NOT_REQUEST
  • SPAM
  • UNKNOWN_BLOCK_REASON

See the View metrics for your WhatsApp Business message template help center topic for descriptions of these reasons.

Unpause a template

Request

POST /message_templates/{VERSION}/{did}/{message_template_id}/unpause

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/message_templates/{VERSION}/{did}/{message_template_id}/unpause' \
  --header 'Authorization: <JWT>' \
  --header 'Content-Type: application/json' \
  --data '{}'

Response

Success (200)

{
  "success": true
}