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ó:
- O paciente que esquece. Resolve-se com lembrete, e quanto mais perto da consulta, melhor — por isso o fluxo tem dois: um na véspera, um no dia.
- O paciente que já sabe que não vai. Esse precisa é de um caminho fácil para avisar. Se cancelar exige ligar e esperar atendimento, ele não cancela; se é responder uma mensagem, ele cancela — e a clínica ganha um horário para remanejar.
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.
- Um número. Pode ser o que a clínica já divulga: a API opera o mesmo número, não o substitui, e a recepção continua usando o aparelho. Com várias unidades, uma conexão por unidade.
- Uma conexão no zapon. Cada conexão é um número e tem o seu
token, credencial de todas as chamadas daquele número. Conecta-se lendo o QR Code no painel (WhatsApp → Aparelhos conectados) ou por código de pareamento.
- Quem dispara. Ou o seu sistema chama os endpoints, ou uma ferramenta de automação lê a agenda e chama a API por HTTP.
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.
- Só fale do que o paciente marcou. Confirmação, lembrete, remarcação, preparo, resultado disponível — conteúdo operacional, que ele espera. Promoção de procedimento é marketing e pede consentimento explícito, registrado e com data.
- Horário civilizado. Lembrete de véspera cabe no fim da tarde; o do dia, de manhã. Mensagem de clínica às 22h assusta mais do que ajuda — e mensagem que assusta vira denúncia. Se a rotina falhar e só for rodar às 23h, segure para o dia seguinte.
- Descadastro que funciona. Quem pede para não receber precisa parar de receber, em todas as rotinas. Guarde num campo do cadastro e faça toda rotina consultá-lo antes de enviar — foi o que o
optOut do exemplo em Node fez. O pedido chega em qualquer palavra ("para de mandar"), então alguém precisa olhar a fila de exceções todo dia.
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 há 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.