Avisar sobre um pedido
Do evento no ERP à mensagem no WhatsApp do cliente.
Um evento no seu ERP — pedido despachado, boleto vencendo, entrega concluída — vira uma mensagem no WhatsApp do cliente. São três chamadas, e a terceira é a que envia.
O fluxo
Pedido despachado no ERP
↓
1. encontre (ou crie) o contato POST /v1/contacts external_id
↓
2. encontre (ou abra) a conversa POST /v1/conversations external_id
↓
3. envie POST /v1/messages Idempotency-Key
↓
4. acompanhe webhook message.delivered | message.failed
Os dois external_id fazem o trabalho pesado: eles tornam os passos 1 e 2 seguros de repetir, e o Idempotency-Key cuida do passo 3.
O código
async function avisarSobreOPedido(pedido) {
// 1. O contato. Repetir devolve o mesmo — sem tabela de-para.
const contato = await amivu("/v1/contacts", {
method: "POST",
body: {
external_id: `cliente-${pedido.clienteId}`,
name: pedido.clienteNome,
phone: pedido.clienteTelefone,
},
});
// 2. A conversa DO PEDIDO. Um external_id por pedido mantém o histórico
// de cada um separado — e reprocessar não abre uma segunda.
const conversa = await amivu("/v1/conversations", {
method: "POST",
body: {
contact_id: contato.id,
channel_id: process.env.AMIVU_CHANNEL_ID,
external_id: `pedido-${pedido.numero}`,
metadata: { numero: pedido.numero, valor: pedido.total },
},
});
// 3. A mensagem. A chave descreve a OPERAÇÃO, não a tentativa.
return amivu("/v1/messages", {
method: "POST",
headers: { "Idempotency-Key": `pedido-${pedido.numero}-despachado` },
body: {
conversation_id: conversa.id,
type: "text",
text: `Olá, ${pedido.clienteNome}! Seu pedido #${pedido.numero} saiu para entrega.`,
},
});
}
Acompanhar o resultado
A resposta do envio é queued: aceita por nós, ainda não pelo canal. O que aconteceu de verdade chega por webhook.
app.post("/webhooks/amivu", async (req, res) => {
if (!assinaturaValida(req)) return res.status(401).end();
res.status(200).end();
const { type, data } = req.body;
const pedido = data.conversation?.external_id;
if (!pedido) return;
if (type === "message.delivered") {
await marcarAvisoEntregue(pedido);
}
if (type === "message.failed") {
// O código é do provedor e quase sempre pede AÇÃO, não retentativa.
await abrirTarefaDeContato(pedido, data.message.error);
}
if (type === "message.received") {
// O cliente respondeu: leve para o time, não para o robô.
await notificarAtendimento(pedido, data.message.text);
}
});
A janela de 24 horas
No WhatsApp oficial, mensagem livre só sai dentro de 24 horas desde a última mensagem do cliente. Fora disso, o canal exige um modelo aprovado.
Descubra se o canal tem essa restrição lendo capabilities.session_window em GET /v1/channels/{id}. Onde ela existe, o envio fora da janela é recusado pelo provedor e você recebe message.failed com o motivo.
Veja Canais e capacidades.
Escrevemos sobre operação de atendimento, canais e IA no blog da Amivu.