Skip to main content
Templates definem conteúdo de mensagem reutilizável. Crie e gerencie-os no painel (/templates) ou via API REST pública (/v1/templates) e o servidor MCP (templates_create / templates_update / templates_delete). Ao enviar, referencie o template pelo templateId e passe um objeto variables com chaves correspondentes.
Modal de envio de template via API com curl pronto

Todo template tem uma chamada de API pronta — o modal Enviar via API do editor gera o curl exato com o templateId.

Todas as requisições usam o header x-api-key: ps_... (ou x-api-key-id). URL base: https://pilotstatus.com.br/v1.

Categoria

Definida no momento da criação; não pode ser alterada depois.
  • MARKETING — mensagens promocionais (mais sensíveis às políticas do WhatsApp).
  • UTILITY — mensagens transacionais (atualizações de conta, alertas, lembretes).
  • OTP — mensagens de código único / de verificação.

Estrutura do template

Apenas o body é obrigatório.
  • API REST: passe header.url (URL http(s) pública) ou header.base64 (data URI) — o base64 é re-hospedado no servidor automaticamente.
  • MCP: header.url apenas — base64 não é suportado via MCP.
Não existe header LOCATION.

Body

  • Até 1024 caracteres.
  • Variáveis escritas como {{nome}} (estilo nomeado).
  • O body não pode começar nem terminar com uma variável.
  • Emojis e múltiplas variáveis são permitidos.
Texto estático de até 60 caracteres. Sem variáveis.

Buttons

