InícioCasos de uso › API de WhatsApp para clínicas

API de WhatsApp para clínicas e consultórios: confirmação e lembrete de consulta automáticos

A agenda da clínica já sabe quem tem consulta amanhã; falta o aviso sair sozinho. Com a API do zapon, o seu sistema envia a confirmação na marcação e os lembretes da véspera e do dia — e recebe a resposta do paciente por webhook, para dar baixa na agenda sem ninguém digitar nada.

Toda clínica convive com as mesmas duas perdas: a falta sem aviso, que deixa o horário vago porque ninguém descobriu a tempo que o paciente não viria, e o custo de tentar evitá-la — a recepção ligando um a um na véspera, gastando a tarde em ligações que metade não atende.

As duas se resolvem com a mesma coisa: um canal que o paciente lê e responde sem esforço, disparado pelo sistema que já tem a agenda. É o que uma API de WhatsApp faz. O zapon expõe uma API REST simples — header token, JSON entrando e saindo — que a sua agenda ou o seu fluxo de automação chama como chamaria qualquer serviço. Abaixo: o fluxo passo a passo, os endpoints em cURL e Node, o evento que chega quando o paciente responde e o que fazer com ele.

A dor: por que o horário fica vago

Por que o paciente falta mesmo tendo marcado a consulta?

Quase nunca é descaso: é a distância entre a marcação e a data. Consulta marcada com três semanas sai da cabeça, e quando ele lembra já é tarde para avisar. Um lembrete que chega no WhatsApp e se responde com um toque tira o atrito dos dois lados: quem vem confirma, quem não vem libera o horário.

São dois problemas que costumam virar um só:

Por que ligar para cada paciente não escala?

Ligação tem custo fixo por paciente e não melhora com volume: cem consultas amanhã são cem ligações, com espera, ocupado e recado. Quem faz isso deixa de atender o balcão e prende o telefone da clínica. E não deixa registro — já a resposta pelo WhatsApp chega como um evento com telefone, horário e conteúdo, que vira um campo na agenda.

O que a clínica precisa ter para começar

O que preciso para avisar paciente por WhatsApp automaticamente?

Três coisas: um número de WhatsApp, uma conta no zapon com esse número conectado por QR Code ou código de pareamento, e um sistema que saiba quais consultas existem para amanhã. Não é preciso servidor próprio, conta na Meta, aprovação de template nem aplicativo instalado no celular da clínica.

Preciso trocar o número que a clínica já usa?

Não, e é melhor não trocar: o paciente responde para o número que conhece, e o que a automação não trata fica na conversa, no WhatsApp da clínica, para uma pessoa responder. Só use um número que a clínica controla, nunca o celular pessoal de um profissional.

Como o meu sistema de agenda entra nisso?

Se ele roda código, chama a API direto: uma requisição na hora da marcação e uma rotina diária que varre o dia seguinte. Se é fechado, leia os dados por fora — relatório, banco, planilha — e dispare dali. O que a API precisa saber é sempre o mesmo: telefone e texto.

O fluxo completo da clínica, passo a passo

Como funciona o fluxo de lembrete de consulta ponta a ponta?

Cinco etapas: (1) a consulta é marcada e o paciente recebe a confirmação com data, hora e endereço; (2) na véspera sai o lembrete pedindo confirmação; (3) no dia sai um lembrete curto; (4) o paciente confirma, remarca ou cancela; (5) o webhook entrega essa resposta ao seu sistema, que atualiza a agenda e, se for cancelamento, libera o horário. Nada depende de alguém abrir o WhatsApp.

Cada passo tem um objetivo diferente — não é a mesma mensagem três vezes.

1. O que enviar assim que a consulta é marcada?

A mensagem registra o combinado por escrito e valida o canal: se a entrega falhar aqui, você descobre hoje que o cadastro tem telefone errado, não na véspera. Conteúdo mínimo: data, dia da semana, horário, unidade e endereço. Não peça confirmação agora — ela não valeria nada com três semanas de antecedência.

2. Como mandar o lembrete da véspera?

Uma rotina diária varre o dia seguinte e dispara um lembrete por paciente. É este o momento de pedir resposta: cancelamento avisado agora ainda vira horário reaproveitado. Texto com números (1 confirma, 2 remarca, 3 cancela) é universal; botões deixam a resposta a um toque e devolvem um identificador definido por você. Use botões e aceite texto também — quem escreve "confirmado" precisa ser entendido.

3. Como é o lembrete do dia?

