Seções

Templates

Criar, listar, editar e sincronizar templates oficiais e seu ciclo de aprovação.

Templates são um conceito oficial (WABA): só existem para números oficiais. O broker é dono ponta a ponta — valida, submete à plataforma oficial, recebe o status. Um tenant só não-oficial recebe unsupported_capability ao tentar usá-los.

Ciclo de vida

Ao criar, o template fica pending (em revisão na plataforma oficial). A aprovação/rejeição chega de forma assíncrona pelo evento template.updated no seu webhook — não bloqueie esperando.

statussignificado
pendingsubmetido, em revisão na plataforma oficial
approvedaprovado — pode ser usado no envio
rejectedrejeitado (veja rejectedReason)
pausedpausado pela plataforma oficial
disableddesabilitado

Criar

templates.create(input) recebe name, language, category (marketing / utility / authentication) e components agnósticos — o broker os valida e monta no formato da plataforma oficial. channelId é opcional com um único número oficial; obrigatório com mais de um.

ts
const template = await wa.templates.create({
  name: 'confirmacao_pedido',
  language: 'pt_BR',
  category: 'utility',
  components: [
    { type: 'body', text: 'Pedido {{1}} confirmado, entrega {{2}}.', example: ['1234', 'amanhã'] },
    { type: 'footer', text: 'Sua Loja' },
  ],
})

Resposta 201

json
{
  "category": "utility",
  "channelId": "ch_9f2c8a1b0d3e4f50",
  "components": [
    {
      "example": {
        "body_text": [
          [
            "John"
          ]
        ]
      },
      "text": "Hi {{1}}",
      "type": "BODY"
    }
  ],
  "createdAt": "2026-08-04T12:00:00.000Z",
  "id": "tpl_5a1c3e7f9b2d4068",
  "language": "en_US",
  "metaTemplateId": "meta-777",
  "name": "welcome",
  "rejectedReason": null,
  "status": "pending",
  "updatedAt": "2026-08-04T12:00:00.000Z"
}

Listar e ler

ts
// Paginado por cursor; filtro opcional por status
const page = await wa.templates.list({ status: 'approved', limit: 50 })
for (const t of page.items) console.log(t.name, t.language, t.status)
if (page.nextCursor) {
  const next = await wa.templates.list({ cursor: page.nextCursor })
}

const one = await wa.templates.get(template.id)

Resposta 200

json
{
  "items": [
    {
      "category": "utility",
      "channelId": "ch_9f2c8a1b0d3e4f50",
      "components": [
        {
          "example": {
            "body_text": [
              [
                "John"
              ]
            ]
          },
          "text": "Hi {{1}}",
          "type": "BODY"
        }
      ],
      "createdAt": "2026-08-04T12:00:00.000Z",
      "id": "tpl_5a1c3e7f9b2d4068",
      "language": "en_US",
      "metaTemplateId": "meta-777",
      "name": "welcome",
      "rejectedReason": null,
      "status": "pending",
      "updatedAt": "2026-08-04T12:00:00.000Z"
    }
  ],
  "nextCursor": null
}

Resposta 200

json
{
  "category": "utility",
  "channelId": "ch_9f2c8a1b0d3e4f50",
  "components": [
    {
      "example": {
        "body_text": [
          [
            "John"
          ]
        ]
      },
      "text": "Hi {{1}}",
      "type": "BODY"
    }
  ],
  "createdAt": "2026-08-04T12:00:00.000Z",
  "id": "tpl_5a1c3e7f9b2d4068",
  "language": "en_US",
  "metaTemplateId": "meta-777",
  "name": "welcome",
  "rejectedReason": null,
  "status": "pending",
  "updatedAt": "2026-08-04T12:00:00.000Z"
}

Editar

templates.update(id, input) edita de forma atômica (sem delete+create): novos components e, opcionalmente, category. name e language são imutáveis, então não entram. A edição devolve o template à revisão (volta a pending) e só vale para um template em estado editável.

ts
await wa.templates.update(template.id, {
  components: [
    { type: 'body', text: 'Pedido {{1}} confirmado. Entrega prevista: {{2}}.', example: ['1234', 'amanhã'] },
  ],
})

Resposta 200

json
{
  "category": "marketing",
  "channelId": "ch_9f2c8a1b0d3e4f50",
  "components": [
    {
      "example": {
        "body_text": [
          [
            "Jane"
          ]
        ]
      },
      "text": "Hi again {{1}}",
      "type": "BODY"
    }
  ],
  "createdAt": "2026-08-04T12:00:00.000Z",
  "id": "tpl_5a1c3e7f9b2d4068",
  "language": "en_US",
  "metaTemplateId": "meta-777",
  "name": "welcome",
  "rejectedReason": null,
  "status": "pending",
  "updatedAt": "2026-08-04T12:00:00.000Z"
}

Só approved ou rejected podem ser editados

A plataforma oficial só aceita editar templates approved ou rejected. Um pending (em revisão) ou nunca submetido responde template_not_editable (HTTP 409).

Sincronizar e remover

  • templates.sync() reconcilia a partir da plataforma oficial sob demanda — devolve { synced, created, updated }. Útil para alinhar mudanças feitas fora do broker.
  • templates.delete(id) apaga na plataforma oficial e faz o soft-delete local. Resolve void.
ts
const result = await wa.templates.sync()

await wa.templates.delete(template.id)

Resposta 200

json
{
  "created": 0,
  "synced": 1,
  "updated": 1
}

Enviar um template aprovado

Com o template approved, envie por messages.send com content.kind: 'template'. Veja Enviar mensagens.