Pular para o conteúdo principal

Enviar uma mensagem de WhatsApp

POST https://pilotstatus.com.br/v1/messages/send
Este é o único endpoint de envio. Ele suporta três modos de nível superior mutuamente exclusivos:
  1. Envio de templatetemplateId (+ variables opcional)
  2. Envio de texto livretext
  3. Envio de mídia diretamedia + mediaType (sem templateId, sem text)
Exatamente um modo deve ser usado por requisição. Não existem endpoints separados /messages/text, /messages/media ou /messages/interactive.

Headers

  • Content-Type: application/json
  • x-api-key: ps_... (ou x-api-key-id: <api_key_id>) — uma chave com escopo de número

Destino (exatamente um)

destinationNumber
string
Telefone de destino em E.164 com um + inicial (ex.: +5511999999999).
groupId
string
JID do grupo do WhatsApp terminando em @g.us.
newsletterId
string
JID do canal do WhatsApp terminando em @newsletter.

Campos de modo

templateId
string
Template do painel /templates. Mutuamente exclusivo com text e com o modo de mídia direta.
variables
object
Mapa chave→valor para as variáveis do template. Variáveis obrigatórias ausentes produzem MISSING_TEMPLATE_VARIABLES.
text
string
Corpo de uma mensagem de texto livre. Obrigatório se templateId não for enviado (e não se tratar de um envio de mídia direta).
media
string
Uma URL http(s) pública ou um data URI base64 (ex.: data:audio/ogg;base64,AAAA...) para um arquivo de imagem, vídeo, documento ou áudio. Base64 é aceito para todos os tipos de mídia em números Meta Cloud API. Em números não oficiais (Pilot Status web), base64 não é aceito — use uma URL http(s) pública. Sobrescreve qualquer mediaUrl embutido no template.
mediaType
string
image, video, document ou audio. Defina explicitamente quando a extensão da URL não for óbvia (ex.: PDFs cuja URL não termina em .pdf). Quando mediaType é audio, o arquivo é entregue como uma nota de voz (PTT) do WhatsApp em todos os provedores. Em números não oficiais (Pilot Status web), um indicador de presença “gravando áudio” é exibido logo antes da entrega; a Meta Cloud API não possui API de presença de saída, então nenhum indicador é exibido para envios de áudio pela Meta.

Envio de mídia direta

Envie mídia por conta própria fornecendo media + mediaType sem templateId e sem text. Nesse modo, buttons, header, footer e variables não são permitidos; um caption opcional é permitido para image, video e document, mas não para audio.
Envios de mídia estão disponíveis em todos os planos, incluindo o Free — eles contam na cota de mensagens do número como qualquer outra mensagem. Não há uma cobrança paga separada para enviar mídia.

Agendamento e janela de entrega

deliverAt
string
Data e hora ISO 8601 para agendar o envio.
deliverUntil
string
Prazo ISO 8601 para a entrega. Se expirar, a mensagem falha (veja Códigos de erro de log).

Outros campos

labels
string[]
Marque o destino com Labels (escopo do tenant). Processados de forma assíncrona. Com a chave de API retentionDays = 0, as Labels são criadas, mas a vinculação com o telefone/grupo pode não ser persistida (PII).
marketingOptions
object
Apenas para templates MARKETING. aiRewriteEnabled: true habilita a variação automática do texto final da mensagem para reduzir padrões repetitivos (anti-spam) preservando a intenção. Se a variação não puder ser aplicada, o texto original é enviado. Envios MARKETING também recebem um atraso automático de fila variável (padrão 8–25 s) para espaçar o ritmo de envio.
buttons
array
Até 3 botões que sobrescrevem os botões do template. Cada botão possui type e displayText mais campos específicos do tipo:
  • { "type": "reply", "displayText": "Yes", "id": "yes" } — resposta rápida
  • { "type": "url", "displayText": "Site", "url": "https://example.com" } — botão de URL
  • { "type": "call", "displayText": "Call", "phoneNumber": "+5511999999999" } — botão de chamada
  • { "type": "copy", "displayText": "Code", "copyCode": "ABC123" } — botão de copiar
buttons pode ser combinado com qualquer mediaType. A API não rejeita botões com mediaType: "video" ou mediaType: "document" (números não oficiais os aceitam); observe que a Meta Cloud API pode rejeitar algumas combinações de botões com vídeo/documento no momento da entrega.
header
object
Header para uma mensagem interativa de texto livre. Requer buttons. Tipos: { "type": "text", "content": "Header title" } (até 60 caracteres), ou image / video / document com uma URL pública como content.
Rodapé da mensagem (máximo 60 caracteres). Requer buttons.

Restrições de texto livre

  • media e mediaType não podem ser usados com text (texto livre).
  • header e footer só são suportados quando buttons está presente (limitação da Meta Cloud API).
  • Em números Meta, mensagens de texto livre só funcionam dentro da janela de conversa de 24h do WhatsApp. Fora da janela, um erro META_OUTSIDE_24H_WINDOW é retornado no webhook message.failed — use um template aprovado em vez disso.

Exemplos

curl -X POST "https://pilotstatus.com.br/v1/messages/send" \
  -H "Content-Type: application/json" \
  -H "x-api-key: ps_your_key_here" \
  -d '{
    "templateId": "onboarding-test",
    "destinationNumber": "+5511999999999",
    "variables": { "name": "John", "order_id": "123" }
  }'

Resposta (202)

{
  "id": "msg_abc",
  "correlationId": "corr_123",
  "status": "QUEUED",
  "createdAt": "2026-02-24T15:00:00.000Z",
  "origin": "My WhatsApp"
}
id
string
ID interno da mensagem. Persista este valor — é o valor a ser usado com GET /v1/messages/{id} e corresponde a internalMessageId nos webhooks.
correlationId
string
Identificador de correlação para a requisição de envio.
status
string
Sempre QUEUED na aceitação.

Correlação com webhooks

  • O campo id na resposta é o mesmo que internalMessageId em message.sent, message.delivered, message.read e message.failed, e corresponde a messageRepliedId em message.reply quando a plataforma vincula a resposta ao seu envio.
  • O messageId do WhatsApp (wamid) não está no corpo do 202; ele aparece pela primeira vez no webhook message.sent (e se repete nos eventos de status daquela mensagem).
  • Persista id quando receber o 202 e use GET /v1/messages/{id} com o mesmo valor.

Erros comuns

StatusSignificado
400Payload inválido (ex.: telefone fora do E.164, campos obrigatórios ausentes, MISSING_TEMPLATE_VARIABLES, ou texto livre não suportado pelo provedor: code: FREE_FORM_NOT_SUPPORTED)
401Header de chave de API ausente/inválido (x-api-key / x-api-key-id)
403Uma chave com escopo de tenant usada em um endpoint com escopo de número
404Template não encontrado ou sem uma versão aprovada
422Cobrança do tenant suspensa (code: BILLING_SUSPENDED) — inadimplência, ou saldo WALLET / de extras não pago; regularize seus créditos ou cartão para retomar os envios
429Limite de taxa
Falhas de entrega assíncronas (ex.: META_OUTSIDE_24H_WINDOW, META_TEMPLATE_NOT_APPROVED, WHATSAPP_NOT_EXIST) aparecem via webhook message.failed e nos Logs — veja Códigos de erro de log.