Algumas horas antes, uma mensagem curta: horário, endereço, o que levar e quando chegar. O objetivo aqui é logística, não confirmação. Se o paciente já cancelou no passo anterior, este envio não pode acontecer — o erro mais comum da primeira versão de qualquer fluxo desses. Leia o status no momento do envio, nunca uma lista montada na véspera.

4. Como o paciente responde para confirmar, remarcar ou cancelar?

Ele responde na conversa, tocando no botão ou escrevendo. Isso vira um evento entregue por webhook no endereço que a clínica cadastrar — um POST com a mensagem inteira: telefone, identificador, horário e conteúdo. É a peça que fecha o ciclo; sem ela você automatizou só o aviso, e alguém ainda lê as respostas à mão.

5. O que o seu sistema faz com a resposta?

O webhook não decide nada, ele entrega. A decisão é uma regra sua: casar o identificador do botão (ou o telefone) com o agendamento, atualizar o status e agir — cancelou, libera o horário e aciona a fila de espera; pediu para remarcar, entra numa lista que a recepção trata pela manhã.

Os endpoints que a clínica usa na prática

Quais endpoints da API do zapon uma clínica precisa?

Praticamente tudo se resolve com três: POST /chat/send/text para as mensagens, POST /chat/send/buttons para o lembrete com resposta em um toque e POST /user/check para conferir se o telefone do cadastro tem WhatsApp. Todos usam a base https://api.zapon.dev e o header token. São 49 endpoints publicados — 23 de /chat, 18 de /group e 8 de /user —, mas o fluxo de agenda vive nesses três.

A autenticação é um header só, token, copiado da conexão no painel: não é Authorization, não é Bearer, não há OAuth. Trate-o como senha — quem o tem envia mensagens em nome da clínica.

Como enviar a confirmação de consulta pela API?

Um POST em /chat/send/text com dois campos obrigatórios: Phone, o número em formato internacional só com dígitos, e Body, o texto.

confirmação na marcação — cURL
curl -X POST https://api.zapon.dev/chat/send/text \
  -H "token: SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "Phone": "5511999999999",
    "Body": "Ana, sua consulta está marcada.\n\nData: 12/03 (quarta)\nHorário: 14h30\nLocal: Clínica Exemplo — Rua das Acácias, 120, sala 4\n\nChegue 15 minutos antes com documento com foto. Para remarcar, é só responder por aqui."
  }'

A resposta traz o identificador da mensagem no WhatsApp:

resposta da API
{
  "code": 200,
  "success": true,
  "data": {
    "Details": "Sent",
    "Id": "90B2F8B13FAC8A9CF6B06E99C7834DC5",
    "Timestamp": "2026-03-01T09:12:08-03:00"
  }
}

Guarde esse Id junto do agendamento: é ele que prova qual mensagem saiu e evita reenvio duplicado.

Como disparar os lembretes do dia a partir do meu sistema?

O padrão é uma rotina agendada — um cron às 18h para a véspera, outro às 8h para o dia — que busca os agendamentos, monta o texto e chama a API. Em Node:

lembrete da véspera — Node
// lembretes.js — roda todo dia às 18h
const API = "https://api.zapon.dev";
const TOKEN = process.env.ZAPON_TOKEN;

async function enviarTexto(phone, body) {
  const r = await fetch(`${API}/chat/send/text`, {
    method: "POST",
    headers: { "token": TOKEN, "Content-Type": "application/json" },
    body: JSON.stringify({ Phone: phone, Body: body })
  });
  const json = await r.json();
  if (!r.ok || !json.success) throw new Error(json.error || `HTTP ${r.status}`);
  return json.data.Id;
}

const pausa = (ms) => new Promise((r) => setTimeout(r, ms));

for (const ag of await agendamentosDeAmanha()) {
  if (ag.status !== "agendado" || ag.paciente.optOut) continue;
  try {
    const id = await enviarTexto(ag.paciente.telefone,
      `${ag.paciente.nome}, sua consulta é amanhã, ${ag.data}, às ${ag.hora}.\n\n` +
      `Responda 1 para confirmar, 2 para remarcar ou 3 para cancelar.`);
    await registrarEnvio(ag.id, "lembrete_d1", id);   // guarda o Id: evita duplicar
  } catch (e) {
    await registrarFalha(ag.id, "lembrete_d1", String(e)); // vira tarefa da recepção
  }
  await pausa(4000);   // não despeje a agenda inteira no mesmo segundo
}

