---
title: "IA que liga para confirmar agendamento no WhatsApp (e entende sim, não e remarcar)"
description: "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."
url: "https://wame.api.br/blog/ia-ligar-confirmar-agendamento-whatsapp"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-28"
modified_time: "2026-09-28"
author: "Raphael Serafim"
keywords: "confirmar agendamento por ligação, ia liga para cliente whatsapp, ligação whatsapp api, api whatsapp não oficial, api não oficial whatsapp, lembrete de consulta por voz, reduzir falta agendamento"
reading_time: "10 min de leitura"
---

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

**Uma IA que confirma agendamento por ligação no WhatsApp liga com `POST /{key}/call` só para clientes que escolheram esse canal, espera o evento `call-ready` no Socket.IO, diz o compromisso, entende a resposta — confirmar, cancelar ou remarcar — e atualiza a agenda. Se ninguém atender, o evento `call-media-failed` avisa e a confirmação segue por mensagem de texto.** Com a API não oficial da WAME, tudo roda no número que o cliente já conhece.

A confirmação por mensagem já foi coberta em [lembrete de agendamento no WhatsApp](/blog/lembretes-agendamento-confirmacao-whatsapp). A ligação é a camada extra para quem não responde texto — e tem regras próprias.

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

## Para quem ligar (e para quem não)

Este é o ponto que decide se a automação ajuda ou derruba o número. A regra:

- **Só para quem optou.** No agendamento, pergunte: "Como prefere a confirmação: mensagem ou ligação?". Guarde a resposta.
- **Só para compromisso real**, com data e hora marcadas pelo próprio cliente.
- **Uma ligação por compromisso.** Não atendeu, vai por texto. Religar três vezes é o comportamento que gera denúncia.
- **Em horário razoável.** Comercial, nunca cedo demais ou à noite.

Ligar automaticamente para uma lista de contatos que não espera a ligação é robocall. É denunciado rápido, derruba o número e a WAME não apoia esse uso. Feito do jeito certo — cliente que pediu, uma vez, no horário combinado —, é atendimento, e a taxa de bloqueio é muito baixa.

## O fluxo completo

1. Um job seleciona os agendamentos de amanhã com `canal = "ligacao"` e ainda não confirmados.
2. Para cada um, espaçado no tempo, `POST /{key}/call`. A resposta volta na hora com o `callId` e `status: "ringing"`.
3. **Atendeu**: o Socket.IO emite `call-ready` com o `callId`. A IA fala o compromisso e ouve a resposta pelo evento `call-audio`.
4. **Não atendeu ou recusou**: o Socket.IO emite `call-media-failed`. O sistema manda a confirmação por mensagem.
5. A resposta vira ação na agenda: confirmado, cancelado ou remarcado.
6. A ligação é encerrada com `POST /{key}/call/end` e o resultado é registrado.

## Iniciar a ligação

```js
const KEY = process.env.WAME_KEY;
const BASE = `https://server.wame.api.br/${KEY}`;

