Enviar mensagens
POST /v1/messages
Exige o escopo send. A resposta é 202, com o id da mensagem: ela entrou na fila e será enviada respeitando o ritmo do número.
Texto
{
"instance": "nome-do-numero",
"to": "5542999999999",
"type": "text",
"content": { "text": "Sua sala está confirmada para amanhã às 14h." },
"category": "transactional",
"external_ref": "invoice:1234"
}
| Campo | O que é |
|---|---|
instance |
Nome do número que envia |
to |
Telefone com DDI e DDD, só números |
type |
text ou media |
content |
O conteúdo, conforme o tipo |
category |
transactional, notification ou marketing: define a prioridade na fila e se o opt-out se aplica. Omitida, vale transactional, que não respeita opt-out nem a pausa noturna |
external_ref |
Uma referência sua, devolvida nos webhooks |
callback_url |
Webhook só desta mensagem, no lugar do configurado no projeto |
Mídia
O gateway não recebe o arquivo: recebe uma URL pública e vai buscá-la.
{
"to": "5542999999999",
"type": "media",
"content": {
"media_url": "https://exemplo.com/exame.pdf",
"media_type": "document",
"text": "segue o seu exame"
}
}
media_type aceita image, audio, video e document.
Template (número oficial)
No número oficial (API da Meta), fora da janela de 24 horas só sai template: um modelo de mensagem que a Meta aprovou antes. Você pode criá-los no Gerenciador do WhatsApp da sua empresa, ou por aqui.
GET /v1/instances/{name}/templates os aprovados, com as variáveis de cada um (escopo send)
GET /v1/instances/{name}/templates?status=all todos, com status, rejected_reason e quality_score
POST /v1/instances/{name}/templates cria na Meta: {name, category, language?, body, body_examples, footer?, buttons?} → 201 PENDING (manage_instances)
DELETE /v1/instances/{name}/templates/{templateName} apaga na Meta → 204 (manage_instances)
A aprovação (minutos a 48 h) chega pelo webhook template.status. Erros ao criar voltam como 422 com error estável: nome_duplicado, exemplo_faltando, template_invalido, sem_permissao_de_gerenciamento (o token do número não tem whatsapp_business_management; templates_gerenciaveis em GET /v1/instances/{name} diz antes).
{
"instance": "numero-oficial",
"to": "5542999999999",
"type": "template",
"template": {
"name": "lembrete_consulta",
"language": "pt_BR",
"body": ["Ana", "amanhã às 14h"],
"header": { "type": "image", "media_url": "https://exemplo.com/clinica.jpg" },
"buttons": [{ "index": 0, "type": "url", "value": "abc123" }]
},
"category": "notification"
}
| Campo | O que é |
|---|---|
name, language |
O template, como aparece na lista. language padrão pt_BR |
body |
As variáveis do corpo, na ordem ({{1}}, {{2}}…). Template com variáveis nomeadas: um objeto, {"nome": "Ana"} |
header |
Só se o template tem cabeçalho variável: text (com text), ou image, video, document (com media_url pública) |
buttons |
Só os botões que pedem valor: url (o pedaço final do link), quick_reply (o payload) ou copy_code (o cupom), cada um com o index dele |
A Meta cobra cada template entregue, direto da conta da sua empresa. Responder quem escreveu dentro de 24 horas não é cobrado. Template só existe no número oficial: no número conectado por QR a resposta é 422 template_exige_numero_oficial.
Idempotência
Para ligar cada webhook ao seu lado (uma campanha, um pedido), mande metadata: um objeto JSON de até 1 KB, devolvido igual em message.sent, message.delivered, message.read e message.failed.
Mande um cabeçalho Idempotency-Key com um valor seu e único por envio. Repetir a chamada com a mesma chave (por exemplo, depois de um timeout) devolve a mesma mensagem, com 200 e idempotent_replay: true, em vez de enviar duas vezes.
As travas de proteção
O gateway recusa o que pode derrubar o número: banimento, na conexão por QR code, e queda de qualidade na Meta, no número oficial. As recusas mais comuns:
| Resposta | Significado |
|---|---|
422 fora_da_janela |
O contato não escreveu para este número nas últimas 24 horas. É definitivo: o contato precisa escrever primeiro. Não repita em loop; use outro canal (e-mail, SMS), ou, no número oficial, um template. |
422 categoria_nao_permitida |
O projeto só responde, e a categoria marketing não é aceita. Projeto com a chave de campanha ligada manda marketing só por template, só pelo número oficial. |
422 teto_marketing_do_dia |
O número oficial já alcançou o teto de contatos de marketing do dia. retry_after diz, em segundos, quando tentar de novo (meia-noite de Brasília). |
409 |
O número pediu para não receber esta categoria (opt-out). |
409 dados_excluidos |
A Idempotency-Key repetida é de uma mensagem cujo contato pediu a exclusão dos dados. Use outra chave. |
Quando um contato pede a exclusão dos dados dele, as mensagens e a mídia daquele telefone passam a responder 404, e os avisos pendentes sobre elas não são entregues.
O campo error é o código estável; message, quando existe, é texto para humanos e pode mudar. Decida pelo error.
Consultar e cancelar
GET /v1/messages/{id} status e histórico de eventos (escopo read_logs)
POST /v1/messages/{id}/cancel cancela se ainda não saiu (escopo send)
O que o WhatsMax não faz
Lista comprada, envio em massa, lista de transmissão e qualquer coisa que ignore o opt-out ou o ritmo do número ficam de fora de propósito: é o que derruba números. Para falar com quem não escreveu nas últimas 24 horas, use um template aprovado pelo número oficial (em projeto que só responde, com a chave de campanha ligada). No número por QR code, que só responde, o caminho é e-mail ou SMS.