Três detalhes desse laço separam o fluxo que dura do que quebra na primeira semana. O continue impede lembrete de consulta cancelada e de quem pediu para não receber. O registrarEnvio guarda o Id, então rodar duas vezes não manda a mesma mensagem duas vezes. E a pausa evita transformar a agenda numa rajada de centenas de mensagens no mesmo instante — comportamento que não parece humano.

Como oferecer confirmar, remarcar e cancelar em botões?

O endpoint /chat/send/buttons envia botões de resposta rápida. Cada botão carrega um id definido por você, e é ele que volta no webhook quando o paciente toca. Coloque o número do agendamento aí dentro: a resposta chega amarrada ao registro certo, sem depender do telefone e sem interpretar texto. Além da resposta rápida, o mesmo endpoint monta botão que abre um link ("type": "cta_url"), botão que abre o discador ("type": "cta_call") e botão que copia um código ("type": "copy") — e os tipos convivem na mesma mensagem. O toque em resposta rápida volta no webhook; os outros três agem no aparelho de quem recebe.

lembrete com botões
POST https://api.zapon.dev/chat/send/buttons
token: SEU_TOKEN

{
  "Phone": "5511999999999",
  "Body": "Ana, sua consulta é amanhã, 12/03, às 14h30, na Clínica Exemplo. Podemos confirmar?",
  "Footer": "Clínica Exemplo",
  "Buttons": [
    { "id": "ag4821|confirmar", "text": "Confirmar" },
    { "id": "ag4821|remarcar",  "text": "Remarcar" },
    { "id": "ag4821|cancelar",  "text": "Cancelar" }
  ]
}

O texto de cada botão é curto por natureza do WhatsApp — uma ou duas palavras. Se precisar de mais opções, como escolher entre horários de remarcação, o /chat/send/list entrega um menu em lista.

Como saber se o número do paciente tem WhatsApp antes de enviar?

Cadastro de clínica tem telefone fixo, número antigo e dígito faltando. O POST /user/check recebe uma lista e diz quais têm conta no WhatsApp — serve para limpar a base antes do primeiro disparo.

checar números — cURL
curl -X POST https://api.zapon.dev/user/check \
  -H "token: SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "Phone": ["5511999999999", "5511888888888"] }'

// resposta
{ "code": 200, "success": true, "data": { "Users": [
  { "Query": "5511999999999", "IsInWhatsapp": true,  "JID": "[email protected]" },
  { "Query": "5511888888888", "IsInWhatsapp": false, "JID": "" }
] } }

Ao todo são 13 formas de envio — texto, imagem, áudio, vídeo, documento, sticker, localização, contato, enquete, lista, botões, template e edição de mensagem já enviada — mais reação, "digitando", marcar como lido e histórico. Fora do trio principal, os úteis para clínica são localização, no lembrete do dia, e documento, para o preparo de um exame em PDF.

A resposta do paciente: webhook, regra e ação

Como recebo no meu sistema a resposta do paciente?

Cada conexão tem um webhook próprio: você cadastra no painel a URL do seu sistema e escolhe os eventos. A partir daí, toda mensagem que chega no número é entregue como um POST nessa URL, com o conteúdo inteiro no corpo — telefone, identificador, horário, texto e, quando é resposta de botão, o id que você definiu. Não há polling nem nada para ficar consultando.

O ciclo tem três partes que não se misturam: o webhook entrega o evento, a sua regra interpreta e a ação acontece no seu sistema. A API não sabe o que é uma consulta; sabe que uma mensagem chegou.

Qual é o formato do evento de mensagem recebida?

O corpo traz o tipo do evento e a mensagem completa. Assim chega quem respondeu "1" em texto:

webhook — mensagem recebida
{
  "type": "Message",
  "event": {
    "Info": {
      "ID": "3EB0C767D26A1B5F7C83",
      "Chat": "[email protected]",
      "Sender": "[email protected]",
      "IsFromMe": false, "IsGroup": false,
      "PushName": "Ana Souza",
      "Timestamp": "2026-03-11T18:04:22-03:00"
    },
    "Message": { "conversation": "1" }
  }
}

// quando ele toca num botão, muda só o bloco Message:
    "Message": { "buttonsResponseMessage": {
      "selectedButtonID": "ag4821|confirmar",
      "Response": { "SelectedDisplayText": "Confirmar" }
    } }

Duas observações que economizam horas: o corpo pode chegar como JSON puro ou como formulário codificado, com o JSON dentro de um campo — aceite os dois. E o que o próprio número envia também gera evento, com IsFromMe igual a true: ignore, ou a recepção respondendo um paciente aciona a sua automação.

Como transformar a resposta em ação na agenda?

