Listar templates do WhatsApp, enviar um template aprovado, ver a fila de conversas aguardando atendimento e acompanhar uma transmissão, com curl, steel CLI e SDK.
Nesta página
Todas as rotas desta página exigem um token com o módulo Comunicação e
rodam com as suas permissões na Comunicação. Os exemplos usam $STEEL_URL e
$STEEL_TOKEN (veja Antes da primeira chamada).
Operação
Rota
Escopo
CLI
SDK
Listar templates
GET /api/v1/whatsapp/templates
api:read
steel zap templates
whatsapp.templates()
Enviar template
POST /api/v1/whatsapp/messages/template
api:write
steel zap send
whatsapp.sendTemplate()
Conversas aguardando
GET /api/v1/whatsapp/conversations/waiting
api:read
—
—
Situação da transmissão
GET /api/v1/whatsapp/broadcasts/{broadcastId}
api:read
steel zap broadcast status
whatsapp.broadcast()
A v1 envia só templates (os modelos aprovados pela Meta), que valem a
qualquer hora. Texto livre numa conversa fica no aplicativo; na API oficial da
Meta ele só é aceito dentro da janela de 24 horas depois da última mensagem do
cliente. A fila de conversas sem atendente está em
Conversas aguardando atendimento.
Listar templates
Os templates das conexões do workspace. Por padrão, só os aprovados pela
Meta.
Parâmetro
Valores
status
APPROVED (padrão), PENDING, REJECTED, PAUSED, DISABLED ou ALL
components é o formato da Cloud API da Meta: as variáveis do corpo aparecem
como {{1}}, {{2}} (ou com nome, {{nome}}). quality é a nota de
qualidade da Meta: GREEN, YELLOW, RED ou UNKNOWN. Um template em
PAUSED ou DISABLED não envia.
steel zap templates # aprovados
steel zap templates --status todos # todos; também pendente, rejeitado, pausado, desativado
Envia um template aprovado. Diga para onde de uma de três formas:
Destino
Campos
Conversa usada
Um número
to (E.164, +5511999990000) e, se houver mais de uma conexão, connectionId
Acha ou cria o contato; usa a conversa aberta dele ou abre uma
Um contato do Steel
contactId + connectionId
A conversa aberta do contato, ou uma nova
Uma conversa
conversationId
Ela mesma
Sem connectionId com to, o Steel usa a única conexão do workspace (ou a
única conectada, se houver várias). Sempre obrigatórios: templateName e
language (por exemplo pt_BR, como na lista de templates).
As variáveis vão em components, no formato da Cloud API:
status começa em SENT e muda para DELIVERED, READ ou FAILED conforme
a Meta avisa; a mensagem aparece na conversa do aplicativo com você como autor.
Para saber quando o cliente responde, assine o evento de webhook
communication.message.received (eventos).
Variáveis com nome usam parameter_name; as do cabeçalho vão num componente
header:
O CLI monta components para você, a partir do template: --var 1=Ana para
{{1}}, --var nome=Ana para {{nome}} e --var header.1=Outubro para o
cabeçalho. Uma variável que o template não tem é erro de uso; no terminal, as
que faltarem são perguntadas.
const sent = await steel.whatsapp.sendTemplate({
to: '+5511999990000',
templateName: 'boas_vindas',
language: 'pt_BR',
components: [{ type: 'body', parameters: [{ type: 'text', text: 'Ana' }] }],
})
if (!sent.ok && sent.error.code === 'RATE_LIMITED') {
// espere sent.error.retryAfterSeconds e tente de novo
}
Limites do envio
20 mensagens por minuto por conexão, somando todos os envios do
workspace por ela. Passou, 429 RATE_LIMITED com Retry-After.
A cota mensal de mensagens e a de conversas do plano. Esgotada,
402 WHATSAPP_MESSAGE_LIMIT_REACHED ou 402 WHATSAPP_CONVERSATION_LIMIT_REACHED
até o mês virar ou o plano mudar.
Só conexões da Meta (Cloud API) enviam template. Uma conexão Z-API
responde 502 WHATSAPP_PROVIDER_ERROR.
Erros
Erro
Quando e o que fazer
422 VALIDATION_ERROR "O workspace tem mais de uma conexão do WhatsApp: informe connectionId."
Envio por to sem connectionId num workspace com várias conexões conectadas
422 VALIDATION_ERROR
Faltou templateName ou language, número fora do E.164 ou nenhum destino
A IA está atendendo a conversa. Tire a conversa do atendimento da IA no aplicativo e envie de novo
502 WHATSAPP_PROVIDER_ERROR
A Meta recusou: template não aprovado nesse idioma, variáveis a mais ou a menos, número sem WhatsApp, ou conexão Z-API. A mensagem traz o motivo quando a Meta informa
429 RATE_LIMITED
20 por minuto por conexão, ou o limite do token. Espere o Retry-After
Um 502 não deve ser repetido igual: corrija o template ou as variáveis
primeiro. Um 429 pode ser repetido depois da espera.
Conversas aguardando atendimento
A Fila da caixa de entrada: conversas abertas (NEW ou IN_PROGRESS),
não arquivadas e sem responsável, da que espera há mais tempo para a mais
recente (pela última mensagem). Vale a visibilidade das Equipes do dono do
token: ele vê a fila geral e as filas das equipes de que participa; o dono do
workspace, e administradores fora de equipes, veem todas. Conversas que a IA
está atendendo também aparecem, com aiActive: true.
Para ser avisado quando uma conversa entra na fila, em vez de consultar esta
rota de tempos em tempos, assine o webhook
communication.conversation.waiting.
Acompanhar uma transmissão
Uma transmissão (disparo em massa) é criada no aplicativo, em Comunicação ›
Transmissões. Pela v1 você acompanha o andamento: os contadores e cada
destinatário com o status de envio.
status da transmissão: DRAFT, QUEUED, RUNNING, DONE ou FAILED.
Cada destinatário: PENDING, SENT, FAILED ou SKIPPED (por exemplo,
contato descadastrado pela LGPD).
steel zap broadcast status cm2brd0001
const b = await steel.whatsapp.broadcast('cm2brd0001')
if (b.ok) console.log(`${b.data.sentCount}/${b.data.recipientCount}`)
Erro: 404 WHATSAPP_BROADCAST_NOT_FOUND.
Receita: aviso de pedido despachado pelo seu ERP
async function avisarDespacho(telefone: string, nome: string, pedido: string) {
const sent = await steel.whatsapp.sendTemplate({
to: telefone, // '+5511999990000'
connectionId: process.env.STEEL_ZAP_CONNECTION,
templateName: 'pedido_despachado', // aprovado na Meta, com {{1}} e {{2}}
language: 'pt_BR',
components: [{
type: 'body',
parameters: [
{ type: 'text', text: nome },
{ type: 'text', text: pedido },
],
}],
})
if (sent.ok) return sent.data.id
if (sent.error.code === 'RATE_LIMITED') {
await new Promise((r) => setTimeout(r, (sent.error.retryAfterSeconds ?? 5) * 1000))
return avisarDespacho(telefone, nome, pedido)
}
throw new Error(`${sent.error.code}: ${sent.error.message}`)
}
Para muitos destinatários de uma vez, prefira uma transmissão no aplicativo: ela
respeita os limites sozinha e mostra o andamento.
Solução de problemas
Sintoma
O que fazer
A lista de templates vem vazia
Nenhum template aprovado ainda. Veja todos com status=ALL; os pendentes dependem da Meta
502 com um template aprovado
O idioma (language) precisa ser exatamente o do template, e o número de variáveis tem de bater com o do corpo
A mensagem não aparece na caixa de entrada
Foi enviada numa conversa nova do contato; procure pelo número. Se a conexão estava desconectada, o envio falha com 502
O cliente não recebeu, mas o envio deu 201
O status da mensagem muda depois; consulte a conversa no aplicativo. FAILED costuma ser número sem WhatsApp ou bloqueio de qualidade da Meta