IA para atender ligação no WhatsApp pela API: como montar um agente de voz
Como montar um agente de voz que atende ligações no WhatsApp pela API: webhook, áudio em tempo real por Socket.IO, transcrição, IA, voz sintética e handoff.
Para uma IA atender ligação no WhatsApp pela API, você junta quatro peças: o webhook avisa que alguém está ligando, POST /{key}/call/accept atende, o Socket.IO entrega a voz do cliente em tempo real (evento call-audio) e o seu código devolve a fala da IA pelo evento call-audio-in. Entre uma ponta e outra ficam a transcrição, o modelo de linguagem e a voz sintética. Com a API não oficial da WAME, tudo isso roda no número que você já usa, sem aprovação na Meta.
Este guia mostra a arquitetura completa e um esqueleto em Node.js que você pode adaptar. Os detalhes de latência e interrupção têm um artigo próprio: agente de voz no WhatsApp: latência, interrupção e silêncio.
A camada não oficial da WAME é independente e não é afiliada, endossada ou suportada pelo WhatsApp ou pela Meta. O uso é de responsabilidade de quem envia.
O que acontece numa ligação atendida por IA
Do toque ao "até logo", o fluxo é este:
- Alguém liga. O webhook da instância recebe um evento com
field: "call"e a chamada emvalue.calls, comstatus: "offer". - Você decide se atende. Horário, cliente conhecido, fila de atendimento: é aqui que você escolhe entre atender com IA, recusar e responder por mensagem ou deixar tocar.
- Você atende.
POST /{key}/call/acceptcom ocallIde ofrom_jidde quem ligou. A API atende já com o canal de áudio aberto. - A voz do cliente chega pelo socket. Cada pedaço de áudio vem no evento
call-audio, identificado pelocallId. - Você entende e responde. Detecta quando a pessoa parou de falar, transcreve, pede a resposta ao modelo e sintetiza a voz.
- A IA fala. Você manda o áudio pelo evento
call-audio-in, em tempo real, ou envia um arquivo pronto comPOST /{key}/call/{callId}/audio. - A ligação termina.
POST /{key}/call/end, e o resumo vai para o seu sistema.
A diferença para um chatbot de texto é o tempo real: em vez de uma mensagem inteira, você recebe um fluxo contínuo de áudio e precisa decidir sozinho quando a pessoa terminou de falar.
Pré-requisitos
- Uma instância não oficial conectada, com permissão de chamadas habilitada.
- O webhook configurado no formato
meta(viaPUT /{key}/instance). - Um servidor Node.js com acesso público para o webhook.
- Três provedores de IA, que podem ser do mesmo fornecedor ou não: transcrição (algo na linha do Whisper), modelo de linguagem e voz sintética com saída em streaming. Existe ainda a alternativa dos modelos que já recebem fala e devolvem fala (speech-to-speech), que substituem as três etapas por uma.
Este artigo não amarra você a um fornecedor. O código usa três funções, transcrever, responder e sintetizar, que você implementa com o serviço que escolher.
O formato do áudio
Os dois sentidos usam o mesmo formato: PCM de 16 bits, little-endian, mono, 16 kHz, em base64 no campo pcm.
Isso importa por dois motivos. Primeiro, muitos serviços de transcrição aceitam exatamente esse formato, então o áudio pode ir quase direto. Segundo, alguns provedores de voz sintética devolvem áudio a 24 kHz ou mais; nesse caso você precisa reamostrar para 16 kHz antes de enviar, ou a voz sai acelerada e aguda.
Para arquivos prontos (saudação gravada, aviso de horário), o caminho mais simples é POST /{key}/call/{callId}/audio com url ou base64: a API converte qualquer formato de áudio para o formato da chamada e coloca na fila.
Conectar o socket
O áudio da ligação não passa pelo webhook: ele é contínuo demais para isso. Ele chega por Socket.IO, e a conexão precisa da key da instância tanto em auth quanto em query — a query é o que leva a conexão até o servidor que cuida da sua instância.
import { io } from 'socket.io-client';
const KEY = process.env.WAME_KEY;
const socket = io('https://us.api-wa.me', {
auth: { key: KEY },
query: { key: KEY },
transports: ['websocket', 'polling'],
});
socket.on('connect', () => console.log('socket conectado'));
socket.on('error', (e) => console.error('erro no socket', e));O socket só recebe eventos da própria instância. Se você mandar áudio para uma chamada que já terminou ou que não foi atendida, o evento error volta com o código call_session_not_found.
O esqueleto do agente
O código abaixo junta webhook, socket e estado por chamada. As três funções de IA ficam como contratos para você preencher.
import express from 'express';
import { io } from 'socket.io-client';
const KEY = process.env.WAME_KEY;
const BASE = `https://us.api-wa.me/${KEY}`;
// ---- Contratos de IA: implemente com o provedor que escolher ----
async function transcrever(pcm16k) { /* Buffer PCM16 16 kHz -> texto */ }
async function responder(historico) { /* mensagens -> { texto, encerrar, humano } */ }
async function sintetizar(texto) { /* texto -> Buffer PCM16 16 kHz (reamostre se preciso) */ }
const post = (path, body) =>
fetch(`${BASE}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}).then((r) => r.json());
// Estado por ligação
const chamadas = new Map();
const socket = io('https://us.api-wa.me', {
auth: { key: KEY },
query: { key: KEY },
transports: ['websocket', 'polling'],
});
// Fala da IA: envia em pedaços pequenos (~40 ms) para poder parar no meio.
const BYTES_POR_PEDACO = 16000 * 2 * 0.04; // 16 kHz * 2 bytes * 40 ms
function falar(callId, pcm) {
for (let i = 0; i < pcm.length; i += BYTES_POR_PEDACO) {
const pedaco = pcm.subarray(i, i + BYTES_POR_PEDACO);
socket.emit('call-audio-in', { callId, pcm: pedaco.toString('base64') });
}
}
// Voz do cliente
socket.on('call-audio', ({ callId, pcm }) => {
const c = chamadas.get(callId);
if (!c) return;
c.detector.alimentar(Buffer.from(pcm, 'base64'));
});
async function aoTerminarFala(callId, trecho) {
const c = chamadas.get(callId);
if (!c || c.ocupado) return;
c.ocupado = true;
try {
const texto = await transcrever(trecho);
if (!texto?.trim()) return;
c.historico.push({ role: 'user', content: texto });
const r = await responder(c.historico);
c.historico.push({ role: 'assistant', content: r.texto });
falar(callId, await sintetizar(r.texto));
if (r.encerrar || r.humano) {
setTimeout(() => encerrar(callId, r.humano), 4000); // deixa a despedida tocar
}
} finally {
c.ocupado = false;
}
}
async function encerrar(callId, precisaHumano) {
const c = chamadas.get(callId);
if (!c) return;
await post('/call/end', { callId, peerJid: c.jid });
chamadas.delete(callId);
if (precisaHumano) await abrirTicket(c); // sua fila, seu CRM
}
const app = express();
app.use(express.json());
app.post('/webhook/wame', async (req, res) => {
res.sendStatus(200); // responda já; o resto roda em segundo plano
const change = req.body?.entry?.[0]?.changes?.[0];
if (change?.field !== 'call') return;
const ch = change.value?.calls?.[0];
if (!ch || ch.status !== 'offer' || ch.is_group) return;
if (!deveAtenderComIA(ch)) return; // horário, cliente, fila...
const jid = ch.from_jid ?? ch.from;
await post('/call/accept', { callId: ch.id, callFrom: jid });
chamadas.set(ch.id, {
jid,
telefone: ch.from,
historico: [],
ocupado: false,
detector: criarDetectorDeFala((trecho) => aoTerminarFala(ch.id, trecho)),
});
const saudacao =
'Olá! Aqui é a assistente virtual da Loja Exemplo. ' +
'Esta ligação é atendida por inteligência artificial e pode ser transcrita. ' +
'Como posso ajudar?';
falar(ch.id, await sintetizar(saudacao));
});
app.listen(3000);Três pontos desse código merecem atenção:
from_jid, nãofrom. Ofromvem só com dígitos; para atender e encerrar, a API precisa do JID completo, que chega emfrom_jid.- Um estado por
callId. Várias ligações podem acontecer ao mesmo tempo, e o áudio de todas chega pelo mesmo socket. Tudo é indexado pelocallId. - O webhook responde 200 antes de atender. Webhook lento é reenviado; sem isso, você tentaria atender a mesma ligação duas vezes.
Detectar quando a pessoa terminou de falar
O criarDetectorDeFala é a peça que transforma um fluxo contínuo em frases. A versão mais simples mede a energia de cada pedaço de áudio e considera que a pessoa terminou quando há silêncio por algumas centenas de milissegundos:
function criarDetectorDeFala(aoTerminar, { silencioMs = 700, limiar = 500 } = {}) {
let buffer = [];
let falando = false;
let ultimoSom = 0;
const energia = (buf) => {
let soma = 0;
for (let i = 0; i < buf.length; i += 2) soma += Math.abs(buf.readInt16LE(i));
return soma / (buf.length / 2);
};
return {
alimentar(buf) {
const agora = Date.now();
if (energia(buf) > limiar) {
falando = true;
ultimoSom = agora;
}
if (falando) buffer.push(buf);
if (falando && agora - ultimoSom > silencioMs) {
falando = false;
const trecho = Buffer.concat(buffer);
buffer = [];
aoTerminar(trecho);
}
},
};
}Isso funciona para um protótipo. Em produção, troque por um detector de voz (VAD) de verdade e ajuste os limites com ligações reais: ambiente barulhento, pessoa que pensa no meio da frase, áudio de viva-voz. É exatamente o assunto de latência, interrupção e silêncio.
O que a IA pode fazer durante a ligação
Um agente de voz útil não só conversa: ele consulta e age. O mesmo mecanismo de function calling que você usa no texto funciona aqui — o responder pode chamar ferramentas para ver horários livres, consultar pedido ou abrir chamado. E, com RAG, ele responde com base nas suas políticas, não no que o modelo acha.
Uma regra que muda de canal para canal: na voz, respostas curtas. Duas frases no máximo. Texto longo lido por voz sintética cansa, e o cliente interrompe. Deixe isso explícito nas instruções do modelo.
Handoff: quando a IA deve passar o caso
Não existe transferência de chamada para outro número. Então o handoff é sempre o mesmo movimento: a IA avisa, encerra a ligação e o caso segue por outro caminho.
- Mensagem no WhatsApp, logo depois da ligação: "Vou passar seu caso para o time; em até 30 minutos alguém te chama por aqui."
- Ticket no seu sistema, com o resumo da conversa até ali.
- Retorno agendado por um humano, no horário que o cliente escolher.
Quando fazer isso? As mesmas regras de quando a IA deve parar de responder valem na voz, com um agravante: irritação na voz aparece antes. Pedido explícito de humano, duas respostas sem resolver, assunto sensível (cobrança contestada, reclamação séria) — em todos esses casos, passe o caso.
Quando não atender com IA
Nem toda ligação deveria cair no agente:
- Ligações de grupo. O
is_groupvem no evento; o esqueleto acima ignora. - Fora do escopo do agente. Se a IA só sabe agendar, um cliente com problema técnico vai sair frustrado. Às vezes é melhor recusar e responder por texto.
- Cliente que já pediu humano antes. Guarde isso no seu CRM e respeite.
- Limite de sessões simultâneas. A plataforma tem um teto de ligações com áudio ativo ao mesmo tempo; em pico, tenha um plano B (recusar com mensagem) em vez de deixar tocar.
Transparência e LGPD
Diga logo na saudação que é um assistente virtual e, se você transcreve ou grava, que a ligação pode ser transcrita. Defina para que usa essas transcrições, por quanto tempo guarda e quem acessa. As cláusulas que um cliente corporativo vai pedir estão em API de WhatsApp e LGPD.
E um limite que não se negocia: o agente de voz é para atender quem ligou e para retornos combinados. Ligação automatizada para lista de contatos é robocall — é denunciada rápido e derruba número. A WAME não apoia esse uso. No uso certo, atendendo quem procurou você, a taxa de bloqueio é muito baixa.
Custo e onde ele está
O custo do agente de voz fica quase todo na IA: minutos de transcrição, tokens do modelo e caracteres de voz sintética. Ligações longas e respostas prolixas são o que encarece. Os cálculos de quanto custa rodar um agente de IA valem aqui, somando transcrição e voz.
Conclusão
Um agente de voz no WhatsApp é um chatbot com duas peças a mais — ouvir e falar — e uma exigência nova: tempo real. A API não oficial da WAME entrega a parte difícil do canal: o evento de chamada no webhook, o atendimento com áudio aberto e a voz do cliente em PCM 16 kHz pelo socket, com o caminho de volta pelo mesmo socket ou por arquivo. Do seu lado ficam a detecção de fala, a IA e as regras de quando passar para um humano. Comece pelo esqueleto acima, teste com ligações reais e só depois otimize a latência. Os endpoints de chamada estão na documentação, e o básico de ligar e atender está em ligação pelo WhatsApp via API.
Pronto para automatizar seu WhatsApp?
Crie sua conta gratuita e comece a enviar mensagens pela API em minutos.
Começar grátisPerguntas frequentes
Dá para uma IA atender ligação no WhatsApp?+
Sim. Com a API não oficial da WAME, a ligação chega no webhook, você atende com POST /{key}/call/accept e passa a receber a voz de quem ligou em tempo real pelo Socket.IO (evento call-audio, em PCM 16 kHz). Seu código transcreve, pede a resposta a um modelo de IA, sintetiza a voz e devolve o áudio pelo evento call-audio-in.
Em que formato chega o áudio da ligação?+
PCM de 16 bits, little-endian, mono, a 16 kHz, codificado em base64 no campo pcm do evento call-audio. O mesmo formato vale para o áudio que você envia de volta pelo evento call-audio-in. Se o seu provedor de voz usa outra taxa, como 24 kHz, é preciso reamostrar.
A IA consegue transferir a ligação para um atendente?+
Não existe transferência de chamada para outro número. O handoff é feito encerrando a ligação com um aviso e passando o caso para um humano: mensagem no WhatsApp, ticket no seu sistema ou retorno agendado. É por isso que o agente precisa saber a hora de parar.
Preciso avisar que quem atende é uma IA?+
É a prática recomendada e ajuda a cumprir a LGPD: logo na saudação, diga que a ligação é atendida por um assistente virtual e, se for o caso, que ela pode ser transcrita. Transparência também reduz reclamação e denúncia.
Posso usar isso para ligar para uma lista de contatos?+
Não. Ligação automatizada para quem não pediu é robocall, é denunciada rápido e derruba o número. A WAME não apoia esse uso. O agente de voz serve para atender quem ligou e para retornos combinados com o cliente.
Continue lendo
Agente de voz no WhatsApp: latência, interrupção (barge-in) e silêncio
Como deixar um agente de voz no WhatsApp natural: latência, streaming, detecção de fala, interrupção (barge-in), silêncio e eco, com exemplos em Node.js.
Ligação pelo WhatsApp via API não oficial: fazer, atender e tocar áudio
Como fazer, atender, recusar e encerrar ligações de WhatsApp pela API não oficial, tocar áudio na chamada e gerar link de chamada, com exemplos em cURL.
IA que liga para confirmar agendamento no WhatsApp (e entende sim, não e remarcar)
IA que liga pelo WhatsApp para confirmar consultas e serviços: entende sim, não e remarcar, atualiza a agenda e cai para mensagem se ninguém atender.