Descarte o que não interessa, identifique o agendamento, decida pela intenção e responda ao paciente confirmando o que foi feito — é essa última parte que evita o "respondi e não sei se valeu".

receptor do webhook — Node/Express
app.post("/whatsapp/eventos", express.json(), async (req, res) => {
  res.sendStatus(200);                        // responda primeiro, processe depois

  const ev = req.body?.event ?? req.body, info = ev?.Info ?? {};
  if (info.IsFromMe || info.IsGroup) return;   // o que a clínica enviou, e grupos, fora
  if (await jaProcessado(info.ID)) return;     // o mesmo evento pode chegar 2x

  const telefone = String(info.Chat || "").split("@")[0];
  const botao = ev?.Message?.buttonsResponseMessage?.selectedButtonID ?? "";
  const texto = (ev?.Message?.conversation ??
                 ev?.Message?.extendedTextMessage?.text ?? "").trim().toLowerCase();

  const ag = botao ? await buscarAgendamento(botao.split("|")[0])
                  : await proximoAgendamentoPorTelefone(telefone);
  if (!ag) return filaDaRecepcao(telefone, texto);

  const acao = botao ? botao.split("|")[1]
    : /^(1|sim|confirmo|confirmado)$/.test(texto) ? "confirmar"
    : /^(2|remarcar)$/.test(texto)                ? "remarcar"
    : /^(3|cancelar|nao vou)$/.test(texto)        ? "cancelar" : null;

  if (acao === "confirmar") {
    await atualizarStatus(ag.id, "confirmado");
    return enviarTexto(telefone, `Confirmado. Até amanhã às ${ag.hora}.`);
  }
  if (acao === "cancelar") {
    await atualizarStatus(ag.id, "cancelado");
    await liberarHorario(ag);                 // aciona a fila de espera
    return enviarTexto(telefone, "Consulta cancelada. Quando quiser remarcar, é só chamar.");
  }
  if (acao === "remarcar") {
    await atualizarStatus(ag.id, "remarcar");
    return enviarTexto(telefone, "Certo. A recepção vai te chamar com os horários.");
  }
  return filaDaRecepcao(telefone, texto);      // o resto é assunto de gente
});

E quando o paciente escreve qualquer outra coisa?

Ele vai escrever: "posso levar meu filho?", "aceita meu convênio?". Não tente responder tudo automaticamente — o que a automação não reconhece vira pendência para uma pessoa tratar. A conversa já está no WhatsApp da clínica, e a recepção responde no próprio aplicativo, como sempre fez; o papel da automação é sinalizar que aquela conversa espera resposta. Em saúde isso vale em dobro: sintoma, urgência e orientação clínica são assunto de profissional. Automatize horário, não conduta.

Consentimento, horário e uso responsável

Posso mandar mensagem para qualquer paciente da base?

Mensagem sobre um agendamento que o próprio paciente fez é esperada — ele deu o telefone para isso e o assunto é o serviço contratado. Divulgação, campanha e oferta são outra história: exigem consentimento e um caminho fácil de descadastro. Misturar as duas coisas no mesmo canal é o erro que transforma um número útil num número denunciado.

Sobre bloqueio de número, sem promessa mágica. Mensagem não solicitada aumenta o risco: quando muita gente denuncia ou bloqueia um número, o WhatsApp age. Esse risco existe em qualquer API — inclusive na oficial da Meta — e não pode ser eliminado, só reduzido com boas práticas: falar com quem espera ser falado, manter volume e ritmo compatíveis com uma clínica de verdade, responder quem responde e respeitar quem pediu para sair. Quem promete que o número nunca será bloqueado não está sendo honesto.

Dado de saúde: o que escrever e o que não escrever

O que não deve entrar no texto de uma mensagem de clínica?

Diagnóstico, resultado de exame, nome de procedimento sensível, medicação e qualquer detalhe clínico. A mensagem precisa de data, hora, local e uma ação — nada além. O WhatsApp do paciente pode estar aberto na mesa do trabalho, e a notificação mostra o texto antes de qualquer senha.

Escreva imaginando que a mensagem será lida por outra pessoa. "Sua consulta é amanhã às 14h30" é seguro; citar a especialidade ou o motivo não é. Para resultado, avise que um resultado disponível e diga como retirá-lo — não mande o conteúdo.

Quem consegue ler a mensagem depois de enviada?

