Blog
Tecnologia

Comparativo técnico: webhooks vs. polling em sistemas de agendamento

Atualizado em eAgenda

Polling

Quem integra um sistema de agendamento a um CRM, a um ERP ou a um painel próprio precisa decidir cedo como os dois lados vão se manter sincronizados. Existem duas respostas, e a escolha entre elas define latência, custo de infraestrutura e quantos pontos de falha o integrador vai ter que monitorar depois.

No polling, o seu sistema pergunta de tempos em tempos: um GET /api/v3/appointments/ a cada cinco minutos, por exemplo. No webhook, a plataforma avisa — uma requisição HTTP chega ao seu endpoint no instante em que o agendamento é criado ou alterado.

A diferença parece só de direção, mas as consequências não são simétricas.

O custo escondido do polling é a razão entre consultas e eventos

Polling é mais simples de implementar. Não exige endpoint público, não exige tratar retentativa de entrega, e o integrador controla a frequência. Para quem está começando ou precisa de algo funcionando no mesmo dia, é o caminho mais curto.

O problema aparece na aritmética. Uma consulta a cada cinco minutos são 288 requisições por dia por conta integrada. Se a agenda recebe 20 agendamentos diários, 268 dessas requisições não trouxeram novidade alguma — mais de 90% de tráfego descartado, pago pelos dois lados. Quando a integração cresce para dezenas de contas, o desperdício cresce junto, e a resposta natural é aumentar o intervalo, o que piora a latência.

E a latência do polling é sempre pior do que parece. Com ciclo de cinco minutos, o atraso médio é de dois minutos e meio, mas o pior caso é cinco. Para relatório diário isso é irrelevante. Para avisar um profissional de que a próxima consulta acabou de ser cancelada, cinco minutos é a diferença entre reocupar o horário e perdê-lo.

Webhook troca simplicidade por infraestrutura

O webhook resolve os dois problemas de uma vez: só há tráfego quando há evento, e a notificação chega em segundos. Em troca, transfere responsabilidade para o lado de quem integra.

Você precisa de um endpoint acessível pela internet, disponível quando o evento acontecer. Precisa validar a origem da requisição, porque um endpoint público que aceita qualquer POST é um convite a dados forjados — token no header ou assinatura HMAC no corpo resolvem. E precisa decidir o que fazer quando seu sistema estiver fora do ar no momento da entrega.

Esse último ponto é o que costuma ser subestimado. Polling é resiliente por natureza: se o seu processo caiu, o próximo ciclo busca tudo o que ficou para trás. Webhook não tem essa propriedade — evento perdido durante uma janela de indisponibilidade não volta sozinho. Na prática, integrações sérias com webhook mantêm um polling de baixa frequência como rede de segurança, justamente para reconciliar o que escapou.

CritérioPollingWebhooks
LatênciaMetade do intervalo, na médiaSegundos
Uso de recursosAlto — requisições mesmo sem novidadeBaixo — só quando há evento
ComplexidadeBaixaMédia: endpoint, autenticação, retentativa
Recuperação após quedaAutomática no próximo cicloExige reconciliação
Onde faz sentidoRelatórios, carga histórica, batch noturnoCancelamento, confirmação, notificação ao cliente

Implementando polling

Um agendador dispara a consulta em intervalo fixo. O exemplo abaixo usa schedule e requests, mas a lógica é a mesma em qualquer stack — inclusive em um cron job do sistema, que costuma ser mais robusto que manter um processo Python vivo indefinidamente.

import requests
import schedule
import time

def fetch_appointments():
    url = "https://eagenda.com.br/api/v3/appointments/"
    headers = {
        "Authorization": "Bearer seu-token-aqui",
        "Content-Type": "application/json"
    }
    params = {
        "account_slug": "minha-conta",
        "status": "CONFIRMED",
        "start_date": "2025-06-01T00:00:00Z",
        "end_date": "2025-06-30T23:59:59Z",
        "page_size": 10
    }
    response = requests.get(url, headers=headers, params=params)
    if response.status_code == 200:
        print("Agendamentos:", response.json()["results"])
    else:
        print("Erro:", response.status_code)

