InícioCasos de uso › API de WhatsApp para odontologia

API de WhatsApp para clínica odontológica: confirmação de sessão, lembrete por bloco e recall automáticos

Em odontologia a falta não custa vinte minutos: custa a cadeira, o dentista e a auxiliar parados por uma manhã inteira. Com a API do zapon, o seu software odontológico confirma a sessão no fechamento do plano, ajusta a antecedência do lembrete ao tamanho do bloco e recebe a resposta do paciente por webhook.

A agenda de uma clínica odontológica não é feita de encaixes iguais. Uma limpeza ocupa trinta minutos; uma sessão de canal, noventa; uma prótese sobre implante pode passar de duas horas. Quando a falta cai num bloco longo, não há remanejamento de última hora: a cadeira fica vazia, o cirurgião-dentista fica sem produção e a auxiliar de saúde bucal fica esperando.

O outro buraco é silencioso. O paciente aprova o orçamento, faz duas sessões e some no meio do plano de tratamento — e ninguém percebe, porque não havia horário marcado para ele faltar. Este texto mostra como fechar os dois com uma API de WhatsApp: REST, header token, JSON entrando e saindo, chamada pelo sistema que já conhece a sua agenda.

A dor da odontologia é a cadeira ociosa em bloco longo

Por que a falta em clínica odontológica custa mais do que em outros consultórios?

Porque a unidade de produção é a cadeira, reservada em blocos. Um bloco de noventa minutos que cai às sete da manhã não se preenche às oito: quem está na lista de espera precisa se deslocar, e o procedimento que entraria no lugar raramente cabe naquele tempo.

São três perdas diferentes, tratadas quase sempre como uma só:

Por que a secretária ligando na véspera não dá conta?

A ligação não distingue bloco curto de bloco longo, e acontece no dia anterior — tarde demais para reorganizar noventa minutos. A resposta pelo WhatsApp chega como evento com telefone, horário e conteúdo, que vira status na agenda.

Tratamento em sessões: avise a sequência, não só a próxima

Devo avisar só a próxima sessão ou o plano de tratamento inteiro?

Os dois, em momentos diferentes. No fechamento do plano, a mensagem descreve a sequência completa — quantas sessões, o que acontece em cada uma e quanto tempo cada uma ocupa. Depois, cada lembrete cuida de uma sessão só. Quem enxerga o plano inteiro entende que faltar não atrasa um dia, atrasa o tratamento.

Um plano de endodontia em duas sessões, seguido de núcleo e coroa, tem dependência entre as etapas. Quem só recebe o aviso da próxima trata cada sessão como evento isolado e negociável. Quem recebe a sequência vê um compromisso com começo e fim — e a clínica ganha um argumento honesto para pedir antecedência maior nos blocos grandes.

Como a mensagem do fim de cada sessão ancora a próxima?

A hora de marcar a sessão seguinte é enquanto o paciente ainda está na clínica. A automação fixa isso por escrito: encerrada a sessão no sistema, sai uma mensagem curta com a data da próxima, a duração prevista e o que ele precisa fazer até lá. Sem essa âncora, a sessão seguinte vira uma intenção que depende de o paciente ligar.

E se o orçamento foi aprovado mas nenhuma sessão foi marcada?

É o caso que mais escapa, porque não existe agendamento para rotina nenhuma varrer. Trate por data: busque planos com orçamento aprovado há sete dias e sem primeira sessão marcada, e dispare uma mensagem única. Sem resposta, vira tarefa da secretária — não uma segunda e uma terceira mensagem.

O que a clínica precisa ter antes do primeiro disparo

O que preciso para avisar paciente de odontologia por WhatsApp automaticamente?

Um número de WhatsApp que a clínica controle, uma conexão no zapon com esse número lido por QR Code ou código de pareamento, e um sistema que saiba quais sessões existem, com data, hora e duração. A duração é o dado que a maioria das clínicas já tem no software e nunca usou para nada além de desenhar o bloco na tela.

O meu software odontológico precisa ter integração pronta?

Não. Se ele executa código ou tem área de integrações, chama os endpoints direto. Se é fechado, leia os dados por fora — relatório, banco, exportação de agenda — e dispare dali. O que a API precisa saber é sempre o mesmo: telefone e texto.

O fluxo da clínica odontológica, passo a passo