A conversa fica no WhatsApp da clínica: quem tem acesso ao aparelho ou aos aparelhos conectados vê o histórico. Isso merece o cuidado que se dá à senha do sistema — bloqueio de tela e retirada dos aparelhos conectados quando alguém deixa a equipe. E o texto que você guardar no banco passa a fazer parte do que precisa ser protegido.

Preço, conexão e o que esperar do painel

Quanto custa para uma clínica com um número?

R$ 27 por mês por número conectado, sem cobrança por mensagem: o valor não muda se a clínica mandar 50 ou 5.000 lembretes. Cada número conectado tem cota de 300 mensagens por dia, o que cobre a agenda de uma clínica cheia e ainda segura o ritmo de envio que faz o WhatsApp bloquear número. O teste é de 14 dias sem cartão e a contagem só começa na primeira conexão — dá para criar a conta, escrever a integração com calma e só depois conectar o número.

É essa previsibilidade que torna o fluxo viável para clínica pequena: são três mensagens por consulta, e com cobrança por mensagem o custo cresceria com a agenda até alguém cortar o terceiro envio. Com mais de uma unidade, é uma conexão por unidade — e o seu sistema escolhe de qual número a mensagem sai trocando o header.

Como sei que a conexão continua de pé?

O painel mostra o estado de cada conexão e atualiza a cada 10 segundos enquanto a página está aberta. Para não depender de alguém olhar a tela, assine os eventos de conexão no webhook: Disconnected avisa a queda e LoggedOut avisa que o número precisa reler o QR Code. E quando uma chamada de envio falhar, registre numa lista visível — foi o que o registrarFalha fez — e faça alguém olhar essa lista todo dia. Lembrete que não saiu precisa virar tarefa, não silêncio.

Perguntas frequentes

Funciona com o sistema de agenda que a clínica já usa?

Funciona sempre que esse sistema conseguir fazer uma chamada HTTP ou exportar os agendamentos do dia. Se ele é próprio ou tem área de integrações, chama a API direto. Se é fechado, leia os dados por fora (relatório, banco, planilha) e dispare com uma ferramenta de automação no meio.

Preciso de servidor próprio para isso?

Não para enviar: qualquer coisa que faça uma requisição HTTP resolve, inclusive uma ferramenta no-code. Para receber a resposta por webhook, é preciso um endereço público que aceite POST — um endpoint do seu sistema, uma função serverless ou a URL de webhook de uma plataforma de automação.

E a LGPD? Posso tratar dado de paciente por WhatsApp?

A comunicação sobre um atendimento que o paciente agendou tem base na execução do serviço, e ele forneceu o telefone para isso. O que muda é a disciplina: minimize o conteúdo (data, hora, local e ação, sem dado clínico), registre o consentimento quando o assunto for divulgação, respeite o descadastro e proteja o que armazenar.

O WhatsApp pode bloquear o número da clínica?

Pode — em qualquer API, inclusive na oficial da Meta. O risco não é eliminável, é gerenciável: fale só com quem espera sua mensagem, mantenha volume e ritmo compatíveis com o tamanho da clínica e pare de enviar para quem pediu para sair. O que dispara bloqueio é mensagem não solicitada em massa, não o uso de API.

Quanto custa e tem limite de mensagens?

R$ 27 por mês por número conectado, sem cobrança por mensagem, com limite de 300 mensagens por dia por número — sobra para os lembretes de uma agenda cheia e uma barreira contra o disparo em massa que derruba a conexão. O teste é de 14 dias sem cartão e só começa a contar quando você conecta o primeiro número.

Dá para usar o mesmo número que a recepção já atende?

Dá, e costuma ser o melhor arranjo: o paciente responde para o número que conhece e a recepção continua atendendo no aparelho. A automação cuida dos avisos e das respostas previsíveis; o resto fica visível na conversa para uma pessoa tratar.

E se o paciente responder e ninguém vir a resposta?

Por isso a resposta vai para o seu sistema, e não só para a tela do celular. O webhook entrega cada mensagem recebida: o que a sua regra reconhece vira ação na agenda, e o que ela não reconhece vai para uma lista de pendências que a recepção olha todo dia. Resposta que não vira tarefa é resposta perdida.

Preciso da API oficial da Meta ou de conta WhatsApp Business?

Não. O número é conectado por QR Code ou código de pareamento, sem fila de aprovação, sem cadastro de template e sem custo por mensagem. Em compensação, a boa conduta do número é responsabilidade da clínica.

Outros casos de uso

Pare de perder horário por falta que ninguém avisou.

14 dias grátis, sem cartão — a contagem só começa quando você conectar o número. Crie a conta, leia o QR Code e mande o primeiro lembrete hoje.