← Blog

·

Como criar, editar e excluir templates pela API do WhatsApp

Atualizado em 29/10/2026

Para criar um template pela API do WhatsApp, você faz POST /<WABA_ID>/message_templates com name, language, category e o array components, incluindo um valor de exemplo para cada variável. A Meta responde com o id do template e o status PENDING; quando a revisão termina, chega o webhook message_template_status_update. Para editar, use POST /<TEMPLATE_ID>; para excluir, DELETE /<WABA_ID>/message_templates?name=..., com hsm_id se quiser apagar um idioma só.

Este guia mostra os payloads de cada operação, os limites de edição e exclusão e os erros que mais travam quem automatiza templates. O conceito de template e as regras de uso estão no guia templates da API do WhatsApp; aqui o foco é o ciclo de vida pela API.

Onde os templates vivem depois de 23/09/2026

Desde 23 de setembro de 2026, a Meta separa a antiga WABA em conta do WhatsApp (o número e o perfil) e conta de mensagens (templates, cobrança e webhooks). A documentação de templates já fala em “Messaging account”: os templates são ativos da conta de mensagens, e cada conta de mensagens tem seus próprios templates.

Na prática, nada muda no código. As contas de mensagens herdaram o ID da WABA, e os exemplos da documentação continuam usando /<WABA_ID>/message_templates. Ou seja: o mesmo ID que você já usava serve para criar, listar e excluir. A consequência que importa é outra: templates não são compartilhados entre contas de mensagens. Se o mesmo número for usado por dois provedores, cada um tem a sua conta de mensagens e precisa ter os templates criados nela. A estrutura completa está em conta do WhatsApp x conta de mensagens.

Antes de começar

  • ID da conta: o WABA ID (ou ID da conta de mensagens, que é o mesmo). Se não sabe onde ele fica, veja onde encontrar o Phone Number ID e o WABA ID.
  • Token: um token com a permissão whatsapp_business_management. Só com whatsapp_business_messaging, a exclusão devolve erro de código 200, segundo a documentação. Para produção, use um token permanente de usuário do sistema.
  • Versão da Graph API: os exemplos abaixo usam v26.0. Troque pela versão que você usa.
  • Limites da conta: até 100 templates criados por hora por conta de mensagens. O total é de 250 templates se o portfólio não for verificado e de até 6.000 se o portfólio for verificado e tiver nome de exibição aprovado em pelo menos uma conta do WhatsApp.

Quer testar enquanto lê? Crie sua conta na Vectalk e envie a primeira mensagem pela API oficial. Criar conta grátis →

Os campos da criação

CampoObrigatórioO que é
nameSimLetras minúsculas, números e sublinhado; até 512 caracteres
languageSimCódigo do idioma, como pt_BR, en_US ou es_MX
categorySimMARKETING, UTILITY ou AUTHENTICATION
componentsNa prática, simHEADER, BODY, FOOTER e BUTTONS
parameter_formatNãoPOSITIONAL ({{1}}) ou NAMED ({{nome}})
message_send_ttl_secondsNãoTempo de vida da mensagem enviada
library_template_nameNãoCria a partir de um modelo da biblioteca da Meta

O nome não é único: você pode ter pedido_enviado em pt_BR e em es_MX, e cada combinação nome + idioma é um template com ID próprio. A resposta da criação traz três campos:

{
  "id": "1252715608684590",
  "status": "PENDING",
  "category": "UTILITY"
}

Guarde o id. Ele é a chave para consultar, editar e excluir só aquele idioma.

Exemplo 1: utilidade com variáveis posicionais

Toda variável precisa de um valor de exemplo. Sem isso, a criação é rejeitada. No corpo, os exemplos vão em example.body_text, um array dentro de outro array, na ordem das variáveis.