Como funciona o fluxo de confirmação e lembrete de sessão ponta a ponta?

Cinco etapas: (1) o plano de tratamento é fechado e o paciente recebe a sequência de sessões com duração e preparo; (2) o lembrete sai com antecedência proporcional ao tamanho do bloco; (3) no dia sai o preparo específico daquela sessão; (4) o paciente confirma, remarca ou cancela; (5) a régua de recall cuida de quem terminou o tratamento e sumiu.

Cada passo tem função própria. Repetir a mesma mensagem três vezes é o jeito mais rápido de virar ruído e ser silenciado.

1. O que enviar quando o plano de tratamento é fechado?

A mensagem registra o combinado por escrito e valida o telefone do cadastro: se a entrega falhar aqui, você descobre hoje, não na véspera da cirurgia. Ela traz a sequência de sessões, a duração de cada uma e o preparo — comer antes, não dirigir depois da anestesia, quem acompanha. Não peça confirmação agora: confirmação dada com três semanas de antecedência não vale nada.

2. Como escalonar o lembrete pela duração do bloco?

É aqui que a odontologia se separa de um consultório de horários iguais. Bloco curto — limpeza, manutenção de aparelho, avaliação — pede lembrete só na véspera. Bloco longo — canal, prótese, cirurgia — pede aviso 48 horas antes, porque cancelar noventa minutos com um dia de antecedência ainda deixa a cadeira parada. Este é o passo com botões, cada um carregando o identificador da sessão.

3. Qual é o conteúdo do lembrete do dia?

Curto e logístico: horário, quando chegar, o que trazer — carteirinha do convênio odontológico, guia autorizada, radiografia feita fora — e o que não fazer, como não comer antes de sedação. Se a sessão foi cancelada no passo anterior, este envio não pode acontecer: leia o status no instante do envio, nunca uma lista congelada na véspera.

4. O que acontece quando o paciente responde?

A resposta chega ao seu sistema por webhook: telefone, identificador da mensagem, horário e conteúdo — e, quando é botão, o id que você definiu. Confirmar e cancelar são automáticos. Remarcação de bloco longo, não: depende de casar a agenda do especialista com a cadeira e com o tempo necessário, então vira tarefa da secretária.

5. Como o recall alcança quem sumiu depois do tratamento?

É o único passo que não parte de um horário marcado. A rotina varre a data do último atendimento: manutenção de aparelho a cada 30 dias, profilaxia a cada 6 meses. Vencido o intervalo, sem sessão futura agendada, o paciente entra na régua — uma mensagem, com opção clara de sair, e o registro do envio para não repetir no mês seguinte.

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

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

Três resolvem o fluxo inteiro: POST /chat/send/text para as mensagens, POST /chat/send/buttons para o lembrete de bloco longo com resposta em um toque, e POST /user/check para limpar a base antes do recall. Base https://api.zapon.dev, header token. São 49 endpoints publicados, todos com schema, mas a 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.

Como enviar a confirmação de uma sessão de endodontia?

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

confirmação de sessão — cURL
curl -X POST https://api.zapon.dev/chat/send/text \
  -H "token: SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "Phone": "5511977770001",
    "Body": "Rafael, sua sessão está agendada.\n\nData: 18/03 (quarta)\nHorário: 08h00\nDuração prevista: 90 minutos\nDentista: Dra. Helena Muniz — cadeira 2\n\nComa alguma coisa leve antes. Usaremos anestesia local, então prefira não dirigir na volta. Para remarcar, responda por aqui — blocos longos precisam de 48h de antecedência."
  }'

A resposta traz o identificador da mensagem:

resposta da API
{
  "code": 200,
  "success": true,
  "data": {
    "Details": "Sent",
    "Id": "7C41A0DE93B25F18AA0C7761E4D2B9F3",
    "Timestamp": "2026-03-02T11:47:15-03:00"
  }
}

Grave esse Id junto da sessão: é ele que prova qual mensagem saiu e impede reenvio duplicado.

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

O /chat/send/buttons envia botões de resposta rápida, com rótulo curto. Cada um carrega um id definido por você, e é ele que volta no webhook — coloque o número da sessão ali dentro e a resposta chega amarrada ao registro certo, 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 de bloco longo — botões
POST https://api.zapon.dev/chat/send/buttons
token: SEU_TOKEN

