Como enviar mensagem de WhatsApp por API: exemplos em curl, Node, Python e PHP
Aprenda a enviar texto, imagem e documento pela API GoZAP, escolher number ou chatid, usar a fila assíncrona e interpretar respostas HTTP com passos práticos.

Como enviar texto para um número?
Para texto, envie number ou chatid junto com text. Os dois destinos são strings; ao informar ambos, chatid prevalece. O telefone pode conter pontuação, que é removida antes da validação, e precisa resultar em 8 a 15 dígitos. Inclua os prefixos internacionais e de área, sem presumir que a API complete partes ausentes.
A instância é localizada pelo token permanente. A autenticação pode seguir no header token ou como Authorization: Bearer SEU_TOKEN. Os snippets abaixo usam a mesma URL fictícia e o mesmo corpo, para facilitar a comparação entre bibliotecas.
| Rota | O que faz |
|---|---|
POST /send/text |
Envia texto a um número ou JID de conversa. |
POST /send/media |
Envia imagem, vídeo, áudio, sticker ou documento conforme type. |
POST /send/image |
Envia imagem com o mesmo corpo de mídia, fixando o tipo como imagem. |
Corpo comum aos quatro exemplos:
{"number":"5511999999999","text":"Sua mensagem de teste"}
curl
curl -X POST 'https://SEU-DOMINIO/send/text' \
-H 'Content-Type: application/json' \
-H 'token: SEU_TOKEN' \
--data '{"number":"5511999999999","text":"Sua mensagem de teste"}'
Node.js com fetch
const response = await fetch('https://SEU-DOMINIO/send/text', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
token: 'SEU_TOKEN',
},
body: JSON.stringify({
number: '5511999999999',
text: 'Sua mensagem de teste',
}),
});
console.log(response.status, await response.json());
Python com requests
import requests
response = requests.post(
'https://SEU-DOMINIO/send/text',
headers={'token': 'SEU_TOKEN'},
json={'number': '5511999999999', 'text': 'Sua mensagem de teste'},
)
print(response.status_code, response.json())
PHP com cURL
<?php
$ch = curl_init('https://SEU-DOMINIO/send/text');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'token: SEU_TOKEN'],
CURLOPT_POSTFIELDS => json_encode([
'number' => '5511999999999',
'text' => 'Sua mensagem de teste',
]),
CURLOPT_RETURNTRANSFER => true,
]);
$body = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE) . ' ' . $body;
curl_close($ch);
Troque domínio, token e destino pelos valores da sua instância. O exemplo é para integração e não representa uma mensagem entregue ou lida por uma pessoa.
Na escolha do destino, number é prático quando seu sistema guarda o telefone do contato. Use chatid quando já possui o identificador de conversa aceito pelo serviço. A API permite os dois campos, mas a precedência do chatid torna mais claro enviar apenas aquele que corresponde à conversa desejada. Revise também a normalização de telefone antes de montar lotes: espaços, parênteses e sinais não substituem o código internacional.
Antes de colocar uma rotina em produção, registre qual instância fez a chamada, o horário, o status HTTP e o identificador retornado. Evite registrar o token nos logs. Isso ajuda a distinguir erro de autenticação, indisponibilidade da sessão e falha de validação do corpo sem armazenar credenciais junto com o histórico da aplicação.
Como enviar imagem ou documento?
Mídia usa POST /send/media. O corpo requer um destino e url ou base64; também pode indicar type, mimetype, caption e, para arquivo, fileName. Para um documento hospedado em uma URL:
curl -X POST 'https://SEU-DOMINIO/send/media' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer SEU_TOKEN' \
--data '{"number":"5511999999999","type":"document","url":"https://exemplo.invalid/arquivo.pdf","mimetype":"application/pdf","fileName":"guia.pdf","caption":"Guia solicitado"}'
O domínio exemplo.invalid é ilustrativo e precisa ser substituído por uma URL que a API consiga acessar. Para imagem, use o tipo image e uma URL ou conteúdo Base64. A rota /send/image também recebe os campos de mídia e força o tipo imagem. Não há uma rota dedicada /send/document: o tipo documento pertence a /send/media.
Os tipos aceitos incluem imagem, vídeo, áudio, áudio enviado como PTT/voz, documento e sticker. Para arquivos, forneça um tipo reconhecido e dados de mídia utilizáveis, além do destino. caption pode acompanhar a mídia; fileName serve para informar o nome do arquivo. As flags opcionais de mídia são booleanas, enquanto os demais campos listados no contrato são strings. A documentação não define um limite máximo de bytes para URL ou Base64 nesse fluxo, então não trate um tamanho escolhido pela aplicação como limite oficial da API.
Quando usar a fila assíncrona?
O fluxo padrão processa o envio de forma síncrona. Para os envios compatíveis com fila, async: true no JSON pede processamento assíncrono. O exemplo mantém destino e texto do corpo anterior:
curl -X POST 'https://SEU-DOMINIO/send/text' \
-H 'Content-Type: application/json' \
-H 'token: SEU_TOKEN' \
--data '{"number":"5511999999999","text":"Sua mensagem de teste","async":true}'
Uma resposta aceita na fila usa HTTP 202 e inclui campos como success, async, queued, job e endpoint. A consulta de estado usa GET /message/async; para limpar a fila, há DELETE /message/async. As duas rotas também exigem autenticação.
| Rota | O que faz |
|---|---|
GET /message/async |
Consulta o estado da fila assíncrona. |
DELETE /message/async |
Limpa a fila assíncrona da instância. |
O processamento na fila informa que a API aceitou o trabalho, sem confirmar entrega ao destinatário. A API não aplica rate limit HTTP às rotas /send/*; a sessão e as regras do WhatsApp ainda têm limites.
Considere guardar o campo job da resposta aceita e consultar o estado da fila de acordo com a estratégia da sua aplicação. O endpoint de leitura informa dados da fila, sem confirmar que uma mensagem será entregue. Limpar a fila é uma ação diferente de consultar seu conteúdo; aplique DELETE apenas quando a intenção operacional for remover os trabalhos pendentes daquela instância.
O que significam as respostas HTTP?
No envio síncrono, HTTP 200 representa a resposta de sucesso da operação da API. HTTP 202 indica que o trabalho foi aceito para a fila. HTTP 429 é usado quando a fila está cheia. HTTP 409 indica que o serviço ou a sessão está indisponível ou reiniciando. Trate o corpo e o status como resultado da requisição, sem convertê-los em prova de leitura ou entrega.
Na prática, diferencie os casos antes de repetir a chamada. Uma resposta 429 aponta fila cheia; aumentar tentativas sem verificar o estado pode manter o cliente pressionando uma fila sem espaço. Já 409 indica indisponibilidade ou reinício, por isso a aplicação pode tratar a condição separadamente e tentar de novo após observar a disponibilidade. O HTTP 202 também tem tratamento próprio: guarde os dados do trabalho e consulte o endpoint da fila, em vez de considerar a operação síncrona concluída.
Para acompanhar etapas da integração, registre o status HTTP e o identificador de trabalho recebido na resposta da fila. Se você também precisa consumir eventos de execução, veja o guia de webhooks e SSE da GoZAP. Para outros recursos de envio, leia grupos, comunidades, canais e status e tipos de mensagem WhatsApp API.
Quando não escolher a GoZAP
Não escolha a GoZAP se a sua política exige exclusivamente a API oficial da Meta, ou se o sistema precisa operar sem um serviço hospedado. Confirme também se a sua aplicação aceita trabalhar com o ciclo e os limites de uma sessão WhatsApp. A GoZAP conecta por Web e Mobile, dois modos nativos fora da API oficial da Meta. Veja o modo Mobile.