curl -X POST "https://graph.facebook.com/v26.0/<WABA_ID>/message_templates" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "pedido_enviado",
    "language": "pt_BR",
    "category": "UTILITY",
    "components": [
      {
        "type": "HEADER",
        "format": "TEXT",
        "text": "Pedido {{1}} enviado",
        "example": { "header_text": ["#4821"] }
      },
      {
        "type": "BODY",
        "text": "Olá, {{1}}! Seu pedido saiu para entrega e deve chegar até {{2}}. Código de rastreio: {{3}}.",
        "example": { "body_text": [["Ana", "05/11", "BR123456789"]] }
      },
      {
        "type": "FOOTER",
        "text": "Responda esta mensagem se precisar de ajuda"
      }
    ]
  }'

O cabeçalho de texto aceita uma variável só. O exemplo do cabeçalho vai em header_text (array simples), e o do corpo em body_text (array de arrays). Trocar um pelo outro é um erro frequente.

Exemplo 2: variáveis nomeadas

Com parameter_format: "NAMED", as variáveis ganham nome em vez de número, e os exemplos passam para body_text_named_params (no cabeçalho, header_text_named_params), cada um com param_name e example:

{
  "name": "boleto_disponivel",
  "language": "pt_BR",
  "category": "UTILITY",
  "parameter_format": "NAMED",
  "components": [
    {
      "type": "BODY",
      "text": "Oi, {{primeiro_nome}}. O boleto da fatura {{numero_fatura}} vence em {{vencimento}}.",
      "example": {
        "body_text_named_params": [
          { "param_name": "primeiro_nome", "example": "Carlos" },
          { "param_name": "numero_fatura", "example": "2026-10-0193" },
          { "param_name": "vencimento", "example": "10/11/2026" }
        ]
      }
    }
  ]
}

Variáveis nomeadas deixam o envio mais legível e evitam trocar {{2}} por {{3}} quando alguém reescreve o texto. Nos exemplos da Meta, os nomes usam letras minúsculas e sublinhado; siga o mesmo padrão. Lembre que a escolha vale para o envio: um template NAMED é enviado com parameter_name em cada parâmetro, como mostramos em como enviar template pela API.

Um lembrete de fatura do próprio cliente, como o do exemplo, é utilidade. Cobrança de dívida de terceiros é proibida pela Política de Mensagens Comerciais, em qualquer categoria.

Exemplo 3: cabeçalho com imagem, vídeo ou documento

Para cabeçalho de mídia, o exemplo não é uma URL: é um handle gerado pela Resumable Upload API da Graph API. São duas chamadas, e a primeira usa o App ID do seu app da Meta, não o WABA ID.

Passo 1, abrir a sessão de upload:

curl -X POST "https://graph.facebook.com/v26.0/<APP_ID>/uploads?file_name=banner.jpg&file_length=184320&file_type=image/jpeg" \
  -H "Authorization: Bearer <TOKEN>"

A resposta traz {"id": "upload:<UPLOAD_SESSION_ID>"}. Passo 2, enviar o arquivo binário para essa sessão:

curl -X POST "https://graph.facebook.com/v26.0/upload:<UPLOAD_SESSION_ID>" \
  -H "Authorization: OAuth <TOKEN>" \
  -H "file_offset: 0" \
  --data-binary @banner.jpg

Repare no cabeçalho Authorization: OAuth, como está na documentação. A resposta traz {"h": "4::aW..."}. Esse valor vai em example.header_handle:

{
  "type": "HEADER",
  "format": "IMAGE",
  "example": { "header_handle": ["4::aW..."] }
}

Os tipos aceitos pela Resumable Upload API são application/pdf, image/jpeg, image/jpg, image/png e video/mp4. Para format use IMAGE, VIDEO ou DOCUMENT (o formato GIF existe só para a Marketing Messages API). O arquivo de exemplo é só para a revisão: no envio, você manda a mídia real de cada destinatário.

Exemplo 4: marketing com botões

Os botões ficam num único componente BUTTONS. Este template de campanha combina URL com sufixo dinâmico, código de cupom e resposta rápida:

