Dev

Enviar mensagem de WhatsApp por API com curl: exemplos prontos

Para enviar uma mensagem de WhatsApp por API com curl, faça um POST em /api/v1/{instanceId}/send/text com os cabeçalhos x-api-key e x-api-secret e um JSON com number (com DDI, só dígitos) e text. A resposta traz messageId e status. Este guia vai do primeiro envio até uma lista com intervalo, e cada comando pode ser copiado e rodado no terminal. Para Node, Python e PHP, veja os guias de Node.js em 5 minutos, Python e PHP com cURL.

Publicado em · 4 min de leitura

Este artigo também está disponível em: English · Español

O que você precisa antes de começar

Uma conta no ZapZap, uma instância conectada por QR code, a chave e o segredo da API (no painel, em Configurações e API) e o ID da instância. A autenticação usa só dois cabeçalhos, sem OAuth. Guarde as três informações em variáveis de ambiente para não colar segredo em comando nem deixar no histórico do terminal.

O teste do segundo comando devolve só o código HTTP: 200 indica que a chave e o segredo estão certos; 401 indica que um deles está errado.

Variáveis e teste de credencial

# Keep credentials out of the command and out of the shell history
export ZAPZAP_INSTANCE="your-instance-id"
export ZAPZAP_API_KEY="your-api-key"
export ZAPZAP_API_SECRET="your-api-secret"

# Quick check: a 401 here means key or secret is wrong, not the instance
curl -s -o /dev/null -w "%{http_code}\n" "https://api.zapzapapi.com/api/v1/account" \
  -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET"

O primeiro envio: mensagem de texto

O número vai com DDI e só dígitos, sem +, espaços ou traços: 5511999999999 para um celular de São Paulo. O corpo mínimo tem number e text. A resposta síncrona traz o messageId e o status, que guardam o rastro da mensagem no seu sistema.

Por padrão, a API exibe o 'digitando...' proporcional ao tamanho do texto antes de enviar, o que humaniza o envio. Se precisar de resposta mais rápida, envie digitando como false; para atrasar o envio em milissegundos, use delay.

curl: texto

curl -X POST "https://api.zapzapapi.com/api/v1/$ZAPZAP_INSTANCE/send/text" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ZAPZAP_API_KEY" \
  -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -d '{"number":"5511999999999","text":"Hello! Your order left for delivery."}'
# Expected answer: {"messageId":"ABCDEF123456","status":"sent"}

Enviar imagem e PDF

O endpoint /send/media recebe o tipo (image, video, audio, document, sticker e outros) e a URL pública do arquivo no campo file. Em imagem e vídeo, o campo text vira legenda. Em documento, docName é obrigatório e vira o nome do arquivo que o cliente vê.

Se a URL não for pública, o envio falha: o arquivo precisa estar acessível sem login. Para arquivos privados, gere um link temporário assinado no seu storage.

curl: mídia

# Image with caption (the file must be a public URL)
curl -X POST "https://api.zapzapapi.com/api/v1/$ZAPZAP_INSTANCE/send/media" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -d '{"number":"5511999999999","type":"image","file":"https://example.com/promo.jpg","text":"This week offer"}'

# PDF: type document, and docName is required
curl -X POST "https://api.zapzapapi.com/api/v1/$ZAPZAP_INSTANCE/send/media" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -d '{"number":"5511999999999","type":"document","file":"https://example.com/quote.pdf","docName":"quote.pdf"}'

Receber a resposta do cliente com webhook

Enviar é metade do caminho. Registre uma URL HTTPS pública no endpoint de webhook da instância e a API passa a fazer POST nela a cada evento, como mensagem recebida e mudança de status. Use excludeMessages para não receber de volta as mensagens que você mesmo enviou.

Durante o desenvolvimento, uma URL local não recebe nada. Veja por que o webhook não chega no localhost e, para produção, idempotência e retry no webhook.

curl: webhook

# Receive replies: register your HTTPS URL on the instance
curl -X PUT "https://api.zapzapapi.com/api/v1/instances/$ZAPZAP_INSTANCE/webhook" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET" \
  -d '{"webhook_url":"https://yoursite.com/webhook","events":"messages,status","excludeMessages":true}'

Uma lista pequena, no ritmo certo

O script abaixo lê um CSV (número e nome) e manda uma mensagem por vez, com pausa aleatória de 8 a 20 segundos entre elas. Nunca em paralelo. É o padrão de menor risco para uma lista de quem já pediu para receber, e serve para lembrete e confirmação, não para campanha fria.

Nenhum intervalo elimina o risco de bloqueio, porque a ZapZap usa um canal não oficial. Para volumes maiores, leia o guia de disparo em massa e o de anti-bloqueio.

bash: lista com intervalo

# Small list, human pace: one message every 8 to 20 seconds, never in parallel
while IFS=, read -r number name; do
  curl -s -X POST "https://api.zapzapapi.com/api/v1/$ZAPZAP_INSTANCE/send/text" \
    -H "Content-Type: application/json" \
    -H "x-api-key: $ZAPZAP_API_KEY" -H "x-api-secret: $ZAPZAP_API_SECRET" \
    -d "{\"number\":\"$number\",\"text\":\"Hi $name, your appointment is tomorrow. Reply 1 to confirm.\"}" \
    -w " -> HTTP %{http_code}\n"
  sleep $(( (RANDOM % 13) + 8 ))
done < contacts.csv

Erros mais comuns e como ler a resposta

401: chave ou segredo errados, ou cabeçalho com nome trocado. 404: o ID da instância está errado ou foi colado duas vezes na URL. 400: corpo inválido, como number com letras ou campo obrigatório ausente. 429 e 5xx: erro transitório, vale tentar de novo com espera crescente; 400, 401 e 403 não melhoram repetindo.

Se a API respondeu 'sent' e o cliente não recebeu, o problema costuma estar depois do envio. Veja WhatsApp enviado e cliente não recebe. A referência completa de campos está em enviar mensagem e em referência da API.

Resumo rápido

  • Um POST em /send/text com x-api-key, x-api-secret, number (DDI, só dígitos) e text envia a mensagem.
  • Credenciais em variáveis de ambiente, nunca coladas no comando.
  • Mídia exige URL pública no campo file; documento exige docName.
  • Lista pequena: uma mensagem por vez, com pausa aleatória, só para quem pediu para receber.

Perguntas frequentes

Como enviar uma mensagem de WhatsApp por API com curl?

Faça um POST em https://api.zapzapapi.com/api/v1/{instanceId}/send/text com os cabeçalhos x-api-key, x-api-secret e Content-Type application/json, e o corpo {number, text}. O number leva DDI e só dígitos.

O número precisa de + ou de espaços?

Não. Use só dígitos com DDI, como 5511999999999. Para limpar listas inteiras, use o formatador em lote de números da área de ferramentas.

Posso enviar imagem e PDF pelo curl?

Sim, pelo endpoint /send/media, com type image ou document e a URL pública do arquivo em file. No documento, informe docName.

Como recebo a resposta do cliente?

Registre a URL HTTPS do seu servidor com PUT em /api/v1/instances/{id}/webhook. A API faz POST nela a cada evento de mensagem e de status.

É seguro disparar uma lista inteira com um loop?

Só uma lista pequena, de quem pediu para receber, com pausa entre mensagens. O canal é não oficial e nenhum intervalo elimina o risco de bloqueio. Para volume, siga os guias de anti-bloqueio.

Rode o primeiro curl hoje

Crie a conta, conecte o número por QR code e copie o comando do guia. R$15 por número ativo ao mês, sem cobrança por mensagem.