{
  "Phone": "5511977770001",
  "Body": "Rafael, sua sessão é depois de amanhã, 18/03, às 08h00, com duração prevista de 90 minutos. Podemos confirmar a cadeira?",
  "Footer": "Odonto Vila Nova",
  "Buttons": [
    { "id": "sess3140|confirmar", "text": "Confirmar" },
    { "id": "sess3140|remarcar",  "text": "Remarcar" },
    { "id": "sess3140|cancelar",  "text": "Cancelar" }
  ]
}

Como a rotina decide a antecedência de cada lembrete?

Uma rotina só, todo dia, olha duas janelas: as sessões de amanhã e as de depois de amanhã. A duração decide qual entra em qual — bloco de 60 minutos ou mais dispara em D-2; o resto, em D-1.

lembrete escalonado por duração — Node
// lembretes.js — roda todo dia às 17h
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));

// bloco >= 60 min avisa em D-2; sessão curta, em D-1
const janela = (min) => (min >= 60 ? 2 : 1);

for (const s of await sessoesEntre(1, 2)) {          // amanhã e depois de amanhã
  if (s.status !== "agendada" || s.paciente.optOut) continue;
  if (s.diasAte !== janela(s.duracaoMin)) continue;    // ainda não é a vez dela
  if (await jaEnviado(s.id, "lembrete")) continue;      // não duplica
  try {
    const quando = s.diasAte === 2 ? "depois de amanhã" : "amanhã";
    const id = await enviarTexto(s.paciente.telefone,
      `${s.paciente.nome}, sua sessão é ${quando}, ${s.data}, às ${s.hora} ` +
      `(${s.duracaoMin} min, cadeira ${s.cadeira}).\n\n` +
      `Responda 1 para confirmar, 2 para remarcar ou 3 para cancelar.`);
    await registrarEnvio(s.id, "lembrete", id);         // guarda o Id da API
  } catch (e) {
    await registrarFalha(s.id, "lembrete", String(e));   // vira tarefa da secretária
  }
  await pausa(5000);   // ritmo humano: nada de rajada
}

Quatro linhas sustentam o laço. O primeiro continue impede lembrete de sessão cancelada e de quem pediu para sair. O segundo garante um lembrete só por sessão, na janela certa para o tamanho dela. O jaEnviado torna a rotina segura para rodar de novo. E a pausa evita despejar a agenda inteira no mesmo segundo, comportamento que não se parece com uma clínica.

A resposta do paciente: webhook, regra e fila da secretária

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 naquele número vira um POST nessa URL, com o conteúdo inteiro no corpo. Não há nada para ficar consultando de tempos em tempos.

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": "3EB0A94C71D8E2F60B15",
      "Chat": "[email protected]",
      "Sender": "[email protected]",
      "IsFromMe": false, "IsGroup": false,
      "PushName": "Rafael Andrade",
      "Timestamp": "2026-03-16T17:22:40-03:00"
    },
    "Message": { "conversation": "1" }
  }
}

// quando ele toca num botão, muda só o bloco Message:
    "Message": { "buttonsResponseMessage": {
      "selectedButtonID": "sess3140|remarcar",
      "Response": { "SelectedDisplayText": "Remarcar" }
    } }

Duas observações 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, então ignore, ou a secretária respondendo um paciente aciona a sua automação.

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

Identifique a sessão pelo id do botão, decida pela intenção e responda ao paciente dizendo o que foi feito. Repare na remarcação: o bloco longo não é remarcado sozinho.

receptor do webhook — Node/Express
app.post("/wpp/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 fica fora
  if (await jaProcessado(info.ID)) return;     // o mesmo evento pode vir 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 s = botao ? await buscarSessao(botao.split("|")[0].replace("sess", ""))
                 : await proximaSessaoPorTelefone(telefone);
  if (!s) return filaDaSecretaria(telefone, texto);

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

  if (acao === "confirmar") {
    await atualizarStatus(s.id, "confirmada");
    return enviarTexto(telefone, `Confirmado. Te esperamos ${s.data} às ${s.hora}.`);
  }
  if (acao === "cancelar") {
    await atualizarStatus(s.id, "cancelada");
    await liberarBloco(s.cadeira, s.data, s.hora, s.duracaoMin); // lista de espera
    return enviarTexto(telefone, "Sessão cancelada. Chame a gente para reagendar.");
  }
  if (acao === "remarcar") {
    await atualizarStatus(s.id, "remarcar");
    // bloco longo depende da agenda do especialista: não remarque sozinho
    await filaDaSecretaria(telefone, `remarcar sessão ${s.id} (${s.duracaoMin} min)`);
    return enviarTexto(telefone, "Certo. A recepção vai te chamar com as opções de horário.");
  }
  return filaDaSecretaria(telefone, texto);     // o resto é assunto de gente
});

