---
title: "IA para atender ligação no WhatsApp pela API: como montar um agente de voz"
description: "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."
url: "https://wame.api.br/blog/ia-atender-ligacao-whatsapp-api"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-28"
modified_time: "2026-09-28"
author: "Raphael Serafim"
keywords: "ia atender ligação whatsapp, agente de voz whatsapp, ligação whatsapp api, api whatsapp não oficial, api não oficial whatsapp, atendimento por voz com ia, bot de voz whatsapp"
reading_time: "11 min de leitura"
---

# 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](/blog/agente-voz-whatsapp-latencia-interrupcao).

> 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:

1. **Alguém liga.** O webhook da instância recebe um evento com `field: "call"` e a chamada em `value.calls`, com `status: "offer"`.
2. **Você decide se atende.** Horário, cliente conhecido, fila de atendimento: é aqui que você escolhe entre atender com IA, [recusar e responder por mensagem](/blog/recusar-ligacao-whatsapp-automatico-api) ou deixar tocar.
3. **Você atende.** `POST /{key}/call/accept` com o `callId` e o `from_jid` de quem ligou. A API atende já com o canal de áudio aberto.
4. **A voz do cliente chega pelo socket.** Cada pedaço de áudio vem no evento `call-audio`, identificado pelo `callId`.
5. **Você entende e responde.** Detecta quando a pessoa parou de falar, transcreve, pede a resposta ao modelo e sintetiza a voz.
6. **A IA fala.** Você manda o áudio pelo evento `call-audio-in`, em tempo real, ou envia um arquivo pronto com `POST /{key}/call/{callId}/audio`.
7. **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` (via `PUT /{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.

```js
import { io } from 'socket.io-client';

const KEY = process.env.WAME_KEY;

const socket = io('https://server.wame.api.br', {
  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.

```js
import express from 'express';
import { io } from 'socket.io-client';

const KEY = process.env.WAME_KEY;
const BASE = `https://server.wame.api.br/${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://server.wame.api.br', {
  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ão `from`.** O `from` vem só com dígitos; para atender e encerrar, a API precisa do JID completo, que chega em `from_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 pelo `callId`.
- **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:

```js
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](/blog/agente-voz-whatsapp-latencia-interrupcao).

## 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](/blog/function-calling-api-whatsapp-agente-ia) 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](/blog/rag-whatsapp-base-conhecimento-ia), 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](/blog/quando-ia-deve-parar-responder-whatsapp) 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_group` vem 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](/blog/recusar-ligacao-whatsapp-automatico-api).
- **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](/blog/whatsapp-api-lgpd-contrato-cliente).

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](/blog/quanto-custa-agente-ia-whatsapp) 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](/docs), e o básico de ligar e atender está em [ligação pelo WhatsApp via API](/blog/fazer-ligacao-whatsapp-api-nao-oficial).

## Perguntas 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.
