Operação

Lembrete de consulta no WhatsApp pela API: rotina, confirmação e LGPD

Falta de paciente é horário perdido. O lembrete 24 horas antes, com resposta 1 para confirmar e 2 para remarcar, é a automação de menor esforço para reduzir faltas. Esta receita monta isso a partir da agenda do seu próprio sistema, sem depender de plataforma de terceiros, e cuida do que costuma dar errado: envio em dobro, mensagem fora de hora e dado sensível na conversa.

Publicado em · 4 min de leitura

Este artigo também está disponível em: English · Español

De onde vêm os horários

A fonte da verdade é a sua agenda: um banco com a tabela de consultas, um ERP ou o Google Agenda (veja a integração com Google Calendar). Esta receita assume uma tabela appointments com status, horário, nome, telefone, um campo consent_whatsapp (o paciente concordou em receber lembretes) e reminder_sent_at (nulo até o envio). Se a sua agenda for um SaaS fechado, o caminho costuma ser um webhook ou uma exportação; confira o que ele oferece antes de prometer o lembrete.

O campo de consentimento não é enfeite. Dado de agendamento de saúde é dado pessoal, e quase sempre sensível pelo contexto. Colete o consentimento no cadastro ou na marcação ('posso lembrar você da consulta por WhatsApp?') e consulte o campo no filtro do envio.

A rotina: janela, trava e intervalo

A rotina roda a cada 15 minutos e busca consultas confirmadas que começam entre 23 e 24 horas à frente, ainda sem lembrete e com consentimento. A janela de uma hora, somada ao filtro reminder_sent_at, faz cada consulta ser pega uma vez só. Antes de enviar, a rotina 'reivindica' a linha com um UPDATE condicional: se duas execuções se sobrepõem, só uma consegue marcar o envio. Se o envio falhar, a marca é desfeita para a próxima execução tentar de novo.

O intervalo aleatório de alguns segundos entre mensagens evita rajada. Para lembretes de uma clínica, o volume é baixo, mas o princípio vale: um ritmo humano reduz risco. O envio usa POST /api/v1/{instanceId}/send/text com number e text, e a ZapZap ainda aplica atraso e o indicador de digitando por padrão (anti-bloqueio). Verifique antes se o número tem WhatsApp com a rota chat/check, descrita na referência.

Node.js (cron a cada 15 minutos)

// Runs every 15 minutes (cron, queue worker or n8n schedule). Appointments come from YOUR system.
async function remindAppointments() {
  const rows = await db.query(`
    SELECT id, patient_name, patient_phone, starts_at
    FROM appointments
    WHERE status = 'confirmed' AND reminder_sent_at IS NULL AND consent_whatsapp = TRUE
      AND starts_at BETWEEN now() + interval '23 hours' AND now() + interval '24 hours'`);

  for (const a of rows.rows) {
    // claim before sending: a second run cannot pick the same row
    const claim = await db.query("UPDATE appointments SET reminder_sent_at = now() WHERE id = $1 AND reminder_sent_at IS NULL", [a.id]);
    if (!claim.rowCount) continue;

    const when = new Date(a.starts_at).toLocaleString("pt-BR", { dateStyle: "short", timeStyle: "short", timeZone: "America/Sao_Paulo" });
    try {
      await sendWhatsApp(a.patient_phone, "Oi, " + a.patient_name.split(" ")[0] + ". Lembrete da sua consulta amanhã, " + when + ". Responda 1 para confirmar ou 2 para remarcar.");
    } catch (e) {
      await db.query("UPDATE appointments SET reminder_sent_at = NULL WHERE id = $1", [a.id]); // let the next run retry
      console.error("reminder failed", a.id, e.message);
    }
    await new Promise((r) => setTimeout(r, 4000 + Math.random() * 6000)); // human-like gap between sends
  }
}

// Shared helper: one send through the ZapZap API
async function sendWhatsApp(number, text) {
  const r = await fetch(`https://api.zapzapapi.com/api/v1/${process.env.ZAPZAP_INSTANCE}/send/text`, {
    method: "POST",
    headers: {
      "x-api-key": process.env.ZAPZAP_API_KEY,
      "x-api-secret": process.env.ZAPZAP_API_SECRET,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ number, text }),
  });
  if (!r.ok) throw new Error("ZapZap " + r.status + ": " + (await r.text()));
}

Receber o 1 ou o 2

