Messages
POST /v1/messages (envia template/texto/mídia) e GET /v1/messages/{id} (consulta status).
POST /v1/messages
Envia uma mensagem: template, text, mídia (image/video/document/audio/sticker) ou mensagem interativa (reaction/location/contact/cta_url/buttons/list).
Headers: Idempotency-Key (opcional, recomendado).
Body (JSON):
{
"to": "+5511999990000",
"type": "template",
"account_id": "ckv...",
"template": { "name": "boas_vindas", "language": "pt_BR", "components": [] }
}
| Campo | Tipo | Obrigatório | Regras |
|---|---|---|---|
to | string | Sim | E.164. Regex ^\+?[1-9]\d{7,14}$. Normalizado internamente |
type | enum | Sim | template | text | image | video | document | audio | sticker | reaction | location | contact | cta_url | buttons | list |
account_id | string | Não | Conexão; default = conexão padrão do usuário |
template | object | Não | Obrigatório se type=template. { name (≥1), language (≥1), components? } |
text | object | Não | Obrigatório se type=text. { body } — 1 a 4096 chars |
media | object | Não | Obrigatório para image/video/document/audio/sticker. { id (≥1), caption? (≤1024), filename? (≤255, só document) }. Sticker exige image/webp 512x512 |
reaction | object | Não | Obrigatório se type=reaction. { messageId, emoji } — messageId é o id da mensagem recebida (não o meta_message_id); emoji vazio remove a reação |
location | object | Não | Obrigatório se type=location. { latitude, longitude, name?, address? } |
contacts | array | Não | Obrigatório se type=contact. [{ formattedName, firstName, phones: [{ phone, type? }] }] — firstName é obrigatório (a Meta rejeita formattedName sozinho) |
ctaUrl | object | Não | Obrigatório se type=cta_url. { body, displayText, url } — url precisa ser https:// |
buttons | object | Não | Obrigatório se type=buttons. { body, buttons: [{ id, title }] } — máx 3 botões, title <=20 chars |
list | object | Não | Obrigatório se type=list. { body, buttonText, sections: [{ title?, rows: [{ id, title, description? }] }] } — máx 10 rows somando todas as sections |
carousel | object | Não | Opcional, só com type=template de template criado com componente CAROUSEL. { cards: [{ mediaId, type? }] } — type é image (default) ou video, 2 a 10 cards |
media.id é o media_id obtido em POST /v1/media.
Carrossel: para enviar um template carrossel, primeiro crie o template com componente CAROUSEL (categoria MARKETING obrigatória — UTILITY é rejeitado pela Meta com 400; templates MARKETING passam por revisão mais rigorosa, com PENDING >4h observado e sem SLA — planeje o tempo de aprovação). No envio, suba a mídia de cada card via POST /v1/media e passe os media_id em carousel.cards, na mesma ordem dos cards do template.
{
"to": "+5511999990000",
"type": "template",
"template": { "name": "promo_carousel", "language": "pt_BR" },
"carousel": { "cards": [{ "mediaId": "media_1" }, { "mediaId": "media_2" }] }
}Checagens pré-envio (nesta ordem)
- Conta existe e pertence ao dono da chave → senão
404 ACCOUNT_NOT_FOUND. - Assinatura
ACTIVEouGRACEválida → senão402 SUBSCRIPTION_REQUIRED. - Cap diário do tier não atingido → senão
429 TIER_DAILY_CAP_REACHED. - Contato não optou por sair → senão
403 CONTACT_OPTED_OUT. - Para não-template: houve inbound do contato nas últimas 24h → senão
409 WINDOW_CLOSED.
Templates aprovados ignoram a janela de 24h. Texto e mídia exigem janela aberta.
Resposta 201
Resposta 201
{
"id": "msg_ckv...",
"meta_message_id": "wamid.HBgM...",
"to": "+5511999990000",
"status": "sent"
} | Campo | Descrição |
|---|---|
id | ID interno (consultar em GET /v1/messages/{id}) |
meta_message_id | ID da mensagem na Meta (casa com os webhooks) |
to | Telefone normalizado (E.164) |
status | Sempre "sent". Mudanças de status chegam via webhook. |
Exemplo
curl -X POST https://api.wablastmessage.com/v1/messages \
-H "Authorization: Bearer wak_sua_chave" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 9f1c-7b22-aa01" \
-d '{
"to": "+5511999990000",
"type": "text",
"text": { "body": "Olá! Sua entrega chegou." }
}'import crypto from 'node:crypto';
import fetch from 'node-fetch';
const res = await fetch('https://api.wablastmessage.com/v1/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.WABLAST_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
to: '+5511999990000',
type: 'text',
text: { body: 'Olá! Sua entrega chegou.' },
}),
});
console.log(res.status, await res.json());import os, uuid, requests
res = requests.post(
'https://api.wablastmessage.com/v1/messages',
headers={
'Authorization': 'Bearer ' + os.environ['WABLAST_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={
'to': '+5511999990000',
'type': 'text',
'text': {'body': 'Olá! Sua entrega chegou.'},
},
)
print(res.status_code, res.json())<?php
$ch = curl_init('https://api.wablastmessage.com/v1/messages');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . getenv('WABLAST_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(8)),
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'to' => '+5511999990000',
'type' => 'text',
'text' => ['body' => 'Olá! Sua entrega chegou.'],
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . " " . $res; GET /v1/messages/{id}
Consulta o status de uma mensagem.
Path: id (string, obrig.) — ID interno da mensagem.
Só consulta mensagens enviadas pela API pública. Mensagens disparadas pelo painel ou por campanhas retornam 404 MESSAGE_NOT_FOUND aqui — não é bug, é escopo do endpoint.
Resposta 200
Resposta 200
{
"id": "msg_ckv...",
"status": "DELIVERED",
"meta_message_id": "wamid.HBgM...",
"sent_at": "2026-06-22T14:03:11.000Z",
"error_code": null,
"error_message": null,
"created_at": "2026-06-22T14:03:10.000Z"
} status ∈ SENT | DELIVERED | READ | FAILED. error_code/error_message preenchidos só em falha.
POST /v1/messages/{id}/read
Marca uma mensagem recebida (inbound) como lida — o contato vê o duplo-check azul.
Path: id (string, obrig.) — id da mensagem recebida (do webhook message.received), não o meta_message_id.
409 ACCOUNT_TOKEN_INVALID indica que o token da conexão está inválido — reconecte a conta antes de tentar de novo.
Resposta 200
Resposta 200
{ "success": true } Exemplo
curl -X POST https://api.wablastmessage.com/v1/messages/msg_ckv.../read \
-H "Authorization: Bearer wak_sua_chave"const res = await fetch('https://api.wablastmessage.com/v1/messages/msg_ckv.../read', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + process.env.WABLAST_API_KEY },
});
console.log(res.status, await res.json());import os, requests
res = requests.post(
'https://api.wablastmessage.com/v1/messages/msg_ckv.../read',
headers={'Authorization': 'Bearer ' + os.environ['WABLAST_API_KEY']},
)
print(res.status_code, res.json())<?php
$ch = curl_init('https://api.wablastmessage.com/v1/messages/msg_ckv.../read');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . getenv('WABLAST_API_KEY'),
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . " " . $res; POST /v1/messages/{id}/typing
Mostra “digitando…” para o contato por até 25s ou até a próxima mensagem enviada.
Path: id (string, obrig.) — id da mensagem recebida.
A Meta exige marcar a mensagem como lida na mesma chamada — este endpoint já faz isso por você. 409 ACCOUNT_TOKEN_INVALID indica token da conexão inválido.
Resposta 200
Resposta 200
{ "success": true } Exemplo
curl -X POST https://api.wablastmessage.com/v1/messages/msg_ckv.../typing \
-H "Authorization: Bearer wak_sua_chave"const res = await fetch('https://api.wablastmessage.com/v1/messages/msg_ckv.../typing', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + process.env.WABLAST_API_KEY },
});
console.log(res.status, await res.json());import os, requests
res = requests.post(
'https://api.wablastmessage.com/v1/messages/msg_ckv.../typing',
headers={'Authorization': 'Bearer ' + os.environ['WABLAST_API_KEY']},
)
print(res.status_code, res.json())<?php
$ch = curl_init('https://api.wablastmessage.com/v1/messages/msg_ckv.../typing');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . getenv('WABLAST_API_KEY'),
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . " " . $res;