Mensagens
Envie texto e mídia para um contato dentro da janela de 24 horas e consulte o status de uma mensagem.
Use POST /messages/send para responder um cliente que falou com a loja nas últimas 24 horas. Para falar com quem não escreveu, use um modelo aprovado.
A janela de 24 horas
O WhatsApp só aceita mensagens livres (texto, foto, vídeo, áudio, documento) até 24 horas depois da última mensagem do cliente. Cada mensagem nova do cliente reabre a janela por mais 24 horas.
| Situação | O que acontece |
|---|---|
| Mariana escreveu há 3 horas | A mensagem sai |
| Mariana escreveu há 26 horas | 422 whatsapp_window_closed: nada é enviado nem gravado |
| Contato importado que nunca escreveu | 422 whatsapp_window_closed |
Para saber antes de enviar, olhe o campo lastInboundAt do contato: a janela está aberta se ele for de menos de 24 horas atrás.
POST /messages/send
Envia uma mensagem de texto, ou uma mídia com legenda, para um contato. Acesso: chave secreta com Leitura e escrita.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
contactId | string (UUID) | Sim | O contato que recebe |
content | string | Sim | O texto, até 20.000 caracteres. Com mediaUrl, vira a legenda |
mediaUrl | string | Não | Link público (http:// ou https://) do arquivo. O WhatsApp baixa o arquivo desse link |
mediaType | string | Não | Tipo MIME (image/jpeg, video/mp4, audio/ogg, application/pdf) ou só image, video, audio, document. Sem ele, ou com outro valor, a mídia vai como documento |
curl -X POST https://vamo.ai/api/v1/messages/send \
-H "Authorization: Bearer sk_live_SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{
"contactId": "2c9d8e7f-6a5b-4c3d-9e2f-1a0b9c8d7e6f",
"content": "Oi, Mariana! Seu iPhone 15 saiu para entrega hoje. Código de rastreio: BR123456789.",
"mediaUrl": "https://lojaaurora.com.br/notas/pedido-1042.pdf",
"mediaType": "application/pdf"
}'Resposta 201
{
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"conversationId": "5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716",
"senderType": "human",
"content": "Oi, Mariana! Seu iPhone 15 saiu para entrega hoje. Código de rastreio: BR123456789.",
"mediaUrl": "https://lojaaurora.com.br/notas/pedido-1042.pdf",
"mediaType": "application/pdf",
"waMessageId": "wamid.HBgNNTUxMTk4NzY1NDMyMRUCABEYEjQ1",
"status": "sent",
"source": "api",
"createdAt": "2026-10-31T13:20:05.000Z"
}
}status: "sent" quer dizer que o WhatsApp aceitou a mensagem. Entregue e lida chegam depois: consulte GET /messages/:id ou assine os webhooks message.delivered e message.failed.
O que acontece ao enviar
- A conversa. Cada contato tem uma única conversa. Se ela estava fechada ou adiada, é reaberta; se não existia, é criada (e dispara
conversation.created). - A mensagem aparece na caixa de entrada como enviada pela equipe, com origem
api. Ela dispara o webhookmessage.created. - A IA continua cuidando da conversa. Um envio pela API não conta como uma pessoa assumindo: a IA segue respondendo o cliente. Se havia um rascunho da IA esperando aprovação, ele é descartado, porque a sua mensagem passou a ser a mais recente.
- Textos longos. Um texto com mais de 4.096 caracteres (o limite do WhatsApp) sai em várias mensagens, cortadas em parágrafos ou frases. Na API ele continua sendo uma mensagem só.
- Falhas. Se o WhatsApp recusar, a resposta traz o erro (veja abaixo) e a tentativa fica gravada como
failedna conversa, com o motivo. Se a recusa for antes de chegar ao WhatsApp (janela fechada, contato sem número), nada é gravado.
Repita com Idempotency-Key
Mande o cabeçalho Idempotency-Key com um valor único por mensagem. Se a requisição cair por tempo esgotado, repita com a mesma chave: se a primeira já tinha enviado, a mensagem não sai de novo e você recebe a mesma resposta. Veja Idempotência.
Erros
| Status | Código | Quando |
|---|---|---|
400 | validation_error | Falta contactId ou content, contactId não é UUID, content passa de 20.000 caracteres, mediaUrl não é um link http(s) |
404 | not_found | Contact not found: o contato não existe ou é de outra organização |
422 | whatsapp_window_closed | A janela de 24 horas está fechada. Envie um modelo |
422 | whatsapp_recipient_unavailable | O número não recebe WhatsApp, ou o contato não tem número |
409 | whatsapp_busy | Outra mensagem para o mesmo contato está saindo agora. Tente em alguns segundos |
409 | whatsapp_not_connected | O WhatsApp da loja não está conectado |
429 | whatsapp_rate_limited | Limite de envio do WhatsApp. Espere os segundos de Retry-After |
402 | whatsapp_billing | O WhatsApp recusou por cobrança |
502 | whatsapp_upstream_error | O WhatsApp não processou. Tente mais tarde |
Os erros vêm no formato de sempre:
{
"error": {
"code": "whatsapp_window_closed",
"message": "The 24-hour customer service window is closed. Send an approved template instead."
}
}A lista completa está em Erros.
GET /messages/:id
Consulta uma mensagem, com o status atual e o motivo de uma falha. Acesso: chave secreta (leitura).
curl https://vamo.ai/api/v1/messages/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d \
-H "Authorization: Bearer sk_live_SUA_CHAVE"Resposta 200
{
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"conversationId": "5e4d3c2b-1a09-4f8e-8d7c-6b5a49382716",
"senderType": "human",
"content": "Oi, Mariana! Seu iPhone 15 saiu para entrega hoje. Código de rastreio: BR123456789.",
"mediaUrl": "https://lojaaurora.com.br/notas/pedido-1042.pdf",
"mediaType": "application/pdf",
"status": "read",
"source": "api",
"waMessageId": "wamid.HBgNNTUxMTk4NzY1NDMyMRUCABEYEjQ1",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-10-31T13:20:05.000Z"
}
}Quando status é failed, errorCode traz o código do WhatsApp (por exemplo 131047, janela fechada) e errorMessage a explicação. Rascunhos da IA que ainda esperam aprovação, ou que foram descartados, respondem 404.
Campos da mensagem
| Campo | Valores |
|---|---|
senderType | customer (o cliente), ai (o agente de IA), human (a equipe ou a API) |
status | sending, sent, delivered, read, failed |
source | chat (a conversa normal: cliente, IA e caixa de entrada), api, automation, campaign, business_app (enviada pelo app WhatsApp Business no celular) |