Como enviar mensagens WhatsApp via API
Nível: Intermediário
Tempo de leitura: 8 min
Plano necessário: Pro ou Ultra
Procurando a referência técnica? Veja POST /send-template, POST /send-message e POST /send-conversation-message na documentação de API, com schema completo, idempotência, variáveis dinâmicas e códigos de erro.
O que é esta funcionalidade
A Wevi oferece dois endpoints HTTP que permitem enviar mensagens WhatsApp diretamente de qualquer sistema externo com suporte a requisições HTTP, como n8n, Make, Zapier, sistemas próprios ou scripts.
Com isso, você consegue, por exemplo:
- Enviar um template de boas-vindas quando um novo cliente se cadastra no seu CRM
- Disparar um lembrete de consulta a partir do seu sistema de agendamento
- Notificar clientes sobre status de pedido via webhook do seu e-commerce
- Criar automações de reengajamento a partir de qualquer ferramenta externa
Endpoints disponíveis
| Endpoint | Quando usar |
|---|---|
POST /functions/v1/send-template |
Enviar template aprovado pela Meta. Funciona a qualquer momento, mesmo sem histórico de conversa. |
POST /functions/v1/send-message |
Enviar texto livre. Só funciona se o contato interagiu com você nas últimas 24 horas. Não fica registrado na conversa nem no histórico do agente de IA, só na aba Enviadas de Campanhas. |
POST /functions/v1/send-conversation-message |
Enviar texto e/ou imagem dentro de uma conversa já existente, continuando o atendimento. A mensagem aparece na conversa e entra no contexto do agente de IA. Ideal pra entregar o resultado de um processo assíncrono (ex: geração de imagem via n8n) na mesma conversa que o originou. |
Pré-requisitos
- Plano Pro ou Ultra
- Conexão WhatsApp ativa na Wevi (obtenha o
connection_idem Configurações → WhatsApp) - Para
send-template: pelo menos um template aprovado pela Meta - Uma API Key gerada em Conta → Desenvolvedores
Passo 1: Gerar uma API Key
- No painel, vá em Conta → aba Desenvolvedores
- Role até a seção API Keys
- Digite um nome para identificar a chave (ex: "n8n produção") e clique em Criar chave
- Copie o token exibido. Ele começa com
wevi_e não será exibido novamente
Passo 2: Obter o connection_id
O connection_id identifica qual número WhatsApp vai enviar a mensagem.
- Vá em Configurações → WhatsApp no painel
- Localize o número que vai enviar a mensagem
- Copie o
connection_idmostrado abaixo do nome dele
Passo 3: Fazer a primeira chamada
Enviando um template
curl -X POST https://api.wevi.chat/functions/v1/send-template \
-H "Authorization: Bearer wevi_SUACHAVEAQUI" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "uuid-da-conexao",
"template_name": "boas_vindas_v1",
"language_code": "pt_BR",
"body_params": ["Maria"],
"to": "5548999001122"
}'
Resposta de sucesso:
{
"id": "uuid-do-envio",
"wamid": "wamid.ABC123...",
"status": "sent"
}
Enviando texto livre (dentro da janela de 24h)
curl -X POST https://api.wevi.chat/functions/v1/send-message \
-H "Authorization: Bearer wevi_SUACHAVEAQUI" \
-H "Content-Type: application/json" \
-d '{
"connection_id": "uuid-da-conexao",
"to": "5548999001122",
"text": "Olá! Seu pedido foi enviado e chega em até 2 dias úteis."
}'
Entregando o resultado de um processo assíncrono numa conversa existente
Use quando um sistema externo (ex: um workflow no n8n que demora minutos pra terminar) precisa devolver o resultado dentro da mesma conversa que originou o pedido:
curl -X POST https://api.wevi.chat/functions/v1/send-conversation-message \
-H "Authorization: Bearer wevi_SUACHAVEAQUI" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "uuid-da-conversa",
"text": "Prontinho! Aqui está o resultado.",
"media": {
"url": "https://exemplo.com/resultado.png",
"type": "image",
"mime_type": "image/png"
}
}'
O conversation_id é o mesmo valor que a Wevi já manda automaticamente (dentro de _wevi.conversation_id) quando um agente dispara uma ação customizada pro seu webhook.
Se o seu sistema já tem os bytes do arquivo em mãos (ex: uma imagem gerada que ainda não foi hospedada em lugar nenhum), pode mandar em media.base64 em vez de media.url. Não precisa subir o arquivo pra nenhum storage antes, o Wevichat cuida disso. Veja o passo a passo completo em POST /send-conversation-message.
Parâmetros completos
send-template
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
connection_id |
string (uuid) | Sim | ID da conexão WhatsApp |
template_name |
string | Sim | Nome exato do template aprovado |
to |
string | Sim | Número no formato internacional (ex: 5511999001122) |
language_code |
string | Não | Padrão: pt_BR |
body_params |
array de strings | Não | Valores das variáveis {{1}}, {{2}}... na ordem |
header_image_url |
string (URL) | Não | URL pública de imagem se o template tiver header de imagem |
contact_id |
string (uuid) | Não | ID do contato na Wevi para usar {{contact_name}} automaticamente |
open_conversation |
string | Não | always (padrão) abre a conversa no inbox no disparo. on_reply abre só quando o contato responder |
idempotency_key |
string | Não | Chave única para evitar reenvios em caso de retry |
send-message
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
connection_id |
string (uuid) | Sim | ID da conexão WhatsApp |
to |
string | Sim | Número no formato internacional |
text |
string | Sim | Texto da mensagem (máx. 4096 caracteres) |
contact_id |
string (uuid) | Não | ID do contato na Wevi |
idempotency_key |
string | Não | Chave única para evitar reenvios |
send-conversation-message
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
conversation_id |
string (uuid) | Condicional | ID da conversa (ou use connection_id + to) |
connection_id |
string (uuid) | Condicional | ID da conexão WhatsApp, alternativa a conversation_id |
to |
string | Condicional | Telefone, usado junto com connection_id |
text |
string | Condicional | Texto ou legenda da mídia |
media |
objeto | Condicional | { url, type, mime_type, name? }, precisa de text e/ou media |
idempotency_key |
string | Não | Chave única para evitar reenvios |
Variáveis dinâmicas em templates
Se o template usa {{1}}, {{2}} etc., passe os valores em body_params na ordem:
{
"body_params": ["Maria", "15/06/2026", "14h30"]
}
Além disso, dentro do valor de qualquer variável você pode usar os marcadores especiais:
| Marcador | Substituído por |
|---|---|
{{contact_name}} |
Nome do contato na Wevi (requer contact_id) |
{{contact_phone}} |
Telefone do contato |
{{chave_do_campo}} |
Qualquer campo personalizado do contato (requer contact_id) |
Os campos personalizados são os campos extras que você criou para os contatos da sua organização (ex: plano, empresa, codigo_cliente). Você os cria e gerencia em Configurações → Campos personalizados no painel. Use a chave do campo como marcador.
Exemplo: se você tem um campo personalizado com chave plano, pode usar {{plano}} em qualquer body_params:
{
"contact_id": "uuid-do-contato",
"body_params": ["{{contact_name}}", "{{plano}}", "{{codigo_cliente}}"]
}
Se o contato não tiver o campo preenchido, o marcador é substituído por uma string vazia.
Limites de velocidade
Cada API Key tem um limite de 60 chamadas por minuto (1 por segundo em média). Ao ultrapassar, a API retorna 429 Too Many Requests com o header Retry-After indicando quantos segundos aguardar.
{ "error": "Too many requests", "retry_after": 12 }
No n8n, configure um nó Wait com o valor de retry_after antes de retentar. Em scripts próprios, leia o header Retry-After e durma esse número de segundos.
Para automações de alto volume (ex: disparar templates para uma lista grande), use campanhas em vez da API. Campanhas não têm limite de velocidade e processam em fila automaticamente.
Contatos que pediram para não receber mais
A API respeita o opt-out do contato, seguindo a mesma regra do resto da plataforma: você não pode iniciar conversa com quem pediu para sair, mas pode responder quem falou com você.
Na prática:
| Endpoint | Contato em opt-out |
|---|---|
/send-template |
Sempre bloqueado. Template existe para iniciar conversa. |
/send-message |
Bloqueado, a não ser que o contato tenha escrito nas últimas 24 horas. |
/send-conversation-message |
Bloqueado, a não ser que o contato tenha escrito nas últimas 24 horas. |
Quando bloqueia, a resposta é 403:
{
"error": "opted_out",
"reason": "opted_out",
"message": "Este contato pediu para não receber mais mensagens. Templates não podem ser enviados para ele."
}
No n8n, trate o 403 como um caminho normal do fluxo, não como falha: o contato saiu da lista e o workflow deve seguir sem ele.
Entenda o mecanismo em: Quem pediu para não receber mais mensagens →
Idempotência: evitando reenvios no n8n
O n8n pode reexecutar workflows em caso de erro de rede. Para evitar que a mesma mensagem seja enviada duas vezes, use idempotency_key:
{
"idempotency_key": "pedido-1234-confirmacao"
}
Se a chamada for repetida com a mesma chave, a Wevi retorna o resultado do envio original sem reenviar. A chave deve ser única por organização.
Exemplo: configurando no n8n
- Adicione um nó HTTP Request
- Configure:
- Method: POST
- URL:
https://api.wevi.chat/functions/v1/send-template - Authentication: Generic Credential Type → Header Auth
- Name:
Authorization - Value:
Bearer wevi_SUACHAVEAQUI
- Name:
- Em Body, selecione JSON e monte o payload
- Para usar dados do workflow, use expressões n8n como
{{ $json.email }}nos campos
O mesmo padrão funciona em qualquer ferramenta que suporte HTTP: Make, Zapier, scripts Python, Ruby, Node, ou qualquer sistema interno.
Erros comuns
Invalid API key
A chave foi revogada ou está incorreta. Gere uma nova em Conta → Desenvolvedores.
Connection not found
O connection_id não pertence à sua organização ou foi removido.
Template não aprovado ou inexistente A Meta retorna um erro de template. Verifique o status em WhatsApp > Templates.
Janela de 24h expirada (send-message)
Mensagem de texto livre só funciona dentro da janela de atendimento ativo. Use send-template para mensagens proativas.
402: Plano não permite
API de envio requer plano Pro ou Ultra. Faça upgrade em Conta → Planos.
403: opted_out
O contato pediu para não receber mais mensagens. Veja a seção sobre opt-out acima.
O que acontece quando o contato responde
Quando o destinatário responde a um template ou texto enviado via send-template/send-message, a conversa cai na caixa de entrada do agente normalmente. O que muda é se a mensagem que você enviou fica registrada no histórico dessa conversa.
| Endpoint | O que fica no histórico da conversa |
|---|---|
/send-template |
O template enviado fica registrado. Com open_conversation: "on_reply", ele entra no histórico assim que a resposta chega, com a data do envio original |
/send-message |
O texto enviado não fica registrado, ele só aparece na aba Enviadas de Campanhas. O agente de IA não vai saber o que foi dito antes, e vai responder sem esse contexto |
Se você precisa que o agente de IA continue a conversa sabendo o que foi enviado, use `/send-conversation-message` em vez de send-message, ele grava a mensagem na própria conversa.
Sobre a escolha de abrir ou não a conversa no disparo, veja Abrir conversa a cada disparo ou só quando o contato responder.
Acompanhando os envios
Todos os envios feitos via API aparecem na aba Enviadas dentro de Campanhas, junto com os disparos de campanha. Você pode filtrar por:
- Status (enviada, entregue, lida, falha)
- Origem (campanha ou API)
- Tipo (template ou texto)
- Período
O status é atualizado em tempo real conforme a Meta confirma a entrega e leitura.
Próximos passos
- Como criar e gerenciar campanhas no WhatsApp →
- O que são templates e como aprovar →
- Como usar variáveis nas campanhas →
- Quem pediu para não receber mais mensagens →
Veja também: Conectar a Wevichat ao n8n, que traz um bloco pronto de envio, e Conectar a Wevichat a outros sistemas para o quadro geral das integrações.