Pular para o conteúdo principal

WABA Templates

Templates aprovados pela Meta para envio de mensagens proativas (marketing, utility, authentication). Sem template, você só pode mandar mensagem dentro da janela de 24h após uma inbound do usuário.

Base path: /v1/templates

Apenas WABA. Baileys não tem conceito de template.


Lifecycle

POST /v1/templates


DRAFT ────► (gateway envia pra Meta sync)


PENDING ──► (Meta revisa, ~minutos a ~24h)

├──► APPROVED ──► usável em POST /v1/messages type=template
├──► REJECTED ──► verifique rejectionReason
└──► PAUSED ──► (Meta pausou por baixo engagement)

Após APPROVED, você pode editar (volta pra PENDING).


Componentes suportados

Cada template é composto por componentes (HEADER, BODY, FOOTER, BUTTONS, CAROUSEL, LIMITED_TIME_OFFER). O schema completo:

{ "type": "HEADER", "format": "TEXT", "text": "Olá {{1}}", "example": { "header_text": ["João"] } }

Formats: TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION.

Para mídia, use example com header_handle (de POST /v1/media/upload/resumable).

BODY

{ "type": "BODY", "text": "Sua consulta {{1}} foi confirmada para {{2}}", "example": { "body_text": [["Cardiologia", "20/05 às 14h"]] } }

Body é obrigatório. Suporta variáveis {{1}}, {{2}}, ... que viram variables em POST /v1/messages.

{ "type": "FOOTER", "text": "Acme Saúde" }

Máx 60 chars, sem variáveis.

BUTTONS

Lista de até 10 botões. Tipos suportados:

TipoDescrição
QUICK_REPLYBotão de resposta rápida (texto curto)
URLAbre URL (suporta variáveis em URL: https://acme.com/{{1}})
PHONE_NUMBERDisca número
COPY_CODECopia código (cupom, PIX, etc)
OTPAuthentication template (COPY_CODE/ONE_TAP/ZERO_TAP)
CATALOGAbre catálogo da WABA
MPMMulti-Product Message
SPMSingle-Product Message
FLOWAbre WhatsApp Flow
VOICE_CALLInicia voice call WABA

Exemplo URL com variável:

{
"type": "BUTTONS",
"buttons": [
{ "type": "URL", "text": "Ver pedido", "url": "https://acme.com/pedido/{{1}}", "example": ["12345"] }
]
}

Marketing template com até 10 cards (cada card = mini-template com HEADER mídia + BODY + BUTTONS).

{
"type": "CAROUSEL",
"cards": [
{
"components": [
{ "type": "HEADER", "format": "IMAGE", "example": { "header_handle": ["h:..."] } },
{ "type": "BODY", "text": "Produto A — R$ {{1}}", "example": { "body_text": [["99,90"]] } },
{ "type": "BUTTONS", "buttons": [{ "type": "URL", "text": "Comprar", "url": "https://acme.com/a" }] }
]
}
]
}

LIMITED_TIME_OFFER

Template com countdown:

{
"type": "LIMITED_TIME_OFFER",
"limited_time_offer": { "text": "Oferta termina em", "has_expiration": true }
}

POST /v1/templates

Cria template e submete à Meta de forma síncrona (a request espera a chamada Graph API).

Body

CampoTipoObrigatórioDescrição
phoneIdUUIDsimPhone WABA dono
namestringsim1-120, [a-z0-9_]+ (lowercase + underscore)
languagestringsimpt_BR, en_US, etc.
categoryenumsimMARKETING, UTILITY, AUTHENTICATION
componentsarraysim1+ componentes
allowCategoryChangebooleannãoDefault true. Meta pode reclassificar
messageSendTtlSecondsintnão30-43200 (12h). Auto-fail se não entregue
curl -X POST https://wpp.ogmma.com.br/v1/templates \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"phoneId": "5f7b2e1c-...",
"name": "boas_vindas_v2",
"language": "pt_BR",
"category": "UTILITY",
"components": [
{ "type": "BODY", "text": "Olá {{1}}, bem-vindo!", "example": { "body_text": [["João"]] } },
{ "type": "FOOTER", "text": "Acme Saúde" },
{
"type": "BUTTONS",
"buttons": [{ "type": "QUICK_REPLY", "text": "Saiba mais" }]
}
]
}'

Response 201

{
"id": "tpl-1234-...",
"accountId": "...",
"phoneId": "5f7b2e1c-...",
"name": "boas_vindas_v2",
"language": "pt_BR",
"category": "UTILITY",
"status": "PENDING",
"components": [ ... ],
"metaTemplateId": "987654321",
"createdAt": "2026-05-21T14:00:00.000Z"
}

Errors

HTTPCodeQuando
400VALIDATION_ERRORSchema inválido
400WABA_CREDS_INCOMPLETEPhone sem wabaPhoneNumberId/accessToken
404PHONE_NOT_FOUNDPhone não é WABA ou não pertence à account

GET /v1/templates

Lista templates da account.

curl https://wpp.ogmma.com.br/v1/templates \
-H "X-API-Key: ak_live_..."

Response 200 — array.


GET /v1/templates/:id

Detalhe.

curl https://wpp.ogmma.com.br/v1/templates/tpl-1234-... \
-H "X-API-Key: ak_live_..."

Errors

HTTPCodeQuando
404TEMPLATE_NOT_FOUND

PATCH /v1/templates/:id

Edita um template já sincronizado com Meta. Mantém name/language; permite mudar components, category, messageSendTtlSeconds. Após edit, Meta re-revisa (status volta para PENDING).

Body (todos opcionais)

CampoTipoObrigatório se quiser editar
componentsarray
categoryenum
messageSendTtlSecondsint
curl -X PATCH https://wpp.ogmma.com.br/v1/templates/tpl-1234-... \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"components": [
{ "type": "BODY", "text": "Versão atualizada {{1}}", "example": { "body_text": [["X"]] } }
]
}'

Errors

HTTPCodeQuando
409TEMPLATE_NOT_SUBMITTEDTemplate ainda não tem metaTemplateId

DELETE /v1/templates/:id

Deleta na Meta + remove local. Se Meta falhar (ex.: template já em uso), remove localmente mesmo assim (log de warn).

curl -X DELETE https://wpp.ogmma.com.br/v1/templates/tpl-1234-... \
-H "X-API-Key: ak_live_..."

Response 204


POST /v1/templates/sync

Re-importa todos os templates de uma WABA direto da Meta (útil quando o time criou templates pelo Business Manager).

Body

CampoTipoObrigatório
phoneIdUUIDsim
curl -X POST https://wpp.ogmma.com.br/v1/templates/sync \
-H "X-API-Key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{ "phoneId": "5f7b2e1c-..." }'

Response 200 — objeto com counts de criados/atualizados.


Notificação de aprovação

Quando a Meta aprova/rejeita um template, o webhook template:status é publicado (assumindo que você subscreve esse evento). O DB local é atualizado automaticamente pelo handler meta-webhook. Você pode também fazer polling em GET /v1/templates/:id.


Boas práticas

  1. Nomes únicos por phone+language: boas_vindas_v2 + pt_BR é único — versione o nome se mudar muito o body.
  2. Categorias corretas: MARKETING é cobrado mais caro que UTILITY. Meta auto-reclassifica se identificar abuse.
  3. Examples obrigatórios: Meta exige example em componentes com variáveis para entender o uso real.
  4. Header media via handle: para template com IMAGE/VIDEO header, não use url — suba via POST /v1/media/upload/resumable e use o handle no example.header_handle.