POST /messages

Uma chamada para todo tipo de mensagem: texto, template, mídia, botões, lista, link, pedido de localização e catálogo. Em vez de decorar nove endpoints diferentes, você muda o campo type.

Escopo necessário: messages:send. Exige plano com o recurso de API. Limite: 120 requisições por minuto.

O básico

curl -X POST "https://api.wevi.chat/functions/v1/messages" \
  -H "Authorization: Bearer wevi_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-8412-confirmado" \
  -d '{
    "type": "text",
    "to": "5511999998888",
    "text": "Seu pedido saiu para entrega."
  }'

Resposta:

{
  "id": "bcb8e0c6-de1b-48dd-8712-c381ca4b1b74",
  "wamid": "wamid.HBgLNTUxMT...",
  "status": "sent",
  "conversation_id": null,
  "contact_id": null
}

Quando a Meta recusa, a resposta continua 200, com status: "failed" e o motivo em error. Recusa é resultado do envio, não erro da sua requisição: tratar como 5xx faz cliente com retry automático mandar a mensagem duas vezes.

Campos comuns

Campo Descrição
type Obrigatório. Um dos tipos da tabela abaixo.
to Telefone do destinatário, em qualquer formato brasileiro.
conversation_id Alternativa a to: responde dentro de uma conversa existente.
connection_id O número que envia. Pode omitir quando a organização só tem um.
contact_id Associa o envio a um contato existente.
contact { "name": "...", "fields": { ... } }: cria ou atualiza o contato junto do envio.
idempotency_key Também aceito no header Idempotency-Key. Retry com a mesma chave não reenvia.
open_conversation Só para template: always (padrão) abre a conversa no inbox, on_reply espera o cliente responder.

Tipos

type Campos próprios
text text
template template_name ou template_id, language_code, body_params, header_image_url, button_params
image, audio, video, document media: { url, mime_type, name }, caption
buttons body, buttons (até 3), header, footer
list body, sections, button_text, header, footer
cta_url body, url, display_text, header, footer
location_request body
product catalog_id, product_retailer_id, body, footer
product_list catalog_id, sections, body, header, footer

Template

{
  "type": "template",
  "to": "5511999998888",
  "template_name": "confirmacao_pedido",
  "language_code": "pt_BR",
  "body_params": ["Maria", "8412"],
  "open_conversation": "on_reply"
}

Texto livre só chega dentro da janela de 24 horas depois da última mensagem do cliente. Fora dela, use template: é a regra da Meta, não nossa.

Criar o contato junto do envio

{
  "type": "template",
  "to": "5511999998888",
  "template_name": "boas_vindas",
  "body_params": ["Maria"],
  "contact": {
    "name": "Maria Souza",
    "fields": { "origem": "site", "plano": "premium" }
  }
}

O contato é criado ou atualizado pelo telefone antes do envio, e o contact_id volta na resposta. Poupa uma chamada e garante que a conversa que nascer já esteja ligada à pessoa certa.

Botões

{
  "type": "buttons",
  "to": "5511999998888",
  "body": "Podemos confirmar seu horário de quinta às 15h?",
  "buttons": [
    { "id": "confirmar", "title": "Confirmar" },
    { "id": "remarcar", "title": "Remarcar" }
  ],
  "footer": "Clínica OdontoVita"
}

Mídia

{
  "type": "document",
  "to": "5511999998888",
  "media": {
    "url": "https://seusistema.com/notas/8412.pdf",
    "mime_type": "application/pdf",
    "name": "nota-fiscal-8412.pdf"
  },
  "caption": "Segue a nota fiscal do seu pedido."
}

A URL precisa ser pública: quem baixa o arquivo é a Meta, não a gente.

Erros

Status error Quando
400 missing_type Faltou type.
400 unsupported_type type não existe. A resposta lista os aceitos em details.accepted.
400 missing_destination Nem to nem conversation_id.
400 missing_connection_id A organização tem mais de um número: diga qual usar.
400 no_connection Nenhum número de WhatsApp conectado.
403 opted_out O contato pediu para não receber mais e não escreveu nas últimas 24h.
404 connection_not_found O connection_id não é desta organização.
200 corpo com status: "failed" A Meta recusou. O motivo dela vem em error.

E os endpoints antigos?

/send-message, /send-template, /send-buttons, /send-list, /send-cta-url, /send-location-request, /send-product, /send-product-list e /send-conversation-message continuam funcionando com o mesmo contrato de sempre. Por dentro, agora eles e o /messages usam a mesma implementação de envio.

Integração nova nasce melhor no /messages. Integração que já funciona não precisa mudar nada.

Próximo

/send-template