{
  "name": "cupom_black_friday",
  "language": "pt_BR",
  "category": "MARKETING",
  "components": [
    {
      "type": "BODY",
      "text": "{{1}}, sua Black Friday começou: {{2}} de desconto em todo o site até domingo.",
      "example": { "body_text": [["Marina", "20%"]] }
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "URL",
          "text": "Ver ofertas",
          "url": "https://loja.exemplo.com.br/ofertas?c={{1}}",
          "example": ["bf2026"]
        },
        { "type": "COPY_CODE", "example": "BF20" },
        { "type": "QUICK_REPLY", "text": "Parar promoções" }
      ]
    }
  ]
}

A URL aceita uma variável, sempre no fim. O exemplo de URL é um array; o de COPY_CODE é uma string. Botões de resposta rápida, quando misturados com outros tipos, precisam ficar agrupados (todos antes ou todos depois dos demais); fora dessa ordem, a API devolve erro. Para cards com imagem e botão, o formato é outro: o template carrossel.

Limites dos componentes

ElementoLimite
Texto do cabeçalho60 caracteres, 1 variável
Corpo1.024 caracteres
Rodapé60 caracteres
Texto de botão (URL, telefone, resposta rápida)25 caracteres
Exemplo de código de cupom20 caracteres
URL do botão2.000 caracteres, 1 variável
Botões no total10
Botões de URL2
Botões de telefone1
Botões de copiar código1

A documentação avisa ainda que templates com 4 ou mais botões, ou com resposta rápida junto de outro tipo de botão, não aparecem no WhatsApp para desktop. Não use Markdown no cabeçalho de texto.

Categoria: o que acontece se você errar

A categoria declarada não é a palavra final. Desde 9 de abril de 2025, se você envia um template como UTILITY e a Meta conclui que ele é de marketing, ele é aprovado como MARKETING, sem precisar do antigo allow_category_change: true (esse comportamento passou a ser o padrão). Em outros casos, o template volta REJECTED com motivo INCORRECT_CATEGORY.

A Meta também revisa templates já aprovados. Quando vai mudar a categoria de um, ela dispara o webhook template_category_update com o campo correct_category; depois da mudança, o evento traz previous_category e new_category. Para mudanças de utilidade para marketing, a documentação fala em aviso com 1 dia de antecedência, que não é dado para empresas já advertidas por uso indevido. Há 60 dias para contestar no Business Support Home.

Como a diferença de preço é grande (no Brasil, desde 1º/10/2026, R$ 0,3217 por marketing e R$ 0,0350 por utilidade), vale ler como a Meta classifica templates antes de automatizar a criação.

Consultar o status

Para um template específico, peça os campos que interessam:

curl "https://graph.facebook.com/v26.0/<TEMPLATE_ID>?fields=name,language,status,category,rejected_reason,quality_score" \
  -H "Authorization: Bearer <TOKEN>"

Para listar, use GET /<WABA_ID>/message_templates. Sem fields, a resposta traz name, parameter_format, components, language, status, category, sub_category e id. Dá para filtrar e paginar:

curl "https://graph.facebook.com/v26.0/<WABA_ID>/message_templates?fields=name,status,category&status=rejected&limit=50" \
  -H "Authorization: Bearer <TOKEN>"

A resposta vem com data e paging, que traz os cursores before e after e a URL next. Siga next até ele não existir mais.

Receber mudanças de status por webhook

Consultar em loop funciona, mas o certo é assinar o campo message_template_status_update no webhook do app. O evento chega com field: "message_template_status_update" e, em value, os campos event, message_template_id, message_template_name, message_template_language, message_template_category e reason. Um exemplo com valores ilustrativos:

{
  "object": "whatsapp_business_account",
  "entry": [{
    "id": "<WABA_ID>",
    "time": 1761730000,
    "changes": [{
      "field": "message_template_status_update",
      "value": {
        "event": "REJECTED",
        "message_template_id": 1252715608684590,
        "message_template_name": "cupom_black_friday",
        "message_template_language": "pt_BR",
        "message_template_category": "MARKETING",
        "reason": "INVALID_FORMAT",
        "rejection_info": {
          "reason": "...",
          "recommendation": "..."
        }
      }
    }]
  }]
}