Até 10 botões no total; botões de resposta rápida e CTA podem ser combinados.
  • Botão de URL dinâmica: a URL termina com uma variável (ex.: https://loja.com/promo/{{link}}) — no máximo uma variável, nunca no domínio. O valor de exemplo vai em examples. No envio, ela é preenchida pelo nome (variables.link). Um template criado no painel da Meta com placeholder numerado (https://ctlnk.io/{{1}}) é preenchido por button_<N> — veja Placeholders de botão em templates criados na Meta.
  • Copy-code: o valor vai no botão como example (array, ex.: ["PROMO10"]), somente alfanumérico, até 15 caracteres. Não serve para chave PIX ou e-mail — para PIX use o botão PAYMENT_REQUEST abaixo. Em um número oficial esse example é só uma amostra: o código que o cliente copia vai em variables como button_<N> a cada envio — veja Botões de copiar código em números oficiais.

Botão de pagamento PIX (PAYMENT_REQUEST)

Botão de pagamento do WhatsApp Pay Brasil: o cliente toca e copia o código PIX. É o caminho certo para PIX copia-e-cola — o COPY_CODE trava em 15 caracteres alfanuméricos e um BR Code tem 100-400 caracteres com pontuação. O código é por envio: escreva uma variável no example do botão e mande o valor real em variables no envio, como qualquer outra variável.
Esse botão depende de a Meta ter liberado pagamentos para a sua WhatsApp Business Account. A liberação é gradual e por conta — a própria Meta diz “this feature is rolling out and might not be available yet for your WhatsApp Business account”. Numa conta sem liberação, a Meta recusa a criação do template com 100 / subcode 2388128 (“Button at index 0 has unexpected type (PAYMENT_REQUEST)”). Não há como consultar essa permissão pela API — só tentando criar.
Ao enviar, a variável do código PIX é obrigatória. Se ela faltar, o envio é recusado em vez de seguir: sem o parâmetro a Meta usaria o código de exemplo cadastrado no template, e o cliente pagaria para a conta errada.
O ORDER_DETAILS (card de pedido itemizado) pode ser montado, pré-visualizado e salvo — veja Card de pedido itemizado.
  • Botões são permitidos junto com um header de vídeo ou documento (PDF).

Variáveis & examples (obrigatório)

Ao criar/atualizar via REST ou MCP você deve incluir um objeto examples mapeando cada variável usada (body + texto do header + URL dinâmica) para um valor de exemplo real. O valor do copy-code é a única exceção (ele fica no botão).
Após salvar, GET /v1/templates/{id} retorna todas as chaves detectadas no array variables de nível superior (um string[]) — forneça todas elas em variables no envio. Não há objeto latestVersion na resposta da API pública.

Placeholders de botão em templates criados na Meta

Um template criado no WhatsApp Manager da Meta e sincronizado no Pilot Status (source: "META") com placeholders posicionais numera a variável de um botão de URL dinâmica por conta própria: em https://ctlnk.io/{{1}}, esse {{1}} não é o {{1}} do body. Mande o valor dele como variables["button_<N>"], em que N é a posição do botão na lista de botões do template, começando em 1 — todos os botões contam, inclusive os estáticos. Passe só a parte variável (o sufixo da URL), não a URL inteira:
  • GET /v1/templates e GET /v1/templates/{id} listam a chave em variables — ["1", "2", "3", "button_1"] para o template acima.
  • Um envio sem ela, ou com valor vazio, é recusado com 400 MISSING_TEMPLATE_VARIABLES (ou INVALID_TEMPLATE_VARIABLE_VALUE) nomeando a chave, em vez de ser aceito e falhar depois com o 131008 da Meta.
  • Placeholders nomeados não mudam: um botão criado no Pilot Status como https://loja.com/promo/{{link}} é preenchido por variables.link.
  • A mesma chave button_<N> leva o código de um botão de copiar código num número oficial — veja abaixo.

Botões de copiar código em números oficiais

Para a Meta, o código digitado num botão COPY_CODE na criação é só um exemplo; o código que o cliente copia é um parâmetro obrigatório de todo envio. Por isso, num template aprovado pela Meta (source: "META" — todo template de um número oficial, criado no painel da Meta ou no Pilot Status), um botão de copiar código cujo valor não tem {{variável}} (um exemplo fixo como PROMO10) recebe o código como variables["button_<N>"], com a mesma regra: N é a posição do botão na lista de botões do template, começando em 1, e todos os botões contam. Para os botões [QUICK_REPLY, COPY_CODE] com o exemplo PROMO10:
  • GET /v1/templates e GET /v1/templates/{id} listam a chave em variables — button_4 para o template promo_cupom de Criar via API REST.
  • Um envio sem ela, ou com valor vazio, é recusado com 400 MISSING_TEMPLATE_VARIABLES (ou INVALID_TEMPLATE_VARIABLE_VALUE) nomeando a chave. O example mantém o limite da criação (15 caracteres alfanuméricos); para o código enviado, o limite da Meta é de 20 caracteres.
  • Um botão de copiar código cujo exemplo é uma variável nomeada (["{{cupom}}"]) continua sendo preenchido por variables.cupom. O botão de código de um template de autenticação (OTP) continua recebendo o código do body.
  • Números não oficiais (web/QR): o código também é gerado a cada envio — escreva-o no botão como {{variável}} (ex.: ["{{cupom}}"]) e preencha em variables.

Limites de caracteres

Criar via API REST

  • body pode ser um objeto (recomendado), uma string JSON ou texto simples (templates só de body).
  • Edite com PUT /v1/templates/{id} (mesmo formato); remova com DELETE /v1/templates/{id} — para um template Meta isso também pede à Meta para excluí-lo, e a resposta depende do que a Meta faz (veja Excluir).
  • GET /v1/templates / GET /v1/templates/{id} retornam source (META | PILOT_STATUS), metaStatus (APPROVED | PENDING | REJECTED | DISABLED | null), metaLanguage e sendable — em um número Meta apenas templates META com metaStatus: "APPROVED" são enviáveis.

Excluir

DELETE /v1/templates/{id} não retorna mais sucesso sempre. Para um template Meta a exclusão é encaminhada à Meta, e o resultado depende do que a Meta faz:
  • Um 200 { "deleted": true, "id" } é a única resposta que significa que o template realmente sumiu — removido na Meta e localmente.
  • Um 409 significa que nada foi removido: a Meta rejeitou a exclusão (ex.: o system token não tem permissão na WABA), então o template ainda existe na Meta e o nome dele continua reservado. O registro local é mantido, e a mensagem nomeia o template e o motivo. Corrija a permissão e tente de novo.
  • Se a Meta informar que o template não existe (um 404 de verdade / “template does not exist”), o registro local obsoleto é removido e você ainda recebe 200 { "deleted": true, "id" }.

Templates de carrossel

Um template de carrossel é um template aprovado cujo body carrega um bloco carousel: uma faixa rolável na horizontal com 2 a 10 cartões de mídia, cada um com sua própria imagem, linha de texto e botões. Templates de carrossel são exclusivos de números Meta e sempre da categoria MARKETING — em um número Meta a criação é enviada à Meta como um componente CAROUSEL. Diferente do carrossel de sessão (interativo, somente resposta rápida — um botão de URL ali retorna 400), um cartão de carrossel de template pode combinar botões QUICK_REPLY e URL no mesmo cartão. Ele fica dentro de body, ao lado de body.text — a mensagem exibida acima dos cartões (o corpo do carrossel).

Limites (validados na criação e na atualização)

Os mesmos limites e regras de mídia valem para POST (criar) e PUT (atualizar) — a validação não é mais pulada. Mídia do cartão — cada card.media.url deve ser uma URL https pública terminada em .png, .jpg, .jpeg ou .webp, sem query string. A Meta aceita uma imagem inacessível com 200 e depois não entrega nada, então a URL é buscada e recusada antes do envio, com um erro tipado que nomeia o cartão problemático.
Um header de nível superior não é permitido com carousel (a mídia fica em cada cartão), e os botões dos cartões substituem os buttons de nível superior.

Criar um template de carrossel

Aqui todo cartão repete o par QUICK_REPLY + URL declarado em cardTemplate.buttons, nessa ordem. Um cartão que omite um botão, troca a ordem ou muda um tipo é recusado antes do envio.

Aprovação

  • Números Meta: os templates são enviados à Meta para revisão (“Submit to Meta” em /templates, ou ao salvar). Categorias, idioma e status seguem as regras da Meta.
  • Números não oficiais (Pilot Status web): os templates são criados localmente e ficam imediatamente utilizáveis — sem etapa de aprovação.

Não suportado

LOCATION (header ou botão), CATALOG/MPM, LIMITED_TIME_OFFER, OTP autofill/one-tap/zero-tap e botões VOICE_CALL. (O carousel de sessão — a variante fora de template — está na referência de Enviar mensagem.) Botões FLOW são suportados em números Meta — veja Enviar um Flow. O ORDER_DETAILS (card de pedido itemizado) pode ser montado, pré-visualizado e salvo — veja Card de pedido itemizado para o comportamento por tipo de número. O parameter_format NAMED é suportado: um template criado no painel da Meta com variáveis nomeadas ({{nome_do_cliente}}) é importado com as variáveis certas e enviado com parameter_name em cada parâmetro.

Erros de envio & rejeição

Botões de link/URL aceitam uma única variável que deve estar no final da URL e nunca no domínio; botões de chamada precisam do código do país (ex.: +55).

Verificado antes de enviar à Meta

Validação do lado da API

A Meta rejeitou o envio

Rejeitado após revisão

Bloqueios ao enviar (mesmo aprovado)

Erro comum ao enviar

404 — template sem uma versão aprovada (não existe para a chave, ou o template Meta ainda não tem versão aprovada).