schedule.every(5).minutes.do(fetch_appointments)

while True:
    schedule.run_pending()
    time.sleep(60)

Duas melhorias valem o esforço desde o início: filtrar por data de modificação em vez de reprocessar a janela inteira a cada ciclo, e tratar a paginação — page_size: 10 funciona no teste e falha silenciosamente no primeiro dia de movimento real.

Implementando webhook

Do lado receptor, o endpoint precisa responder rápido e validar antes de processar.

const express = require('express');
const app = express();
app.use(express.json());

app.post('/eagenda-webhook', (req, res) => {
    // Valide o token antes de qualquer processamento
    if (req.headers['x-webhook-token'] !== process.env.WEBHOOK_TOKEN) {
        return res.status(401).send('Unauthorized');
    }
    // Responda primeiro, processe depois: entrega lenta vira retentativa
    res.status(200).send('OK');
    enfileirarEvento(req.body);
});

app.listen(3000, () => console.log('Webhook rodando na porta 3000'));

Responder 200 antes de processar não é detalhe de estilo. Se o seu handler leva oito segundos para gravar no banco e a plataforma considera a entrega falha após cinco, você recebe o mesmo evento repetidamente. Enfileirar e confirmar rápido evita esse laço — e obriga o processamento a ser idempotente, já que reentrega é normal em qualquer sistema de webhook.

O payload entregue traz o agendamento completo, o que dispensa uma segunda chamada à API para buscar detalhes:

{
    "appointment_key": "191e1237-0240-4000-8ac1-60bcc5ae8701",
    "status": "ATTENDED",
    "calendar": {
        "calendar_key": "191e1237-0240-4000-85e4-6430bf42cf01",
        "calendar_name": "Agenda Principal"
    },
    "service_list": [
        {
            "service_key": "191e1237-0240-4000-81be-0e5d361a8501",
            "service_name": "Consulta Médica"
        }
    ],
    "tag_list": [
        {
            "tag_key": "191e1237-0240-4000-8921-719af633b401",
            "label": "Urgente"
        }
    ],
    "attendees": [
        {
            "person_key": "191e1237-0240-4000-8ed4-9fac97c84d01",
            "name": "João Silva",
            "email": "joao.silva@example.com",
            "phone": "+5511942529100"
        }
    ],
    "owner_user": {
        "email": "admin@example.com",
        "full_name": "Dr. Maria Souza"
    },
    "start": {
        "dateTime": "2025-06-01T10:00:00Z",
        "timeZone": "UTC"
    },
    "end": {
        "dateTime": "2025-06-01T10:30:00Z",
        "timeZone": "UTC"
    },
    "created_at": {
        "dateTime": "2025-06-01T09:58:00Z",
        "timeZone": "UTC"
    },
    "location": "Clínica Central",
    "conference_data": {
        "provider": "zoom",
        "url": "http://example.com",
        "label": "Reunião Online",
        "pin": "123456",
        "access_code": "7890",
        "meeting_code": "123456789",
        "passcode": "abc123"
    },
    "event": "appointment.created"
}

Repare no campo event: o mesmo endpoint recebe criação, atualização e cancelamento, então o roteamento por tipo de evento precisa existir desde a primeira versão. Tratar tudo como criação funciona até o primeiro cancelamento chegar.

Como decidir

A pergunta útil não é qual tecnologia é melhor, e sim quanto atraso o seu caso tolera. Se a resposta for “alguns minutos não fazem diferença” — sincronização de relatório, carga histórica, conciliação noturna —, polling entrega o resultado com menos peça para manter, e não há mérito em complicar.

Se a resposta envolver alguém esperando do outro lado — cliente que precisa saber que a consulta foi confirmada, profissional que quer reocupar um cancelamento, CRM que dispara fluxo a partir do agendamento —, o webhook é o caminho, com a ressalva de que ele exige tratar autenticação, idempotência e reconciliação. Pular essas três coisas produz uma integração que funciona na demonstração e falha em produção.

Consulte a documentação da API