Os valores de event mais úteis para automatizar:

eventO que fazer
APPROVEDLiberar o template no seu sistema
REJECTEDLer reason (e rejection_info, nos casos de INVALID_FORMAT), corrigir e editar
PAUSED / FLAGGEDAvisar o time; o template está com qualidade ruim
DISABLEDParar de usar; disable_info traz a data
REINSTATED / UNARCHIVEDVoltar a liberar
ARCHIVEDTemplate parado por inatividade; será excluído em 28 dias se não for desarquivado
LIMIT_EXCEEDEDA conta atingiu o limite de templates

Os motivos de reason incluem INCORRECT_CATEGORY, TAG_CONTENT_MISMATCH, INVALID_FORMAT, PROMOTIONAL, ABUSIVE_CONTENT e SCAM. As correções mais comuns estão em template reprovado: motivos e como corrigir, e o caso de pausa em template pausado ou desativado.

Editar um template

A edição é um POST no ID do template, e o array components enviado substitui todos os componentes. Não existe edição de um componente isolado: mande o template inteiro.

curl -X POST "https://graph.facebook.com/v26.0/<TEMPLATE_ID>" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "components": [
      {
        "type": "BODY",
        "text": "Olá, {{1}}! Seu pedido saiu para entrega e chega até {{2}}. Rastreio: {{3}}.",
        "example": { "body_text": [["Ana", "05/11", "BR123456789"]] }
      }
    ]
  }'

A resposta é {"success": true}. As regras da página de gerenciamento de templates:

  • Dá para editar templates APPROVED, REJECTED ou PAUSED (a referência da API cita aprovados e rejeitados).
  • Os campos editáveis são categoria, componentes e tempo de vida, mas a categoria de um template aprovado não pode ser editada.
  • Um template aprovado pode ser editado no máximo uma vez a cada 24 horas e até 10 vezes em 30 dias. Rejeitados e pausados não têm esse limite.
  • Depois de editado, um template aprovado ou pausado passa de novo pela revisão; se passar, continua aprovado.

Se você precisa mudar o nome, o idioma ou a categoria de um template aprovado, o caminho é criar um template novo.

Excluir templates

A exclusão usa o endpoint de listagem com DELETE. Há três formas:

# Apaga TODOS os idiomas com esse nome
curl -X DELETE "https://graph.facebook.com/v26.0/<WABA_ID>/message_templates?name=pedido_enviado" \
  -H "Authorization: Bearer <TOKEN>"

# Apaga só o template com esse ID (um idioma)
curl -X DELETE "https://graph.facebook.com/v26.0/<WABA_ID>/message_templates?hsm_id=1252715608684590&name=pedido_enviado" \
  -H "Authorization: Bearer <TOKEN>"

A terceira é hsm_ids, com um array JSON de até 100 IDs. Ela não pode ser combinada com name nem com hsm_id, e um único ID inválido faz a requisição inteira falhar.

O que acontece depois:

  • Mensagens já enviadas e ainda não entregues ficam com o template em PENDING_DELETION, e o WhatsApp tenta entregá-las por 30 dias.
  • O nome de um template aprovado excluído não pode ser reutilizado por 30 dias.
  • Templates desativados (DISABLED) não podem ser excluídos.
  • Excluir um nome que não existe devolve erro.

Antes de rodar uma limpeza, lembre que a própria Meta arquiva templates sem uso por 12 meses e agenda a exclusão para 28 dias depois. Às vezes a limpeza manual nem é necessária.