E se o paciente responder com uma dúvida clínica?

Ele vai responder. "Está doendo, é normal?", "o ponto abriu". Nada disso pode ser respondido por automação. O que a sua regra não reconhece vai para uma fila que uma pessoa olha, e a conversa continua no WhatsApp da clínica. Automatize horário e logística; conduta é de profissional habilitado.

A régua de recall: profilaxia semestral e manutenção do aparelho

Qual é a diferença entre lembrete de agendamento e régua de recall?

O lembrete parte de um horário que existe: há data, hora e cadeira reservada, e a mensagem é esperada. O recall parte de um intervalo vencido — seis meses desde a última profilaxia, trinta dias desde a última manutenção de aparelho — e não há nada marcado. Por isso ele exige mais cuidado: é a clínica quem inicia a conversa.

As duas réguas têm cadências diferentes. A de manutenção de aparelho ortodôntico é mensal e previsível: quem usa aparelho sabe que precisa voltar, e o aviso funciona como serviço. A de profilaxia é semestral e mais delicada, porque atinge gente que não pisa na clínica há muito tempo.

Como escrever a mensagem de recall sem parecer propaganda?

Fale do intervalo, não da oferta. "Sua última limpeza foi em setembro; a próxima está prevista para março" é informação sobre o tratamento da pessoa. "Limpeza com 30% de desconto" é campanha. Frase de saída explícita no fim, sempre, e frequência baixa: um recall por intervalo vencido, não um por mês até responder.

Como limpar a base antes de disparar o recall semestral?

Recall de seis meses é o primeiro contato com telefone antigo, e cadastro de clínica acumula fixo, número trocado e dígito faltando. O POST /user/check recebe uma lista e diz quais têm conta no WhatsApp. Envie só para os válidos e marque os demais como pendência de cadastro.

limpeza da base antes do recall — cURL
curl -X POST https://api.zapon.dev/user/check \
  -H "token: SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "Phone": ["5511977770001", "551133334444"] }'

// resposta — o fixo antigo do cadastro não tem WhatsApp
{ "code": 200, "success": true, "data": { "Users": [
  { "Query": "5511977770001", "IsInWhatsapp": true,  "JID": "[email protected]" },
  { "Query": "551133334444",  "IsInWhatsapp": false, "JID": "" }
] } }

São 13 formas de envio ao todo — 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, presença de "digitando", marcar como lido e histórico. Fora do trio principal, servem à odontologia a localização, no lembrete do dia, e o documento, para a orientação pós-operatória em PDF.

Consentimento, publicidade odontológica e sigilo

Posso mandar mensagem para qualquer paciente da base da clínica?

Depende do assunto. Mensagem sobre um tratamento em curso é esperada: o paciente deu o telefone para isso. Recall de profilaxia em quem não volta há dois anos é fronteira — exige consentimento registrado e descadastro que funcione. Divulgação de clareamento, implante ou preço é marketing puro e não pode entrar no mesmo canal como se fosse aviso de agenda.

O que não pode entrar no texto da mensagem?

Nome de procedimento sensível, diagnóstico, achado de radiografia, imagem de exame. A notificação aparece na tela travada e pode ser lida por qualquer um perto do celular. "Sua sessão é quarta às 8h, duração de 90 minutos" é seguro; dizer qual dente e qual problema, não. Na orientação pós-operatória, escreva o cuidado sem descrever a condição.

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. Em odontologia o ponto de atenção é o recall: é a régua que mais se parece com disparo em massa, porque atinge muita gente de uma vez e fala com quem não tem nada marcado. Mantenha volume e ritmo compatíveis com o tamanho da clínica, respeite quem pediu para sair e responda quem responde. Quem promete que o número nunca será bloqueado não está sendo honesto.

Preço, cadeiras e o estado da conexão

