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.
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}}orCongratulations!).
| Message objective | Business goal | Examples |
|---|---|---|
| Awareness | Generate awareness of your business, products, or services. | New tower installed, event invitation, resort opening. |
| Sales | Send promotional offers, coupons, or content to drive sales or renewals. | Loyalty discount, donations, subscription upgrade, pre-approved credit card. |
| Retargeting | Promote 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 Promotion | Request install or a specific app action. | In-app checkout, new feature, in-app discount, community welcome. |
| Build Customer Relationships | Strengthen 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 objective | Business goal | Examples |
|---|---|---|
| Opt-In Management | Confirm opt-in/opt-out collected via other channels. | Opt-in confirmation, opt-out confirmation. |
| Order Management | Confirm, update, or cancel orders with specific details. No promoting, recommending, upselling, cross-selling, or offers. | Order confirmation, tracking, backorder, refund. |
| Account Alerts or Updates | Time-sensitive updates for purchased/subscribed products or services. No promotions or offers. | Account balance, payment reminder, minutes remaining, profile setup, new support number. |
| Feedback Surveys | Collect 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 Conversation | Move 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 category | Use case | Example |
|---|---|---|
| Public Safety | Severe weather | Tornado alert, stay indoors. |
| Public Safety | Crisis response | Support services activated, live updates. |
| Public Service | Health awareness | Free COVID-19 vaccination. |
| Public Service | Health emergency | Health emergency declared by the city. |
| Public Service | Voting registration | Voter registration card check. |
| Public Service | Disbursements | Welfare disbursement balance. |
| Public Disruption | System outages | System outage impacting a zip code. |
| Public Disruption | Operational disruption | Trains halted due to an issue. |
| Account/Product Protection | Fraud awareness | ATM fraud increase, update PIN. |
| Account/Product Protection | Product recalls | Recalled product. |
| Account/Product Protection | Warranty alerts | Active warranty, manuals. |
| Legal/Regulatory Compliance | Identity compliance | Upgrade identification card. |
| Legal/Regulatory Compliance | Privacy disclosures | Updated privacy policy. |
| Legal/Regulatory Compliance | Warranty alerts | Active 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, andmessage_template_status_updatewebhook withevent: APPROVED.- Warning (since Apr 9, 2025): if you selected
UTILITYand WhatsApp determined it should beMARKETING, the template is approved asMARKETING. You can request a review up to 60 days from the category update. - Warning (since Apr 9, 2025):
allow_category_changenow defaults totruein creation.
- Warning (since Apr 9, 2025): if you selected
PENDING: WhatsApp agrees with the category but the template is under review. On completion, amessage_template_status_updatewebhook withevent: APPROVEDorREJECTED.REJECTED: WhatsApp disagrees with the category you designated. Webhookmessage_template_status_updatewithevent: REJECTEDandreason: 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
APPROVEDand 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
REJECTEDand can no longer be used to send.
Notifications:
| Channel | Detail |
|---|---|
| To people with full control of the portfolio over the WABA. Contains a link to the Manage Templates panel. | |
| Webhook | template_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 Manager | Manage 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 andcorrect_categoryis non-empty → will be updated on the 1st of next month; ifcorrect_categoryis 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_updatewebhook fires withnew_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:
- In WhatsApp Manager, select the Message Templates dropdown, then Message Templates. You should see a rejection banner. Click Go to Business Support.
- 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:
| Level | What happens | Duration |
|---|---|---|
| Warning | Written warning to WABA admins. After a warning, utility→marketing changes become instant. | Ongoing |
| Rate limiting | Utility 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 restriction | All 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 restriction | If 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_updatewebhook with therestriction_infoobject 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.
| Scenario | violation_type | restriction_info | restriction_type |
|---|---|---|---|
| Warning | UTILITY_TEMPLATE_ABUSE | Omitted | — |
| Utility template suspension | UTILITY_TEMPLATE_ABUSE | Present | RESTRICTED_UTILITY_TEMPLATES |
| Suspension removed | UTILITY_TEMPLATE_ABUSE_UNBAN | Omitted | — |
| Utility messages rate limited | UTILITY_TEMPLATE_ABUSE_RATE_LIMIT | Present | RATE_LIMITED_UTILITY_TEMPLATE_MESSAGING |
| Rate limit removed | UTILITY_TEMPLATE_ABUSE_RATE_LIMIT_RECOVERY | Omitted | — |
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:
| Language | Code |
|---|---|
| Afrikaans | af |
| Albanian | sq |
| Arabic | ar |
| Arabic (EGY) | ar_EG |
| Arabic (UAE) | ar_AE |
| Arabic (LBN) | ar_LB |
| Arabic (MAR) | ar_MA |
| Arabic (QAT) | ar_QA |
| Azerbaijani | az |
| Belarusian | be_BY |
| Bengali | bn |
| Bengali (IND) | bn_IN |
| Bulgarian | bg |
| Catalan | ca |
| Chinese (CHN) | zh_CN |
| Chinese (HKG) | zh_HK |
| Chinese (TAI) | zh_TW |
| Croatian | hr |
| Czech | cs |
| Danish | da |
| Dari | prs_AF |
| Dutch | nl |
| Dutch (BEL) | nl_BE |
| English | en |
| 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 |
| Estonian | et |
| Filipino | fil |
| Finnish | fi |
| French | fr |
| French (BEL) | fr_BE |
| French (CAN) | fr_CA |
| French (CHE) | fr_CH |
| French (CIV) | fr_CI |
| French (MAR) | fr_MA |
| Georgian | ka |
| German | de |
| German (AUT) | de_AT |
| German (CHE) | de_CH |
| Greek | el |
| Gujarati | gu |
| Hausa | ha |
| Hebrew | he |
| Hindi | hi |
| Hungarian | hu |
| Indonesian | id |
| Irish | ga |
| Italian | it |
| Japanese | ja |
| Kannada | kn |
| Kazakh | kk |
| Kinyarwanda | rw_RW |
| Korean | ko |
| Kyrgyz (Kyrgyzstan) | ky_KG |
| Lao | lo |
| Latvian | lv |
| Lithuanian | lt |
| Macedonian | mk |
| Malay | ms |
| Malayalam | ml |
| Marathi | mr |
| Norwegian | nb |
| Pashto | ps_AF |
| Persian | fa |
| Polish | pl |
| Portuguese (BR) | pt_BR |
| Portuguese (POR) | pt_PT |
| Punjabi | pa |
| Romanian | ro |
| Russian | ru |
| Serbian | sr |
| Sinhala | si_LK |
| Slovak | sk |
| Slovenian | sl |
| Spanish | es |
| 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 |
| Swahili | sw |
| Swedish | sv |
| Tamil | ta |
| Telugu | te |
| Thai | th |
| Turkish | tr |
| Ukrainian | uk |
| Urdu | ur |
| Uzbek | uz |
| Vietnamese | vi |
| Zulu | zu |
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:
- Messaging limits — limit on templates sendable outside customer service windows.
- Template pacing — gives users time to provide feedback.
- Template pausing — can pause templates with poor feedback.
- Template archival — archives and deletes templates inactive for 12+ months (deleted after 28 days unless unarchived).
- Per-user marketing template message limits — limits how many marketing templates a given user receives from any business.
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>" }
]
}
}| Placeholder | Description | Example |
|---|---|---|
<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>"]
}
}| Placeholder | Description | Example |
|---|---|---|
<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 (
idproperty). - Host the asset on your server and use its URL (
linkproperty). If usinglink, 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>"
}
}
]
}| Placeholder | Description | Example |
|---|---|---|
<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>"]
}
}| Placeholder | Description | Example |
|---|---|---|
<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>"
}| Placeholder | Description | Example |
|---|---|---|
<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>"
}| Placeholder | Description | Example |
|---|---|---|
<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>"
}| Placeholder | Description | Example |
|---|---|---|
<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>"
}| Placeholder | Description | Example |
|---|---|---|
<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>"]
}| Placeholder | Description | Example |
|---|---|---|
<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.
| Character | Encoded value | Example |
|---|---|---|
| Space | %20 | New York → New%20York |
: | %3A | x:key → x%3Akey |
| | %7C | 9|DL → 9%7CDL |
ç | %C3%A7 | Gonçalves → Gon%C3%A7alves |
ñ | %C3%B1 | Peña → Pe%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 type | Description | Sample value |
|---|---|---|
ADDRESS | A location address. Must be valid. | 1 Hacker Way, Menlo Park, CA 94025 |
TEXT | Basic text. | regarding your order. |
AMOUNT | A number signifying a quantity. May have monetary prefix/suffix (USD, RS), decimals, commas, and currency symbols ($, €). | USD $375.32 |
DATE | A standard calendar date. | 2021-04-19 |
PHONE NUMBER | A telephone number. May contain numbers, spaces, dashes, parentheses, and plus symbols. | +1 4256789900 |
EMAIL | A standard email address. Must be valid. | 1hackerway@meta.com |
NUMBER | A 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 librarySearching 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:
| Placeholder | Description | Sample 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:
| Placeholder | Description | Sample 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:
| Placeholder | Description | Sample value |
|---|---|---|
type | The button type: QUICK_REPLY, URL, PHONE_NUMBER, OTP, MPM, CATALOG, FLOW, VOICE_CALL, APP. Required | OTP |
phone_number | Phone number for the button. Optional | "+13057652345" |
url | JSON object with base_url and url_suffix_example. Optional | — |
zero_tap_terms_accepted | Whether zero tap terms were accepted. Optional | TRUE |
otp_type | The OTP type: COPY_CODE, ONE_TAP, ZERO_TAP. Optional | COPY_CODE |
supported_apps | Array of objects with package_name and signature_hash. Optional | — |
Library template body inputs:
| Placeholder | Description | Sample value |
|---|---|---|
add_contact_number | Add info about contacting the business by phone. Optional | TRUE |
add_learn_more_link | Add a “learn more” URL link. Optional | TRUE |
add_security_recommendation | Add info about not sharing authentication codes. Optional | TRUE |
add_track_package_link | Add a package tracking link. Optional | TRUE |
code_expiration_minutes | Minutes until the code expires. Optional | 5 |
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, orARCHIVED. - 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_updatewebhook 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
- You have an active WhatsApp Business Account and are in a country eligible for MM API.
- You have an approved marketing template message.
- You are subscribed to the messages webhook.
Accept Terms of Service
- Navigate to the App Dashboard > WhatsApp > Quickstart panel.
- Locate the “Improve ROI with marketing messages with optimizations” module and click the “Get started” button.
- 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_messagingpermission. - 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) orSTRICT(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
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.
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.
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
| Description | MM 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
| Description | MM API (Marketing) | Cloud API |
|---|---|---|
| Animated image (GIF) header | Yes | No |
| Android app deep links: links that open a specified app on a customer’s Android device. | Yes | No |
| 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. | Yes | Yes |
Guidance
| Description | MM API (Marketing) | Cloud API |
|---|---|---|
| Benchmarks: comparison of read and click rates versus similar templates from other businesses in your region. | Yes | No |
| Recommendations: data-derived recommendations to improve performance. | Yes | No |
Metrics
| Description | MM 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. | Yes | Yes |
| Basic metrics: sent, delivered, read, clicked, errors. | Yes | Yes |
Enterprise, security, and compliance
| Description | MM API (Marketing) | Cloud API |
|---|---|---|
| Local Storage support | Yes | Yes |
| Compliance certification: LGPD, GDPR, System Audit Report, SOC, ISO27001. | Yes | Yes |
| Automatic throughput upgrades (with webhook notifications) | Yes | Yes |
| Real-time service status: uptime metrics on metastatus.com. | Yes | Yes |
Onboarding
| Description | MM API (Marketing) | Cloud API |
|---|---|---|
| Onboarding options: Embedded Signup, Intent API, Intent UI. | Yes (all) | Limited: Embedded Signup only. |
| Error codes: MM API-specific codes. | Yes | Yes |
| Onboarding status via API: eligibility field. | Yes | Limited |
| WhatsApp Business app user onboarding | Yes | Yes |
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:
| Component | Count | Required |
|---|---|---|
| Header | 1 | Optional (all types supported) |
| Body | 1 | Required |
| Footer | 1 | Optional |
| Buttons | Up to 10 | Optional (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:
- Catalog templates: showcase your product catalog entirely within WhatsApp.
- Coupon code templates: display a single copy code button. When tapped, the code is copied to the customer’s clipboard.
- Media card carousel templates: a single text message accompanied by up to 10 media cards in a horizontally scrollable view.
- Call permission request templates: allow your business to call customers outside the customer service window.
- Limited-time offer templates: display expiration dates and running countdown timers for offer codes.
- Multi-product message templates (MPM): up to 30 products from your ecommerce catalog, organized in up to 10 sections, in a single message.
- Product card carousel templates: a single text message accompanied by up to 10 product cards in a horizontally scrollable view.
- Single-product message templates (SPM): a single text message accompanied by up to 10 product cards in a horizontally scrollable view.
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
MARKETINGorUTILITYcan 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
MARKETINGare 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
UTILITYorMARKETINGcan 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_preferenceswebhook. 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:
statusset tofailed,codeset to131050,titleset toUnable 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_appswithpackage_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 |
|---|---|
text | Text body with optional link preview (preview_url, body max 4096 chars). |
image | A single image with optional caption. |
video | Video thumbnail with optional caption. |
audio | Audio icon + link to audio file. voice: true for voice message (.ogg OPUS). |
document | Downloadable document icon, with optional filename. |
sticker | Animated or static sticker (.webp). |
contacts | Rich contact info (names, phones, addresses, emails). |
location | Latitude/longitude coordinates, with optional name and address. |
interactive | Interactive 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). |
reaction | Emoji-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
linkare cached 10 minutes; append a random query string to force a re-fetch. - Delivery sequence: delivery order is not guaranteed; confirm the
deliveredstatus 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
deliveredbefore the TTL, assume the message was dropped. - Mark as read:
POST /messageswith{"status":"read","message_id":"<wamid>"}(within 30 days). Addtyping_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:
| Field | Type | Description |
|---|---|---|
name | String | Template name. Max 512 characters. |
category | Enum | Template categories. |
allow_category_change | boolean | Allows automatically assigning a category. If omitted, the template may be rejected for incorrect categorization. |
language | Enum | Language code. |
components | Object | Template 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" }
]
}
]
}'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,REJECTEDorPAUSEDstatus can be edited. - Only the
categoryorcomponentsproperties can be edited. - The
categoryof 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'| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | Image 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 '{}'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:
| Field | Type | Description |
|---|---|---|
cta_url_link_tracking_opted_out | boolean | Indicates whether click tracking is disabled. Set to false when creating the template. |
category | string | If 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:
| Field | Type | Description |
|---|---|---|
source_waba_id | String | Source WhatsApp Business Account ID. |
page_number | number | Templates 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
- A User or System User access token.
- The whatsapp_business_management permission.
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:
| Field | Type | Description |
|---|---|---|
template_ids | String | ID of the template to compare with. |
start | timestamp | UNIX start timestamp. See Timeframes. |
end | timestamp | UNIX 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:
| Window | Seconds to subtract |
|---|---|
| 7 days | 604800 |
| 30 days | 2592000 |
| 60 days | 5184000 |
| 90 days | 7776000 |
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:
| Placeholder | Description |
|---|---|
<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_NEEDEDNO_REASONNO_REASON_GIVENNO_SIGN_UPOFFENSIVE_MESSAGESOTHEROTP_DID_NOT_REQUESTSPAMUNKNOWN_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
}