const post = (path, body) =>
  fetch(`${BASE}${path}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  }).then((r) => r.json());

const emAndamento = new Map(); // callId -> { agendamento, peerJid, tentativas }

async function ligarPara(agendamento) {
  const r = await post('/call', { to: agendamento.telefone });
  const { callId, peerJid } = r.response ?? {};
  if (!callId) {
    await confirmarPorTexto(agendamento); // falhou antes de tocar
    return;
  }
  emAndamento.set(callId, { agendamento, peerJid, tentativas: 0, historico: [] });
}
```

A chamada responde assim que o telefone começa a tocar, com `callId` e `peerJid`. O áudio só existe depois que a pessoa atende — por isso o resto do fluxo depende dos eventos do socket.

## Ouvir o socket

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

const socket = io('https://server.wame.api.br', {
  auth: { key: KEY },
  query: { key: KEY },
  transports: ['websocket', 'polling'],
});

socket.on('call-ready', async ({ callId }) => {
  const c = emAndamento.get(callId);
  if (!c) return;
  const { nome, servico, dataHora } = c.agendamento;
  await falar(callId,
    `Olá, ${nome}! Aqui é a assistente virtual da Clínica Exemplo. ` +
    `Estou ligando para confirmar ${servico} ${dataHora}. ` +
    `Você confirma, quer cancelar ou prefere remarcar?`);
});

socket.on('call-media-failed', async (evt) => {
  const c = evt.callId && emAndamento.get(evt.callId);
  if (!c) return;
  emAndamento.delete(evt.callId);
  await confirmarPorTexto(c.agendamento);
});

socket.on('call-audio', ({ callId, pcm }) => {
  const c = emAndamento.get(callId);
  if (c) c.detector?.alimentar(Buffer.from(pcm, 'base64'));
});
```

Um cuidado com o `call-media-failed`: quando a falha acontece antes de a ligação ganhar um identificador, o evento pode vir sem `callId`. Por isso, tenha também um **tempo limite por ligação** — se nem `call-ready` nem `call-media-failed` chegarem em um minuto ou dois, trate como não atendida e siga por texto.

O `falar` sintetiza a frase em PCM 16 kHz e envia pelo `call-audio-in` em pedaços pequenos — o mesmo reprodutor descrito em [latência, interrupção e silêncio](/blog/agente-voz-whatsapp-latencia-interrupcao). A primeira frase também avisa que é uma assistente virtual: transparência reduz desconfiança e reclamação.

Como a saudação é quase igual para todos, dá para pré-gerar o começo ("Olá, aqui é a assistente virtual da Clínica Exemplo") e sintetizar só o trecho variável. Menos latência e menos custo.

## Entender sim, não e remarcar

A resposta do cliente é curta e variada: "confirmo", "pode deixar", "não vou conseguir", "tem outro horário?", "quem é?". Depois de transcrever, peça ao modelo uma classificação fechada:

```js
const instrucoes = `
Classifique a resposta do cliente sobre o agendamento.
Responda SOMENTE com JSON: {"intencao": "confirmar|cancelar|remarcar|duvida|nao_entendi", "preferencia": "texto livre ou vazio"}
- "pode ser", "tá certo", "confirmo" => confirmar
- "não vou", "desmarca" => cancelar
- "outro dia", "mais tarde", "tem na sexta?" => remarcar (preencha preferencia)
- perguntas sobre endereço, preparo, valor => duvida
`;

async function tratarResposta(callId, texto) {
  const c = emAndamento.get(callId);
  const { intencao, preferencia } = await classificar(instrucoes, texto);

  if (intencao === 'confirmar') {
    await agenda.confirmar(c.agendamento.id);
    await falar(callId, 'Perfeito, está confirmado. Até lá!');
    return encerrar(callId);
  }
  if (intencao === 'cancelar') {
    await agenda.cancelar(c.agendamento.id);
    await falar(callId, 'Tudo bem, cancelei. Se quiser remarcar, é só chamar por aqui.');
    return encerrar(callId);
  }
  if (intencao === 'remarcar') {
    const opcoes = await agenda.horariosLivres(c.agendamento, preferencia);
    c.opcoes = opcoes.slice(0, 3);
    return falar(callId, `Tenho ${falarOpcoes(c.opcoes)}. Qual prefere?`);
  }
  if (intencao === 'duvida') {
    await falar(callId, 'Vou te mandar essas informações por mensagem agora. Você confirma o horário?');
    await enviarInformacoes(c.agendamento);
    return;
  }
  // nao_entendi
  if (++c.tentativas >= 2) {
    await falar(callId, 'Vou te mandar a confirmação por mensagem, tudo bem? Obrigada!');
    await confirmarPorTexto(c.agendamento);
    return encerrar(callId);
  }
  await falar(callId, 'Desculpe, não entendi. Você confirma o horário, quer cancelar ou remarcar?');
}
```

A consulta à agenda e a remarcação são ações do seu sistema; com [function calling](/blog/function-calling-api-whatsapp-agente-ia), o próprio modelo pode decidir chamar `horariosLivres` e `remarcar`, em vez de você codificar cada ramo. Para uma confirmação simples, o `if` explícito acima é mais previsível — e previsibilidade vale ouro numa ligação.

Três regras de conversa que evitam frustração:

- **No máximo três opções de horário** por vez. Por voz, ninguém guarda cinco.
- **Repita a decisão** antes de encerrar: "Então fica quinta, às 14h. Confirmado."
- **Duas incompreensões, sai da voz.** Não force; mande por mensagem.

## Encerrar e registrar

```js
async function encerrar(callId) {
  const c = emAndamento.get(callId);
  if (!c) return;
  emAndamento.delete(callId);
  setTimeout(() => post('/call/end', { callId, peerJid: c.peerJid }), 3000); // deixa a frase final tocar
  await agenda.registrarContato(c.agendamento.id, { canal: 'ligacao', resultado: c.resultado });
}
```

Se o cliente desligar antes, o evento de chamada com o novo status chega no webhook; limpe o estado e, se nada foi decidido, siga por texto.

## O caminho do texto

A confirmação por texto é o plano B e precisa ser boa. Abra com uma mensagem simples antes de botões — para contatos que nunca conversaram com o número, mensagens interativas podem não aparecer como primeira mensagem:

```js
async function confirmarPorTexto(a) {
  await post('/message/text', {
    to: a.telefone,
    text: `Olá, ${a.nome}! Tentamos te ligar para confirmar ${a.servico} ${a.dataHora}.`,
  });
  await post('/message/button_reply', {
    to: a.telefone,
    text: 'Você confirma?',
    buttons: [
      { type: 'quick_reply', id: `conf_${a.id}`, text: 'Confirmo' },
      { type: 'quick_reply', id: `canc_${a.id}`, text: 'Cancelar' },
      { type: 'quick_reply', id: `rem_${a.id}`, text: 'Remarcar' },
    ],
  });
}
```

O clique volta no webhook como `interactive.button_reply.id`, e a mesma lógica de agenda trata a resposta.

## Ritmo das ligações

Um job que dispara cem ligações no mesmo minuto não parece atendimento. Espace:

- **Uma ligação por vez ou poucas em paralelo**, com intervalo entre elas. A plataforma também limita quantas sessões de áudio rodam ao mesmo tempo.
- **Distribua ao longo do horário comercial** do dia anterior, não tudo às 9h.
- **Respeite quem pediu outro horário** para contato.

Se a sua API devolver `429` em algum envio de texto do plano B, é sinal para desacelerar a fila, não para tentar de novo na hora. A lógica de fila está em [fila, rate limit e retry](/blog/fila-rate-limit-retry-disparo-whatsapp).

## Medir o que importa

- **Taxa de atendimento** das ligações.
- **Taxa de confirmação** por canal (voz vs texto).
- **Faltas** antes e depois de ligar.
- **Pedidos de "prefiro mensagem"** — sinal para mudar o canal padrão desse cliente.

Se a voz não reduz faltas mais do que o texto para o seu público, fique no texto: é mais barato. A ligação faz mais sentido para agendamentos de alto valor e para quem não responde mensagens.

## Conclusão

Uma IA que liga para confirmar agendamento é uma conversa curta e bem delimitada: dizer o compromisso, entender confirmar, cancelar ou remarcar, e agir na agenda. A API não oficial da WAME dá as peças — `POST /{key}/call` para ligar, `call-ready` e `call-media-failed` no Socket.IO para saber o que aconteceu, `call-audio` e `call-audio-in` para ouvir e falar. O que faz dar certo é o seu lado: ligar só para quem escolheu esse canal, uma vez, no horário certo, e cair para mensagem sem insistir. O agente de voz completo está em [IA para atender ligação no WhatsApp](/blog/ia-atender-ligacao-whatsapp-api), e o básico de chamadas, em [ligação pelo WhatsApp via API](/blog/fazer-ligacao-whatsapp-api-nao-oficial).

## Perguntas frequentes

### Posso fazer uma IA ligar para confirmar consultas pelo WhatsApp?

Sim, para clientes que escolheram receber a confirmação por ligação. Com a API não oficial da WAME você liga com POST /{key}/call, recebe o aviso de atendimento pelo Socket.IO (call-ready), ouve a resposta pelo evento call-audio e fala pelo call-audio-in. A IA entende confirmar, cancelar ou remarcar e atualiza a agenda.

### E se o cliente não atender?

A API avisa pelo Socket.IO com o evento call-media-failed quando a ligação não é atendida ou é recusada. Nesse caso, mande a confirmação por mensagem de texto com botões. Não fique religando: uma tentativa por voz e o resto por texto.

### Isso não é robocall?

Não, se for feito para quem pediu. Robocall é ligar automaticamente para quem não espera a ligação. Aqui a ligação é para um cliente com horário marcado que optou por confirmação por voz, no horário combinado e uma vez. A WAME não apoia ligação automatizada para listas.

### Como a IA entende a resposta do cliente?

A fala é transcrita e um modelo classifica a intenção em confirmar, cancelar, remarcar ou não entendido. Para remarcar, a IA consulta os horários livres por function calling e oferece duas ou três opções. Se não entender duas vezes, encerra e manda por mensagem.

### Ligação funciona melhor que mensagem para confirmar?

Depende do público. Para quem não lê mensagens com frequência, pessoas mais velhas ou agendamentos de alto valor, a voz costuma funcionar melhor. Para o resto, a mensagem com botões é mais barata e suficiente. O ideal é deixar o cliente escolher o canal.
