Enviar mensagem
/v1/instances/{id}/messagesdesde M2token da instância ou adminQuando usar
Valida e grava a mensagem na fila persistente da instância. Sem wait, responde 202 com status: queued. Com ?wait=true, espera o resultado por até timeout (padrão 30s, no máximo 2m): 200 quando enviada, erro quando falhou, ou 202 com o status atual (queued/in_flight) se o tempo acabar; a mensagem continua na fila.
Tipos: text, image, video, audio (media.ptt: true = mensagem de voz), document, reaction. to aceita número com DDI (10 a 15 dígitos) ou JID (@s.whatsapp.net, @g.us, @lid). Mídia por media.url (o servidor baixa, IPs privados bloqueados) ou media.base64. Limites: imagem 16MB, vídeo/áudio 64MB, documento 100MB, corpo 140MB, texto 64KB.
Idempotência: client_message_id (até 128 caracteres) repetido devolve a mesma mensagem; repetido com outro conteúdo responde 409 conflict.
Autenticação
Aceita o token da instância (só a própria instância) ou o token admin. Um token de outra instância recebe 403 forbidden (ou 404 not_found em webhooks de outra instância).
Parâmetros
Caminho
| Nome | Tipo | Descrição |
|---|---|---|
idobrigatório | string | Id da instância (inst_...). |
Query
| Nome | Tipo | Descrição |
|---|---|---|
wait | "true" | true espera o envio terminar (modo síncrono). |
timeout | string | Duração Go (30s, 90s, 2m). Padrão 30s, teto efetivo 2m. Só com wait=true. |
Corpo (JSON)
| Nome | Tipo | Descrição |
|---|---|---|
toobrigatório | string | Número com DDI (10 a 15 dígitos) ou JID. |
typeobrigatório | "text" | "image" | "video" | "audio" | "document" | "reaction" | |
text | string | Obrigatório em text (até 64KB). |
caption | string | Legenda de image, video e document. |
media | MediaInput | Informe url ou base64. |
media.url | string | http(s) público; o servidor baixa (timeout 30s, sem IPs privados). |
media.base64 | string | |
media.mime | string | |
media.file_name | string | Até 255 bytes. |
media.ptt | boolean | Áudio como mensagem de voz. |
media.url | string | http(s) público; o servidor baixa (timeout 30s, sem IPs privados). |
media.base64 | string | |
media.mime | string | |
media.file_name | string | Até 255 bytes. |
media.ptt | boolean | Áudio como mensagem de voz. |
reaction | object | |
reaction.message_id | string | Id LiteZap ou wa_message_id de uma mensagem do chat. |
reaction.emoji | string | Vazio remove a reação. |
client_message_id | string | Chave de idempotência. (até 128) |
expires_after | string | Duração entre 1m e 168h (padrão 24h). Não enviada até lá: message_expired. |
Exemplo
curl -s -X POST "$LITEZAP_URL/v1/instances/$ID/messages?wait=true" \ -H "Authorization: Bearer $LITEZAP_TOKEN" \ -d '{"to":"5511999999999","type":"text","text":"Olá! Seu pedido saiu para entrega.","client_message_id":"pedido-123"}'const res = await fetch("http://localhost:8787/v1/instances/inst_7f3a9c2e5b1d4086/messages?wait=true", { method: "POST", headers: { Authorization: `Bearer ${process.env.LITEZAP_TOKEN}`, "Content-Type": "application/json" }, body: JSON.stringify({ "to": "5511999999999", "type": "text", "text": "Olá! Seu pedido saiu para entrega.", "client_message_id": "pedido-123" }),});console.log(res.status, res.status === 204 ? "" : await res.json());import osimport requests
r = requests.post( "http://localhost:8787/v1/instances/inst_7f3a9c2e5b1d4086/messages", headers={"Authorization": f"Bearer {os.environ['LITEZAP_TOKEN']}"}, params={ "wait": "true", }, json={ "to": "5511999999999", "type": "text", "text": "Olá! Seu pedido saiu para entrega.", "client_message_id": "pedido-123", }, timeout=150,)print(r.status_code, r.json() if r.content else "")package main
import ( "fmt" "io" "net/http" "os" "strings")
func main() { req, _ := http.NewRequest("POST", "http://localhost:8787/v1/instances/inst_7f3a9c2e5b1d4086/messages?wait=true", strings.NewReader(`{"to":"5511999999999","type":"text","text":"Olá! Seu pedido saiu para entrega.","client_message_id":"pedido-123"}`)) req.Header.Set("Authorization", "Bearer "+os.Getenv("LITEZAP_TOKEN")) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(resp.Status, string(out))}<?phprequire 'vendor/autoload.php'; // composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client(['base_uri' => 'http://localhost:8787']);$res = $client->request('POST', '/v1/instances/inst_7f3a9c2e5b1d4086/messages', [ 'headers' => ['Authorization' => 'Bearer ' . getenv('LITEZAP_TOKEN')], 'query' => [ 'wait' => 'true', ], 'json' => [ 'to' => '5511999999999', 'type' => 'text', 'text' => 'Olá! Seu pedido saiu para entrega.', 'client_message_id' => 'pedido-123', ], 'http_errors' => false,]);echo $res->getStatusCode(), ' ', $res->getBody(), PHP_EOL;Outros corpos de exemplo
{ "to": "5511999999999", "type": "image", "caption": "Comprovante", "media": { "url": "https://exemplo.com/comprovante.jpg" }}{ "to": "5511999999999", "type": "audio", "media": { "base64": "T2dnUwACAAAAAAAA...", "mime": "audio/ogg; codecs=opus", "ptt": true }}{ "to": "5511999999999", "type": "document", "caption": "Segue o boleto", "media": { "url": "https://exemplo.com/boleto.pdf", "file_name": "boleto.pdf" }}{ "to": "5511999999999", "type": "reaction", "reaction": { "message_id": "msg_a41c9e07d2b35f68", "emoji": "👍" }}Nos exemplos, LITEZAP_URL é a URL base (ex.: http://localhost:8787) e o token vem deLITEZAP_TOKEN (instância) ou LITEZAP_ADMIN_TOKEN.
Resposta
200 Enviada (com ?wait=true). Traz wa_message_id.
Campos de Message
id | string | |
client_message_id | string | |
wa_message_id | string | |
chat | string | |
sender | string | |
from_me | boolean | |
source | "contact" | "api" | "device" | "history" | |
type | string | |
text | string | |
media | MediaInfo | |
media.id | string | Id da mídia recebida. |
media.kind | string | |
media.mime | string | |
media.size | integer | |
media.file_name | string | |
media.seconds | integer | |
media.ptt | boolean | |
media.url | string | Caminho da API para baixar (mídia recebida). |
reaction_to | string | |
status | "queued" | "in_flight" | "sent" | "delivered" | "read" | "played" | "failed" | "received" | "pending" | |
attempts | integer | |
error | string | Último erro (codigo: detalhe) de item não enviado. |
timestamp | string |
{ "id": "msg_a41c9e07d2b35f68", "client_message_id": "pedido-123", "wa_message_id": "3EB0A1B2C3D4E5F6A7B8C9", "from_me": true, "source": "api", "type": "text", "text": "Olá! Seu pedido saiu para entrega.", "status": "sent", "timestamp": "2026-10-17T13:50:03Z"}202 Na fila (queued) ou em envio (in_flight).
Campos de Message
id | string | |
client_message_id | string | |
wa_message_id | string | |
chat | string | |
sender | string | |
from_me | boolean | |
source | "contact" | "api" | "device" | "history" | |
type | string | |
text | string | |
media | MediaInfo | |
media.id | string | Id da mídia recebida. |
media.kind | string | |
media.mime | string | |
media.size | integer | |
media.file_name | string | |
media.seconds | integer | |
media.ptt | boolean | |
media.url | string | Caminho da API para baixar (mídia recebida). |
reaction_to | string | |
status | "queued" | "in_flight" | "sent" | "delivered" | "read" | "played" | "failed" | "received" | "pending" | |
attempts | integer | |
error | string | Último erro (codigo: detalhe) de item não enviado. |
timestamp | string |
{ "id": "msg_a41c9e07d2b35f68", "client_message_id": "pedido-123", "from_me": true, "source": "api", "type": "text", "text": "Olá! Seu pedido saiu para entrega.", "status": "queued", "timestamp": "2026-10-17T13:50:00Z"}Erros
| Código | HTTP | Retentável | O que fazer |
|---|---|---|---|
validation_failed | 400 | não | Corrija o corpo ou os parâmetros; a message diz o campo. |
invalid_number | 400 | não | O número não tem WhatsApp. Não reenvie; confira com check-numbers. |
unauthorized | 401 | não | Envie Authorization: Bearer <token> válido. |
forbidden | 403 | não | Use o token certo (admin, ou o da própria instância). |
instance_not_found | 404 | não | Confira o id da instância. |
conflict | 409 | não | O recurso está num estado que não permite a operação; veja a message. |
instance_not_connected | 409 | depende | Confira o estado da instância; se logged_out, pareie de novo. |
instance_banned | 409 | não | Número banido: apague a instância. |
message_expired | 410 | não | Não saiu antes de expires_after; envie de novo se ainda fizer sentido. |
media_too_large | 413 | não | Reduza o arquivo (imagem 16MB, vídeo/áudio 64MB, documento 100MB). |
media_fetch_failed | 422 | sim | Confira se a URL é pública e responde; tente de novo. |
worker_error | 502 | sim | Tente de novo com backoff; se persistir, veja o log do servidor. |
rate_limited | 503 | sim | Espere e tente de novo com backoff. |
shutting_down | 503 | sim | O servidor está reiniciando; tente de novo em alguns segundos. |
worker_timeout | 504 | sim | Tente de novo; a instância pode estar sobrecarregada ou reconectando. |
Todo erro usa o envelope {"error":{"code","message","retryable"}}. Tabela completa em Erros.
Eventos gerados
Equivalente na Z-API: Enviar texto, imagem, áudio, vídeo, documento, reação. Veja Migrar da Z-API.
Outras operações de Mensagens: Consultar mensagem · Listar a fila · Esvaziar a fila · Cancelar item da fila · Favoritar mensagem

