MeetCal: Por Que Construí um Calendly Dentro do Telegram
Todo 'podemos conversar?' no Telegram termina com um link do Calendly no navegador. O MeetCal mantém todo o agendamento em uma conversa
Tem um momento específico que me quebrou.
Alguém me manda uma mensagem no Telegram: “podemos dar um call essa semana?” Respondo: “claro, aqui está meu Calendly.” Ela clica, o navegador abre, carrega devagar no mobile, talvez peça pra criar uma conta, talvez dê timeout. Cinco minutos depois, ela está de volta no Telegram confirmando o horário. A conversa inteira agora está dividida entre dois apps e uma aba de navegador.
Isso acontece dezenas de vezes por semana. Construí o MeetCal porque enjoei dessa divisão.
O problema do Calendly no Telegram
O Calendly está ótimo. Ele faz o que diz. Mas a premissa do produto embutida nele é que o agendamento é uma tarefa autônoma — algo que você navega deliberadamente, como comprar uma passagem aérea.
O agendamento no Telegram não funciona assim. “Podemos conversar?” é uma frase jogada no meio de uma conversa sobre outra coisa qualquer. Quando você solta um link do Calendly nesse momento, você está pedindo para a outra pessoa pausar, trocar de contexto, completar um fluxo em múltiplos passos numa interface estranha e depois voltar. Metade das vezes o momentum foi embora quando ela retorna.
A fricção não são só os passos extras. É a quebra no fio da conversa. A troca de contexto sinaliza “isso agora é uma tarefa formal de agendamento” quando tudo que você queria era encontrar uma hora livre.
O que o MeetCal faz
O host configura a disponibilidade uma vez no bot. A partir daí, você pode compartilhar seu cartão de reserva inline — digita @MeetCalBot em qualquer conversa do Telegram e ele insere um cartão rico de preview diretamente na conversa. O convidado toca nele, um Mini App abre dentro do Telegram, ele escolhe um horário, pronto. Sem navegador, sem e-mail, sem criação de conta.
Confirmações e lembretes chegam como mensagens no Telegram. O loop inteiro — sugerir, reservar, confirmar, lembrar — fica em um só lugar.
A parte do compartilhamento inline importa mais do que parece. Significa que você não precisa sair do chat para compartilhar sua agenda. Você só digita o nome do bot no meio da mensagem e o cartão aparece. O destinatário nunca vê um link cru.
O problema técnico mais difícil
O app é React + Vite. O Telegram Mini Apps te dá acesso ao WebApp.MainButton, que é o botão na parte inferior da tela que flutua sobre o conteúdo. É o botão de ação principal em quase todo Mini App.
A API é imperativa: MainButton.show(), MainButton.hide(), MainButton.setText('Reservar horário'), MainButton.showProgress(). Você chama os métodos, o Telegram cuida da renderização.
React é declarativo. Você descreve o estado, o React decide o que renderizar.
O descompasso criou um bug específico: toda vez que o estado do componente mudava — mesmo um estado não relacionado ao botão — o botão piscava. Ele desaparecia por um único frame antes de reaparecer com o texto correto. Na tela de um celular, isso parece quebrado.
A causa raiz era que eu tinha um único useEffect assistindo todo o estado relacionado ao botão e chamando show() e depois setText() a cada render. O breve hide() entre os renders estava visível.
A correção foi dividir o hook em efeitos separados com arrays de dependência separados. Um efeito roda apenas na montagem para inicializar o botão e anexar o handler de clique. Um efeito separado roda apenas quando o texto do botão ou o estado de carregamento muda, e nunca chama hide() — apenas setText() e showProgress(). A visibilidade é gerenciada de forma independente com seu próprio efeito que só dispara quando a flag de visível muda.
Três efeitos em vez de um. Cada um com um array de dependência mínimo. O piscar parou.
É uma coisa pequena, mas levou meio dia para isolar, e é o tipo de coisa que define se um app parece nativo ou travado.
O que a plataforma Mini App acerta e erra
Acerta: a distribuição é gratuita. Se o bot funciona, as pessoas o encontram pela busca inline. Sem revisão da app store, sem etapa de instalação. As primitivas de UI do Telegram — MainButton, BackButton, feedback háptico, o sheet de compartilhamento nativo — são suficientes para construir algo que parece um app de verdade.
Erra: a experiência de debug é complicada. Erros no Mini App aparecem de formas difíceis de rastrear. O objeto WebApp se comporta de forma diferente entre os clientes Telegram (desktop, iOS, Android) de maneiras não documentadas. Passei um dia depurando um problema de layout que só reproduzia no Android porque o cálculo da altura do viewport inclui o teclado em uma plataforma e não na outra.
A plataforma é jovem. Você sente isso. Mas as restrições te empurram para UIs mais simples, o que geralmente é uma coisa boa.
Estado atual
O MeetCal tem três planos: gratuito (reservas básicas, slots limitados por mês), Starter e Pro. Os planos pagos desbloqueiam disponibilidade recorrente, buffers personalizados entre reuniões e algumas outras coisas que os power users pedem.
A monetização é via Telegram Stars — a moeda interna do Telegram. É um encaixe natural porque os usuários nunca saem da plataforma para pagar. A conversão de gratuito para pago ainda está no início, mas quem paga tende a usar o produto de verdade.
O que eu faria diferente
Gastaria menos tempo polindo o fluxo de reserva na primeira versão e mais tempo no onboarding do host. O momento em que alguém configura sua disponibilidade pela primeira vez é onde a maioria das pessoas desiste. O fluxo funciona, mas não é óbvio o suficiente. Fiquei otimizando a experiência do convidado — a pessoa que reserva — quando a experiência do host era o verdadeiro gargalo.
Também: teria lido o changelog do Telegram Mini Apps com mais cuidado antes de começar. Houve mudanças de API entre quando comecei a construir e quando publiquei que exigiram reescrever partes da camada de autenticação. Lição: trate a plataforma como instável até ter publicado ao menos uma versão.
A aposta central ainda se sustenta. Mensagens é onde a atenção vive. O agendamento deveria viver lá também.