Templates (HSM)

8. Templates (HSM)#

Templates (HSM — Highly Structured Messages) são modelos de mensagem aprovados pela Meta. No canal oficial, um template aprovado é a única forma de iniciar uma conversa fora da janela de 24h (após uma mensagem do contato, você tem 24h para responder livremente; depois disso, só templates). Um template pode ter cabeçalho, corpo com variáveis {{1}}, rodapé e botões (resposta rápida, link, telefone).

Ciclo de vida: você cria o template → a Meta revisa (PENDING) → aprova (APPROVED) ou rejeita (REJECTED). Você acompanha a transição pelo webhook official.template_status. Só templates APPROVED podem ser enviados.

Listar templates#

text
GET /v1/instances/{instanceId}/templates

Retorna os templates da sua WABA com o status de aprovação.

json
{
  "templates": [
    {
      "id": "123456789",
      "name": "confirmacao_pedido",
      "language": "pt_BR",
      "status": "APPROVED",
      "category": "UTILITY",
      "components": [
        { "type": "HEADER", "format": "TEXT", "text": "Olá {{1}}" },
        { "type": "BODY", "text": "Seu pedido {{1}} foi confirmado e chega em {{2}} dias úteis." },
        { "type": "BUTTONS", "buttons": [{ "type": "QUICK_REPLY", "text": "Acompanhar pedido" }] }
      ]
    }
  ]
}

Criar template#

text
POST /v1/instances/{instanceId}/templates

O nome deve ser snake_case (minúsculas, números e _). A categoria é MARKETING, UTILITY ou AUTHENTICATION. O array components segue o formato da Graph API da Meta.

Componente Campos
HEADER (opcional) format: "TEXT", text. Com variável, exige example.header_text: ["exemplo"]. Aceita no máximo uma variável ({{1}}).
BODY (obrigatório) text com {{1}}, {{2}}… Com variáveis, exige example.body_text: [["ex1","ex2"]] (array aninhado).
FOOTER (opcional) text.
BUTTONS (opcional, até 3) buttons[]: QUICK_REPLY (text), URL (text, url), PHONE_NUMBER (text, phone_number).

Request

json
{
  "name": "confirmacao_pedido",
  "language": "pt_BR",
  "category": "UTILITY",
  "components": [
    { "type": "HEADER", "format": "TEXT", "text": "Olá {{1}}", "example": { "header_text": ["Ana"] } },
    { "type": "BODY", "text": "Seu pedido {{1}} foi confirmado e chega em {{2}} dias úteis.", "example": { "body_text": [["#12345", "3"]] } },
    { "type": "FOOTER", "text": "Responda SAIR para não receber mais" },
    { "type": "BUTTONS", "buttons": [{ "type": "QUICK_REPLY", "text": "Acompanhar pedido" }] }
  ]
}

Response 201 — o template entra em revisão (PENDING); acompanhe pelo webhook official.template_status.

Remover template#

text
DELETE /v1/instances/{instanceId}/templates/{name}
json
{ "deleted": true, "name": "confirmacao_pedido" }

Enviar um template aprovado#

text
POST /v1/instances/{instanceId}/official/send-template

Requer Idempotency-Key. É a única mensagem que abre uma conversa fora da janela de 24h. Fora da janela, um envio livre (/messages/text) retorna 409 OUTSIDE_SERVICE_WINDOW — use este endpoint.

Request

json
{
  "to": "5541999998888",
  "template_name": "confirmacao_pedido",
  "language": "pt_BR",
  "components": [
    { "type": "header", "parameters": [{ "type": "text", "text": "Ana" }] },
    { "type": "body", "parameters": [{ "type": "text", "text": "#12345" }, { "type": "text", "text": "3" }] }
  ]
}

Response 202

json
{ "status": "queued", "message_id": "<uuid>", "task_id": "...", "idempotency_key": "..." }

Os parâmetros preenchem as variáveis {{n}} do template na ordem. O message_id retornado é o UUID Catcher que aparecerá nos webhooks message.sent / message.delivered / message.read.

Opt-out de marketing: enviar um template category:"marketing" para um contato que optou por sair (evento official.marketing_optout com opted_out=true) retorna 409 BLOCKED_MARKETING_OPTOUT. Templates utility e authentication sempre passam, independentemente do opt-out.