Para a resposta funcionar, a instância precisa entregar as mensagens recebidas ao seu servidor: registre a URL com PUT /api/v1/instances/{id}/webhook e o evento de mensagens (configurar webhook). Descarte as mensagens fromMe, ou a sua própria resposta automática pode reentrar no fluxo e criar um loop. Confira o formato exato do payload com uma mensagem real antes de escrever o código; o exemplo abaixo mostra só a lógica.

Trate respostas fora do esperado com cuidado: 'ok', 'sim' e 'confirmo' também são confirmações. Mapeie algumas variações e, se não entender, não responda sozinho: encaminhe para a recepção. Para validar o cabeçalho X-ZapZap-Signature e descartar entregas repetidas, siga o guia de webhooks em produção.

Node.js (Express)

// Receive the patient's "1" or "2" (message webhook registered with PUT /api/v1/instances/{id}/webhook, event "messages")
app.post("/zapzap", express.json(), async (req, res) => {
  res.sendStatus(200);
  const m = req.body; // check the exact shape with a real message first (see the webhooks reference)
  if (m.fromMe) return; // never react to your own messages, or an automatic reply answers itself in a loop
  const text = String(m.text || "").trim();
  if (text === "1") await markConfirmed(m.from);
  else if (text === "2") await askReschedule(m.from);
});

O texto: o que dizer e o que NÃO dizer

Diga o essencial: o nome do paciente, o dia e a hora, o nome da clínica e como confirmar ou remarcar. Não escreva o procedimento, o nome do médico em especialidade sensível, o resultado de exame nem o diagnóstico. O WhatsApp é um canal em que o aparelho pode estar com outra pessoa, e dado de saúde numa notificação é um vazamento esperando acontecer. 'Consulta com a Dra. Ana, amanhã às 14h' é suficiente.

Se a clínica tem exigência do conselho profissional sobre comunicação com paciente, siga a norma do seu conselho. Esta receita é técnica e não substitui orientação jurídica ou ética.

Limites e riscos

Lembrete de consulta para quem agendou com você é o uso de menor risco que existe. Mesmo assim, a ZapZap conecta números por um canal não oficial e gerenciado, e nenhum recurso garante ausência de bloqueio. Mantenha o ritmo, não envie para quem pediu para parar e não aproveite o lembrete para divulgar promoção.

Teste primeiro com consultas fictícias e com o seu número. Confira o fuso (o exemplo usa America/Sao_Paulo), a janela de 23 a 24 horas e, principalmente, que rodar a rotina duas vezes seguidas não gera segunda mensagem. Para segmentos específicos, veja as páginas de clínicas e dentistas.

Resumo rápido

  • Rotina a cada 15 minutos, janela de 23 a 24 horas e UPDATE condicional para nunca enviar duas vezes.
  • Consentimento no cadastro e campo consultado no filtro do envio: dado de saúde pede cuidado.
  • Mensagem sem procedimento nem diagnóstico; resposta 1 ou 2 por webhook, ignorando fromMe.
  • Teste a idempotência rodando a rotina duas vezes e conferindo que sai uma mensagem só.

Perguntas frequentes

Qual o melhor momento para lembrar o paciente?

Um lembrete 24 horas antes costuma dar tempo de remarcar. Alguns negócios adicionam um segundo, poucas horas antes. Teste com a sua agenda; a receita usa a janela de 23 a 24 horas.

Preciso de consentimento para lembrar de consulta?

Dado de agendamento de saúde é dado pessoal e costuma ser sensível. Colete o consentimento no cadastro ou na marcação, registre e consulte antes de cada envio. Em caso de dúvida, consulte a sua assessoria jurídica.

Como evito mandar o lembrete duas vezes?

Com um campo de controle e um UPDATE condicional que reivindica a linha antes do envio. Se duas execuções se sobrepuserem, só uma consegue marcar. Em falha de envio, desfaça a marca para tentar de novo.

Posso mencionar o procedimento na mensagem?

Não recomendamos. O aparelho pode estar com outra pessoa, e dado de saúde em notificação vaza fácil. Use nome, dia, hora, clínica e como confirmar ou remarcar.

Como recebo a resposta do paciente?

Registre a URL do seu servidor como webhook da instância com o evento de mensagens, ignore as mensagens fromMe e trate 1 e 2. Confira o formato do payload com uma mensagem real antes de codar.

Isso pode bloquear o número da clínica?

Pode. A ZapZap usa um canal não oficial e nenhum recurso elimina o risco. Lembrete para quem agendou, com ritmo humano e saída para parar, é o uso de menor risco, mas não é risco zero.

Reduza faltas com um lembrete simples

Conecte o número da clínica e rode a rotina da receita. R$15 por número ativo ao mês, com crédito de boas-vindas sujeito à campanha vigente.