Erros comuns na automação

  1. Exemplo faltando: cada variável precisa de exemplo, inclusive a da URL do botão.
  2. header_text com array de arrays ou body_text como array simples: os formatos são diferentes.
  3. URL no header_handle: o exemplo de mídia é o handle da Resumable Upload API.
  4. WABA ID no upload: a sessão de upload é aberta no App ID.
  5. Token sem whatsapp_business_management: lista ou cria, mas falha na exclusão com código 200.
  6. Mais de 100 criações por hora numa conta de mensagens.
  7. Recriar com o mesmo nome logo após excluir um aprovado: espere 30 dias ou use outro nome.
  8. Editar um aprovado duas vezes no mesmo dia: a segunda edição esbarra no limite de 24 horas.

Como fazer isso com a Vectalk

A Vectalk é um proxy da API oficial do WhatsApp, e as mesmas operações estão na API dela, com token de instância (o WABA ID é resolvido pelo token, então não vai na URL):

OperaçãoRota na Vectalk
Listar ou filtrar por nomeGET https://apis.vectalk.com.br/api/templates?name=pedido_enviado
CriarPOST https://apis.vectalk.com.br/api/templates
Editar (só APPROVED ou REJECTED)POST https://apis.vectalk.com.br/api/templates/{templateId}
Excluir por nomeDELETE https://apis.vectalk.com.br/api/templates?name=pedido_enviado

O corpo da criação usa os mesmos campos da Meta (name, language, category, components), e a resposta traz id, status: "PENDING" e category:

curl -X POST https://apis.vectalk.com.br/api/templates \
  -H "Authorization: Bearer <TOKEN_DE_INSTANCIA>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "pedido_enviado",
    "language": "pt_BR",
    "category": "UTILITY",
    "components": [
      {
        "type": "BODY",
        "text": "Olá, {{1}}! Seu pedido saiu para entrega e deve chegar até {{2}}.",
        "example": { "body_text": [["Ana", "05/11"]] }
      }
    ]
  }'

Tokens de organização não acessam templates; crie um token vinculado à instância em Configurações → API Tokens. Se preferir não escrever JSON, o painel tem a seção de templates com a Biblioteca de Modelos. Os detalhes de cada rota estão na documentação de templates da Vectalk, e a conta é criada em apps.vectalk.com.br/register. Para ideias de texto por setor, veja os 60 modelos de template.

Perguntas frequentes

Quanto tempo a Meta leva para aprovar um template criado pela API?

A Meta não fixa um prazo único na página de gerenciamento. O template nasce PENDING, e você fica sabendo do resultado pelo webhook message_template_status_update ou consultando GET /<TEMPLATE_ID>?fields=status. Não monte um fluxo que dependa de aprovação imediata.

Devo usar o WABA ID ou o ID da conta de mensagens?

São o mesmo número. Na separação de 23/09/2026, as contas de mensagens herdaram o ID da WABA, e a documentação de templates continua usando /<WABA_ID>/message_templates.

Posso mudar a categoria de um template aprovado?

Não pela edição: a documentação diz que a categoria de um template aprovado não pode ser editada. Crie outro template com a categoria certa. Quem pode mudar a categoria de um aprovado é a Meta, avisando pelo webhook template_category_update.

Como criar o mesmo template em vários idiomas?

Faça um POST por idioma com o mesmo name e language diferente. Cada um recebe um id. Para excluir só um idioma, use name + hsm_id.

O exemplo de imagem aparece para o cliente?

Não. O handle do exemplo serve à revisão da Meta. No envio, você passa a mídia de verdade no componente header, por link ou media id.


Fontes oficiais consultadas em 29/10/2026: Templates overview (Meta), Template management (Meta), Message Templates API (Meta), Template components (Meta), Template categorization (Meta), Webhook message_template_status_update (Meta), Resumable Upload API (Meta), Atualizações nas contas do WhatsApp Business (Meta), Templates na API da Vectalk.

Coloque o WhatsApp oficial da sua empresa para funcionar

Crie sua conta, conecte seu número à API oficial (dá para manter o app com coexistência) e comece a atender e enviar mensagens.