{"id":748,"date":"2026-10-29T13:22:20","date_gmt":"2026-10-29T13:22:20","guid":{"rendered":"https:\/\/vectalk.com.br\/blog\/create-whatsapp-template-api\/"},"modified":"2026-10-29T13:22:28","modified_gmt":"2026-10-29T13:22:28","slug":"create-whatsapp-template-api","status":"publish","type":"post","link":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/","title":{"rendered":"How to create, edit and delete WhatsApp message templates via the API"},"content":{"rendered":"\n<p><em>Updated on October 29, 2026<\/em><\/p>\n\n\n\n<p>To create a WhatsApp message template through the API, send <code>POST \/&lt;WABA_ID&gt;\/message_templates<\/code> with <code>name<\/code>, <code>language<\/code>, <code>category<\/code> and a <code>components<\/code> array that includes a sample value for every variable. Meta replies with the template <code>id<\/code> and a <code>PENDING<\/code> status, and the review result arrives through the <code>message_template_status_update<\/code> webhook. To edit, call <code>POST \/&lt;TEMPLATE_ID&gt;<\/code>; to delete, call <code>DELETE \/&lt;WABA_ID&gt;\/message_templates?name=...<\/code>, adding <code>hsm_id<\/code> to remove a single language.<\/p>\n\n\n\n<p>This guide covers the payload for every operation, the edit and delete limits, and the mistakes that most often break template automation. For what templates are and when you need them, see our guide to <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-api-message-templates\/\">WhatsApp API message templates<\/a>; here we focus on the template lifecycle through the WhatsApp Business API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where templates live after September 23, 2026<\/h2>\n\n\n\n<p>Since September 23, 2026, Meta has been splitting the old WhatsApp Business Account (WABA) into a <strong>WhatsApp account<\/strong> (the phone number and profile) and a <strong>messaging account<\/strong> (templates, billing and webhooks). The template docs now say &#8220;Messaging account&#8221;: templates are messaging account assets, and each messaging account has its own set.<\/p>\n\n\n\n<p>In practice, your code does not change. Messaging accounts inherited the WABA ID, and the documentation examples still use <code>\/&lt;WABA_ID&gt;\/message_templates<\/code>, so the ID you already use keeps working for create, list and delete. The consequence that matters is a different one: templates are not shared across messaging accounts. If two providers use the same number, each one has its own messaging account and needs the templates created there. The full picture is in <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-account-messaging-account-waba\/\">WhatsApp account vs. messaging account<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Before you start<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Account ID<\/strong>: the WABA ID (which is also the messaging account ID). If you are not sure where to find it, see <a href=\"https:\/\/vectalk.com.br\/blog\/en\/find-whatsapp-phone-number-id\/\">where to find the Phone Number ID and WABA ID<\/a>.<\/li>\n\n\n<li><strong>Access token<\/strong>: it needs the <code>whatsapp_business_management<\/code> permission. According to the docs, a token with only <code>whatsapp_business_messaging<\/code> gets error code 200 when deleting. For production, use a <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-api-permanent-access-token\/\">permanent system user token<\/a>.<\/li>\n\n\n<li><strong>Graph API version<\/strong>: the examples use <code>v26.0<\/code>. Swap in the version you run.<\/li>\n\n\n<li><strong>Account limits<\/strong>: up to 100 templates created per hour per messaging account. The total cap is 250 templates if the business portfolio is unverified, and up to 6,000 if it is verified and has an approved display name on at least one WhatsApp account.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Create request fields<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Field<\/th><th>Required<\/th><th>What it is<\/th><\/tr><\/thead><tbody><tr><td><code>name<\/code><\/td><td>Yes<\/td><td>Lowercase letters, numbers and underscores; up to 512 characters<\/td><\/tr><tr><td><code>language<\/code><\/td><td>Yes<\/td><td>Language code such as <code>en_US<\/code>, <code>pt_BR<\/code> or <code>es_MX<\/code><\/td><\/tr><tr><td><code>category<\/code><\/td><td>Yes<\/td><td><code>MARKETING<\/code>, <code>UTILITY<\/code> or <code>AUTHENTICATION<\/code><\/td><\/tr><tr><td><code>components<\/code><\/td><td>In practice, yes<\/td><td><code>HEADER<\/code>, <code>BODY<\/code>, <code>FOOTER<\/code> and <code>BUTTONS<\/code><\/td><\/tr><tr><td><code>parameter_format<\/code><\/td><td>No<\/td><td><code>POSITIONAL<\/code> (<code>{{1}}<\/code>) or <code>NAMED<\/code> (<code>{{first_name}}<\/code>)<\/td><\/tr><tr><td><code>message_send_ttl_seconds<\/code><\/td><td>No<\/td><td>Time-to-live for sent messages<\/td><\/tr><tr><td><code>library_template_name<\/code><\/td><td>No<\/td><td>Creates the template from Meta&#8217;s template library<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Names are not unique: you can have <code>order_shipped<\/code> in <code>en_US<\/code> and in <code>es_MX<\/code>, and each name + language pair is a separate template with its own ID. The create response has three fields:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"id\": \"1252715608684590\",\n  \"status\": \"PENDING\",\n  \"category\": \"UTILITY\"\n}<\/code><\/pre>\n\n\n\n<p>Store the <code>id<\/code>. It is the key to check, edit and delete that specific language.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Example 1: utility template with positional variables<\/h2>\n\n\n\n<p>Every variable needs a sample value, or the creation fails. Body samples go in <code>example.body_text<\/code>, an array inside an array, in variable order.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -X POST \"https:\/\/graph.facebook.com\/v26.0\/&lt;WABA_ID&gt;\/message_templates\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"name\": \"order_shipped\",\n    \"language\": \"en_US\",\n    \"category\": \"UTILITY\",\n    \"components\": [\n      {\n        \"type\": \"HEADER\",\n        \"format\": \"TEXT\",\n        \"text\": \"Order {{1}} shipped\",\n        \"example\": { \"header_text\": [\"#4821\"] }\n      },\n      {\n        \"type\": \"BODY\",\n        \"text\": \"Hi {{1}}, your order is on its way and should arrive by {{2}}. Tracking code: {{3}}.\",\n        \"example\": { \"body_text\": [[\"Ana\", \"Nov 5\", \"BR123456789\"]] }\n      },\n      {\n        \"type\": \"FOOTER\",\n        \"text\": \"Reply to this message if you need help\"\n      }\n    ]\n  }'<\/code><\/pre>\n\n\n\n<p>A text header takes only one variable. Its sample goes in <code>header_text<\/code> (a flat array), while the body sample goes in <code>body_text<\/code> (an array of arrays). Mixing up the two is one of the most common errors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Example 2: named variables<\/h2>\n\n\n\n<p>With <code>parameter_format: \"NAMED\"<\/code>, variables get names instead of numbers, and the samples move to <code>body_text_named_params<\/code> (<code>header_text_named_params<\/code> for the header), each with <code>param_name<\/code> and <code>example<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"name\": \"invoice_available\",\n  \"language\": \"en_US\",\n  \"category\": \"UTILITY\",\n  \"parameter_format\": \"NAMED\",\n  \"components\": [\n    {\n      \"type\": \"BODY\",\n      \"text\": \"Hi {{first_name}}. Your invoice {{invoice_number}} is due on {{due_date}}.\",\n      \"example\": {\n        \"body_text_named_params\": [\n          { \"param_name\": \"first_name\", \"example\": \"Carlos\" },\n          { \"param_name\": \"invoice_number\", \"example\": \"2026-10-0193\" },\n          { \"param_name\": \"due_date\", \"example\": \"November 10, 2026\" }\n        ]\n      }\n    }\n  ]\n}<\/code><\/pre>\n\n\n\n<p>Named variables make the send payload easier to read and stop <code>{{2}}<\/code> and <code>{{3}}<\/code> from getting swapped when someone rewrites the copy. Meta&#8217;s examples use lowercase names with underscores; follow the same pattern. The format also applies at send time: a <code>NAMED<\/code> template is sent with a <code>parameter_name<\/code> on each parameter, as shown in <a href=\"https:\/\/vectalk.com.br\/blog\/en\/send-whatsapp-template-message-api\/\">how to send a template through the API<\/a>.<\/p>\n\n\n\n<p>An invoice reminder for your own customer, like the one above, is a utility message. Collecting debts on behalf of third parties is prohibited by the WhatsApp Business Messaging Policy, in any category.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Example 3: image, video or document header<\/h2>\n\n\n\n<p>For a media header, the sample is not a URL: it is a <strong>handle<\/strong> generated by the Graph API Resumable Upload API. It takes two calls, and the first one uses your Meta <strong>App ID<\/strong>, not the WABA ID.<\/p>\n\n\n\n<p>Step 1, start an upload session:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -X POST \"https:\/\/graph.facebook.com\/v26.0\/&lt;APP_ID&gt;\/uploads?file_name=banner.jpg&amp;file_length=184320&amp;file_type=image\/jpeg\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\"<\/code><\/pre>\n\n\n\n<p>The response is <code>{\"id\": \"upload:&lt;UPLOAD_SESSION_ID&gt;\"}<\/code>. Step 2, upload the binary file to that session:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -X POST \"https:\/\/graph.facebook.com\/v26.0\/upload:&lt;UPLOAD_SESSION_ID&gt;\" \\\n  -H \"Authorization: OAuth &lt;TOKEN&gt;\" \\\n  -H \"file_offset: 0\" \\\n  --data-binary @banner.jpg<\/code><\/pre>\n\n\n\n<p>Note the <code>Authorization: OAuth<\/code> header, exactly as in the docs. The response is <code>{\"h\": \"4::aW...\"}<\/code>, and that value goes in <code>example.header_handle<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"type\": \"HEADER\",\n  \"format\": \"IMAGE\",\n  \"example\": { \"header_handle\": [\"4::aW...\"] }\n}<\/code><\/pre>\n\n\n\n<p>The Resumable Upload API accepts <code>application\/pdf<\/code>, <code>image\/jpeg<\/code>, <code>image\/jpg<\/code>, <code>image\/png<\/code> and <code>video\/mp4<\/code>. Use <code>IMAGE<\/code>, <code>VIDEO<\/code> or <code>DOCUMENT<\/code> for <code>format<\/code> (<code>GIF<\/code> exists only for the Marketing Messages API). The sample file is only for review: at send time, you pass the real media for each recipient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Example 4: marketing template with buttons<\/h2>\n\n\n\n<p>Buttons live in a single <code>BUTTONS<\/code> component. This campaign template combines a URL with a dynamic suffix, a coupon code and a quick reply:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"name\": \"black_friday_coupon\",\n  \"language\": \"en_US\",\n  \"category\": \"MARKETING\",\n  \"components\": [\n    {\n      \"type\": \"BODY\",\n      \"text\": \"{{1}}, Black Friday is here: {{2}} off sitewide until Sunday.\",\n      \"example\": { \"body_text\": [[\"Marina\", \"20%\"]] }\n    },\n    {\n      \"type\": \"BUTTONS\",\n      \"buttons\": [\n        {\n          \"type\": \"URL\",\n          \"text\": \"Shop deals\",\n          \"url\": \"https:\/\/shop.example.com\/deals?c={{1}}\",\n          \"example\": [\"bf2026\"]\n        },\n        { \"type\": \"COPY_CODE\", \"example\": \"BF20\" },\n        { \"type\": \"QUICK_REPLY\", \"text\": \"Stop promotions\" }\n      ]\n    }\n  ]\n}<\/code><\/pre>\n\n\n\n<p>The URL takes one variable, always at the end. The URL sample is an array; the <code>COPY_CODE<\/code> sample is a string. When quick replies are mixed with other button types, they must be grouped together (all before or all after the others), or the API returns an error. Cards with an image and button per card use a different format, the carousel template.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Component limits<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Element<\/th><th>Limit<\/th><\/tr><\/thead><tbody><tr><td>Header text<\/td><td>60 characters, 1 variable<\/td><\/tr><tr><td>Body<\/td><td>1,024 characters<\/td><\/tr><tr><td>Footer<\/td><td>60 characters<\/td><\/tr><tr><td>Button label (URL, phone, quick reply)<\/td><td>25 characters<\/td><\/tr><tr><td>Coupon code sample<\/td><td>20 characters<\/td><\/tr><tr><td>Button URL<\/td><td>2,000 characters, 1 variable<\/td><\/tr><tr><td>Total buttons<\/td><td>10<\/td><\/tr><tr><td>URL buttons<\/td><td>2<\/td><\/tr><tr><td>Phone number buttons<\/td><td>1<\/td><\/tr><tr><td>Copy code buttons<\/td><td>1<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The docs also warn that templates with 4 or more buttons, or with a quick reply combined with another button type, are not viewable on WhatsApp desktop. Don&#8217;t use Markdown in text headers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Category: what happens if you get it wrong<\/h2>\n\n\n\n<p>The category you declare is not the final word. Since April 9, 2025, if you submit a template as <code>UTILITY<\/code> and Meta decides it is marketing, it is <strong>approved as <code>MARKETING<\/code><\/strong>, with no need for the old <code>allow_category_change: true<\/code> (that behavior is now the default). In other cases, the template comes back <code>REJECTED<\/code> with reason <code>INCORRECT_CATEGORY<\/code>.<\/p>\n\n\n\n<p>Meta also reviews templates that are already approved. Before changing the category of one, it fires a <code>template_category_update<\/code> webhook with a <code>correct_category<\/code> field; after the change, the event carries <code>previous_category<\/code> and <code>new_category<\/code>. For utility-to-marketing changes, the docs describe a 1-day advance notice, which is not given to businesses already warned for misuse. You have 60 days to appeal in Business Support Home.<\/p>\n\n\n\n<p>The price gap makes this worth getting right. In Brazil, since October 1, 2026, a marketing message costs R$ 0.3217 (Brazilian reais) versus R$ 0.0350 for utility. Read <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-template-categories\/\">how Meta categorizes templates<\/a> before automating template creation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Check template status<\/h2>\n\n\n\n<p>For one template, request the fields you need:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl \"https:\/\/graph.facebook.com\/v26.0\/&lt;TEMPLATE_ID&gt;?fields=name,language,status,category,rejected_reason,quality_score\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\"<\/code><\/pre>\n\n\n\n<p>To list templates, use <code>GET \/&lt;WABA_ID&gt;\/message_templates<\/code>. Without <code>fields<\/code>, the response includes <code>name<\/code>, <code>parameter_format<\/code>, <code>components<\/code>, <code>language<\/code>, <code>status<\/code>, <code>category<\/code>, <code>sub_category<\/code> and <code>id<\/code>. You can filter and paginate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl \"https:\/\/graph.facebook.com\/v26.0\/&lt;WABA_ID&gt;\/message_templates?fields=name,status,category&amp;status=rejected&amp;limit=50\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\"<\/code><\/pre>\n\n\n\n<p>The response has <code>data<\/code> and <code>paging<\/code>, with <code>before<\/code> and <code>after<\/code> cursors and a <code>next<\/code> URL. Follow <code>next<\/code> until it is gone.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get status changes by webhook<\/h2>\n\n\n\n<p>Polling works, but the right way is to subscribe your app&#8217;s webhook to the <code>message_template_status_update<\/code> field. The event arrives with <code>field: \"message_template_status_update\"<\/code> and, inside <code>value<\/code>, the <code>event<\/code>, <code>message_template_id<\/code>, <code>message_template_name<\/code>, <code>message_template_language<\/code>, <code>message_template_category<\/code> and <code>reason<\/code> fields. An example with illustrative values:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-json\">{\n  \"object\": \"whatsapp_business_account\",\n  \"entry\": [{\n    \"id\": \"&lt;WABA_ID&gt;\",\n    \"time\": 1761730000,\n    \"changes\": [{\n      \"field\": \"message_template_status_update\",\n      \"value\": {\n        \"event\": \"REJECTED\",\n        \"message_template_id\": 1252715608684590,\n        \"message_template_name\": \"black_friday_coupon\",\n        \"message_template_language\": \"en_US\",\n        \"message_template_category\": \"MARKETING\",\n        \"reason\": \"INVALID_FORMAT\",\n        \"rejection_info\": {\n          \"reason\": \"...\",\n          \"recommendation\": \"...\"\n        }\n      }\n    }]\n  }]\n}<\/code><\/pre>\n\n\n\n<p>The <code>event<\/code> values worth automating:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th><code>event<\/code><\/th><th>What to do<\/th><\/tr><\/thead><tbody><tr><td><code>APPROVED<\/code><\/td><td>Enable the template in your system<\/td><\/tr><tr><td><code>REJECTED<\/code><\/td><td>Read <code>reason<\/code> (and <code>rejection_info<\/code> for <code>INVALID_FORMAT<\/code>), fix it and edit<\/td><\/tr><tr><td><code>PAUSED<\/code> \/ <code>FLAGGED<\/code><\/td><td>Alert the team; the template has poor quality<\/td><\/tr><tr><td><code>DISABLED<\/code><\/td><td>Stop using it; <code>disable_info<\/code> carries the date<\/td><\/tr><tr><td><code>REINSTATED<\/code> \/ <code>UNARCHIVED<\/code><\/td><td>Enable it again<\/td><\/tr><tr><td><code>ARCHIVED<\/code><\/td><td>Archived for inactivity; deleted after 28 days unless unarchived<\/td><\/tr><tr><td><code>LIMIT_EXCEEDED<\/code><\/td><td>The account has hit its template limit<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><code>reason<\/code> values include <code>INCORRECT_CATEGORY<\/code>, <code>TAG_CONTENT_MISMATCH<\/code>, <code>INVALID_FORMAT<\/code>, <code>PROMOTIONAL<\/code>, <code>ABUSIVE_CONTENT<\/code> and <code>SCAM<\/code>. The usual fixes are in <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-template-rejected\/\">WhatsApp template rejected: common reasons and fixes<\/a>, and pauses are covered in <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-template-paused\/\">paused or disabled templates<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Edit a template<\/h2>\n\n\n\n<p>Editing is a <code>POST<\/code> to the template ID, and the <code>components<\/code> array you send <strong>replaces all components<\/strong>. You cannot edit one component on its own, so send the whole template.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -X POST \"https:\/\/graph.facebook.com\/v26.0\/&lt;TEMPLATE_ID&gt;\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"components\": [\n      {\n        \"type\": \"BODY\",\n        \"text\": \"Hi {{1}}, your order is on its way and arrives by {{2}}. Tracking: {{3}}.\",\n        \"example\": { \"body_text\": [[\"Ana\", \"Nov 5\", \"BR123456789\"]] }\n      }\n    ]\n  }'<\/code><\/pre>\n\n\n\n<p>The response is <code>{\"success\": true}<\/code>. The rules from Meta&#8217;s template management page:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You can edit <code>APPROVED<\/code>, <code>REJECTED<\/code> or <code>PAUSED<\/code> templates (the API reference mentions approved and rejected).<\/li>\n\n\n<li>Editable fields are category, components and time-to-live, but <strong>the category of an approved template cannot be edited<\/strong>.<\/li>\n\n\n<li>An approved template can be edited <strong>at most once every 24 hours and up to 10 times in 30 days<\/strong>. Rejected and paused templates have no such limit.<\/li>\n\n\n<li>After an edit, an approved or paused template goes through review again; if it passes, it stays approved.<\/li>\n\n<\/ul>\n\n\n\n<p>To change the name, language or category of an approved template, create a new template.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Delete templates<\/h2>\n\n\n\n<p>Deletion uses the list endpoint with <code>DELETE<\/code>. There are three options:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\"># Deletes ALL languages with this name\ncurl -X DELETE \"https:\/\/graph.facebook.com\/v26.0\/&lt;WABA_ID&gt;\/message_templates?name=order_shipped\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\"\n\n# Deletes only the template with this ID (one language)\ncurl -X DELETE \"https:\/\/graph.facebook.com\/v26.0\/&lt;WABA_ID&gt;\/message_templates?hsm_id=1252715608684590&amp;name=order_shipped\" \\\n  -H \"Authorization: Bearer &lt;TOKEN&gt;\"<\/code><\/pre>\n\n\n\n<p>The third is <code>hsm_ids<\/code>, a JSON array of up to 100 IDs. It cannot be combined with <code>name<\/code> or <code>hsm_id<\/code>, and a single invalid ID makes the whole request fail.<\/p>\n\n\n\n<p>What happens next:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Messages already sent but not yet delivered keep the template as <code>PENDING_DELETION<\/code>, and WhatsApp keeps trying to deliver them for 30 days.<\/li>\n\n\n<li>The name of a deleted approved template <strong>cannot be reused for 30 days<\/strong>.<\/li>\n\n\n<li>Disabled templates cannot be deleted.<\/li>\n\n\n<li>Deleting a name that does not exist returns an error.<\/li>\n\n<\/ul>\n\n\n\n<p>Before running a cleanup script, remember that Meta archives templates unused for 12 months and schedules their deletion 28 days later. Sometimes you don&#8217;t need to clean up at all.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common automation mistakes<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Missing sample<\/strong>: every variable needs one, including the button URL variable.<\/li>\n\n\n<li><strong><code>header_text<\/code> as an array of arrays<\/strong>, or <code>body_text<\/code> as a flat array: the shapes differ.<\/li>\n\n\n<li><strong>A URL in <code>header_handle<\/code><\/strong>: media samples need a Resumable Upload API handle.<\/li>\n\n\n<li><strong>WABA ID in the upload call<\/strong>: the upload session is opened on the App ID.<\/li>\n\n\n<li><strong>Token without <code>whatsapp_business_management<\/code><\/strong>: it may list or create, but deletion fails with code 200.<\/li>\n\n\n<li><strong>More than 100 creations per hour<\/strong> on one messaging account.<\/li>\n\n\n<li><strong>Recreating a deleted approved template with the same name right away<\/strong>: wait 30 days or pick another name.<\/li>\n\n\n<li><strong>Editing an approved template twice in one day<\/strong>: the second edit hits the 24-hour limit.<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">How to do it with Vectalk<\/h2>\n\n\n\n<p>Vectalk is a proxy for the <a href=\"https:\/\/vectalk.com.br\/blog\/en\/official-whatsapp-api\/\">official WhatsApp API<\/a>, and the same operations are available on its API with an instance token (the WABA ID is resolved from the token, so it is not part of the URL):<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Operation<\/th><th>Vectalk route<\/th><\/tr><\/thead><tbody><tr><td>List or filter by name<\/td><td><code>GET https:\/\/apis.vectalk.com.br\/api\/templates?name=order_shipped<\/code><\/td><\/tr><tr><td>Create<\/td><td><code>POST https:\/\/apis.vectalk.com.br\/api\/templates<\/code><\/td><\/tr><tr><td>Edit (only <code>APPROVED<\/code> or <code>REJECTED<\/code>)<\/td><td><code>POST https:\/\/apis.vectalk.com.br\/api\/templates\/{templateId}<\/code><\/td><\/tr><tr><td>Delete by name<\/td><td><code>DELETE https:\/\/apis.vectalk.com.br\/api\/templates?name=order_shipped<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The create body uses Meta&#8217;s fields (<code>name<\/code>, <code>language<\/code>, <code>category<\/code>, <code>components<\/code>), and the response returns <code>id<\/code>, <code>status: \"PENDING\"<\/code> and <code>category<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">curl -X POST https:\/\/apis.vectalk.com.br\/api\/templates \\\n  -H \"Authorization: Bearer &lt;INSTANCE_TOKEN&gt;\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"name\": \"order_shipped\",\n    \"language\": \"en_US\",\n    \"category\": \"UTILITY\",\n    \"components\": [\n      {\n        \"type\": \"BODY\",\n        \"text\": \"Hi {{1}}, your order is on its way and should arrive by {{2}}.\",\n        \"example\": { \"body_text\": [[\"Ana\", \"Nov 5\"]] }\n      }\n    ]\n  }'<\/code><\/pre>\n\n\n\n<p>Organization tokens cannot access templates, so create an instance-bound token under <strong>Settings \u2192 API Tokens<\/strong>. If you would rather not write JSON, the dashboard has a templates section with a Template Library. Every route is documented in the <a href=\"https:\/\/docs.vectalk.com.br\/api-reference\/templates\/create\">Vectalk templates reference<\/a>, and you can sign up at <a href=\"https:\/\/apps.vectalk.com.br\/register\">apps.vectalk.com.br\/register<\/a>. For copy ideas by industry, see our <a href=\"https:\/\/vectalk.com.br\/blog\/en\/whatsapp-template-examples\/\">60 WhatsApp template examples<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">How long does Meta take to approve a template created via the API?<\/h3>\n\n\n\n<p>The template management page does not set a single deadline. The template starts as <code>PENDING<\/code>, and you learn the result from the <code>message_template_status_update<\/code> webhook or by calling <code>GET \/&lt;TEMPLATE_ID&gt;?fields=status<\/code>. Don&#8217;t build a flow that depends on instant approval.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Should I use the WABA ID or the messaging account ID?<\/h3>\n\n\n\n<p>They are the same number. In the September 23, 2026 split, messaging accounts inherited the WABA ID, and the template docs still use <code>\/&lt;WABA_ID&gt;\/message_templates<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I change the category of an approved template?<\/h3>\n\n\n\n<p>Not by editing: the docs say the category of an approved template cannot be edited. Create a new template with the right category. Meta itself can recategorize an approved template, and it tells you through the <code>template_category_update<\/code> webhook.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I create the same template in several languages?<\/h3>\n\n\n\n<p>Send one <code>POST<\/code> per language with the same <code>name<\/code> and a different <code>language<\/code>. Each one gets its own <code>id<\/code>. To delete a single language, use <code>name<\/code> + <code>hsm_id<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does the customer see the sample image?<\/h3>\n\n\n\n<p>No. The sample handle is only for Meta&#8217;s review. At send time, you pass the actual media in the <code>header<\/code> component, by link or media ID.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Official sources checked on October 29, 2026:<\/strong> <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/templates\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">Templates overview (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/templates\/template-management\" target=\"_blank\" rel=\"noreferrer noopener\">Template management (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/reference\/whatsapp-business-account\/message-template-api\" target=\"_blank\" rel=\"noreferrer noopener\">Message Templates API (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/templates\/components\" target=\"_blank\" rel=\"noreferrer noopener\">Template components (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/templates\/template-categorization\" target=\"_blank\" rel=\"noreferrer noopener\">Template categorization (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/reference\/message_template_status_update\" target=\"_blank\" rel=\"noreferrer noopener\">message_template_status_update webhook (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/docs\/graph-api\/guides\/upload\" target=\"_blank\" rel=\"noreferrer noopener\">Resumable Upload API (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/account-model-evolution\/\" target=\"_blank\" rel=\"noreferrer noopener\">WhatsApp Business account updates (Meta)<\/a>, <a href=\"https:\/\/docs.vectalk.com.br\/api-reference\/templates\/create\">Vectalk templates API<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>From POST message_templates to deleting by hsm_id: complete payloads to create, check, edit and delete WhatsApp Business API templates without opening WhatsApp Manager.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-748","post","type-post","status-publish","format-standard","hentry","category-blog"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Create WhatsApp Templates via API: Full Guide | Vectalk<\/title>\n<meta name=\"description\" content=\"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create WhatsApp Templates via API: Full Guide | Vectalk\" \/>\n<meta property=\"og:description\" content=\"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog Vectalk\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-29T13:22:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-29T13:22:28+00:00\" \/>\n<meta name=\"author\" content=\"wanderleyfcunha\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"wanderleyfcunha\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/\"},\"author\":{\"name\":\"wanderleyfcunha\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"headline\":\"How to create, edit and delete WhatsApp message templates via the API\",\"datePublished\":\"2026-10-29T13:22:20+00:00\",\"dateModified\":\"2026-10-29T13:22:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/\"},\"wordCount\":1909,\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/\",\"name\":\"Create WhatsApp Templates via API: Full Guide | Vectalk\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\"},\"datePublished\":\"2026-10-29T13:22:20+00:00\",\"dateModified\":\"2026-10-29T13:22:28+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"description\":\"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/en\\\/create-whatsapp-template-api\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to create, edit and delete WhatsApp message templates via the API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\",\"name\":\"Blog Vectalk\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\",\"name\":\"wanderleyfcunha\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"caption\":\"wanderleyfcunha\"},\"sameAs\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Create WhatsApp Templates via API: Full Guide | Vectalk","description":"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/","og_locale":"en_US","og_type":"article","og_title":"Create WhatsApp Templates via API: Full Guide | Vectalk","og_description":"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.","og_url":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/","og_site_name":"Blog Vectalk","article_published_time":"2026-10-29T13:22:20+00:00","article_modified_time":"2026-10-29T13:22:28+00:00","author":"wanderleyfcunha","twitter_card":"summary_large_image","twitter_misc":{"Written by":"wanderleyfcunha","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/#article","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/"},"author":{"name":"wanderleyfcunha","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"headline":"How to create, edit and delete WhatsApp message templates via the API","datePublished":"2026-10-29T13:22:20+00:00","dateModified":"2026-10-29T13:22:28+00:00","mainEntityOfPage":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/"},"wordCount":1909,"articleSection":["Blog"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/","url":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/","name":"Create WhatsApp Templates via API: Full Guide | Vectalk","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/#website"},"datePublished":"2026-10-29T13:22:20+00:00","dateModified":"2026-10-29T13:22:28+00:00","author":{"@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"description":"Create WhatsApp templates via the API: message_templates payloads, required examples, categories, status webhooks, edit limits and deletion by hsm_id.","breadcrumb":{"@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/vectalk.com.br\/blog\/en\/create-whatsapp-template-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/vectalk.com.br\/blog\/"},{"@type":"ListItem","position":2,"name":"How to create, edit and delete WhatsApp message templates via the API"}]},{"@type":"WebSite","@id":"https:\/\/vectalk.com.br\/blog\/#website","url":"https:\/\/vectalk.com.br\/blog\/","name":"Blog Vectalk","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vectalk.com.br\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b","name":"wanderleyfcunha","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","caption":"wanderleyfcunha"},"sameAs":["https:\/\/vectalk.com.br\/blog"]}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/comments?post=748"}],"version-history":[{"count":1,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/748\/revisions"}],"predecessor-version":[{"id":751,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/748\/revisions\/751"}],"wp:attachment":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/media?parent=748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/categories?post=748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/tags?post=748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}