Quanto custa para uma clínica odontológica 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 enviar 80 ou 4.000 mensagens no mês. O que existe é uma cota de 300 mensagens por dia por número conectado — um teto de ritmo, não de bolso, que impede a clínica de virar um disparador aos olhos do WhatsApp e perder o número da recepção. O teste é de 14 dias sem cartão e a contagem só começa na primeira conexão, então dá para criar a conta, escrever a integração com calma e conectar o número depois.

Essa previsibilidade é o que torna o fluxo viável em odontologia, onde cada plano gera muitas mensagens: confirmação, lembrete de cada sessão, preparo do dia, âncora da próxima e recall. Com cobrança por mensagem, o custo cresceria junto com o tratamento até alguém cortar justamente a régua que sustenta a sequência.

Clínica com vários dentistas precisa de um número por cadeira?

Não. O critério é o número que o paciente conhece, não a cadeira: quatro cadeiras e um telefone divulgado usam uma conexão, e a mensagem diz quem é o dentista. Separar faz sentido com marcas ou endereços distintos — aí é uma conexão por número, e o seu sistema escolhe de qual sai a mensagem trocando o header token.

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 seu webhook: Disconnected avisa a queda e LoggedOut avisa que o número precisa ler o QR Code de novo. E toda falha de envio deve virar item numa lista que alguém confere todo dia — foi o papel do registrarFalha.

Perguntas frequentes

Como tratar o paciente de aparelho, que volta todo mês?

Ele entra em duas réguas ao mesmo tempo e você precisa evitar sobreposição. Se a manutenção já está marcada, vale só o lembrete de véspera, porque é bloco curto. Se o mês virou sem agendamento, entra a régua de recall de 30 dias, contada a partir do último atendimento. Uma mensagem por ciclo, com opção de sair, e o registro do envio para não repetir.

Dá para avisar o pós-operatório de uma exodontia pelo WhatsApp?

Dá, e é um dos usos mais bem recebidos. A mensagem pode trazer cuidado e logística: compressa, alimentação fria, evitar esforço, horário do retorno para avaliação e o telefone da clínica se algo fugir do previsto. O que ela não pode fazer é avaliar sintoma, ajustar medicação ou dizer se algo é normal — isso é conduta, e conduta é do cirurgião-dentista.

Como pedir antecedência maior em bloco longo sem parecer grosseiro?

Explicando o motivo em vez de anunciar a regra. A frase que funciona diz que a sessão reserva a cadeira e o dentista por noventa minutos e que, com 48 horas, a clínica consegue oferecer o horário a outro paciente. O pedido deixa de soar como ameaça de multa e passa a soar como organização. Coloque isso já na confirmação do plano, não só no lembrete.

Clínica com vários dentistas deve usar um número ou vários?

Em geral um só: o paciente responde para o número que já conhece e a mensagem identifica o profissional e a cadeira. Vários números fazem sentido quando há unidades diferentes, marcas diferentes ou um especialista que atende com agenda e identidade próprias. Cada número é uma conexão, com o seu token e a sua assinatura mensal.

E o convênio odontológico, dá para tratar guia e autorização por lá?

Dá para avisar e cobrar o que falta, que é onde a clínica costuma perder tempo: lembrar de trazer a carteirinha, avisar que a guia foi autorizada e que a sessão pode ser marcada, ou que a autorização venceu e precisa de nova solicitação. A negociação com a operadora continua fora do WhatsApp; o canal serve para o paciente saber em que pé está.

E se o paciente responder com dúvida clínica, tipo "está doendo, é normal?"

A automação não responde. Ela reconhece confirmação, remarcação e cancelamento; qualquer outra coisa vira pendência para uma pessoa. A conversa fica visível no WhatsApp da clínica, a secretária responde ou encaminha ao dentista, e o papel do sistema é apenas sinalizar que aquela conversa está esperando resposta.

Quanto custa, qual é o limite diário de mensagens e dá para testar antes?

R$ 27 por mês por número conectado, sem cobrança por mensagem, com cota de 300 mensagens por dia por número conectado. A cota não é comercial: ela segura o ritmo para o WhatsApp não classificar a clínica como robô de disparo. O teste é de 14 dias sem cartão e só começa a contar quando você conecta o primeiro número, então dá para montar a integração com a agenda antes de gastar um dia sequer do período.

Outros casos de uso

Cadeira parada não se recupera no dia seguinte.

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 lembrete da primeira sessão longa hoje.