LeadNest Bot — Telegram

Bot de cualificación y onboarding de leads para SaaS B2B · grammY · Node.js · Railway

Listo para producción grammY v1.x Node.js 20 Railway Deploy
Comandos
5
/start /demo /precios /faq /contacto
Flujos conv.
3
demo · plan-upgrade · faq-detalle
Teclados inline
8
menú, planes, FAQ, navegación, back…
Límite rate
30/s
global · 1 msg/s en grupos
Deploy
WH
Webhooks HTTPS en Railway
📁 Estructura del proyecto
árbol leadnest-bot/
# leadnest-bot/ — grammY + Node.js 20
leadnest-bot/
├── bot.js              # Entry point: init + webhooks
├── handlers/
│   ├── commands.js     # /start, /help, /precios, /contacto
│   ├── callbacks.js    # Inline keyboard actions
│   ├── conversations.js# Flujos multi-paso (demo)
│   └── middleware.js   # Rate limit, logging, auth admin
├── keyboards/
│   ├── menu.js         # Teclado menú principal
│   ├── precios.js      # Selector de plan
│   └── faq.js          # Árbol de FAQs
├── services/
│   ├── notify.js       # Notif. Slack webhook al equipo ventas
│   └── leads.js        # Persistencia leads (JSON/Supabase)
├── .env                # BOT_TOKEN, WEBHOOK_URL, ADMIN_ID
└── package.json        # grammy, dotenv, express
⚡ bot.js — Entry point
bot.js Entry point
import { Bot, session, webhookCallback } from 'grammy';
import { conversations, createConversation } from '@grammyjs/conversations';
import express from 'express';
import 'dotenv/config';
import { registerCommands } from './handlers/commands.js';
import { registerCallbacks } from './handlers/callbacks.js';
import { demoFlow } from './handlers/conversations.js';
import { rateLimiter, logger } from './handlers/middleware.js';

const bot = new Bot(process.env.BOT_TOKEN);

// Middleware global
bot.use(session({ initial: () => ({ step: 'idle', demoData: {} }) }));
bot.use(conversations());
bot.use(createConversation(demoFlow, 'demo'));
bot.use(rateLimiter({ max: 5, windowMs: 10000 }));
bot.use(logger);

// Registrar handlers
registerCommands(bot);
registerCallbacks(bot);

// Webhook para producción (Railway)
const app = express();
app.use(express.json());
app.post(`/bot${process.env.BOT_TOKEN}`,
  webhookCallback(bot, 'express'));

app.listen(process.env.PORT || 3000, async () => {
  await bot.api.setWebhook(
    `${process.env.WEBHOOK_URL}/bot${process.env.BOT_TOKEN}`
  );
  console.log('✅ LeadNest Bot activo (webhook)');
});
💬 conversations.js — Flujo de demo
conversations.js Multi-step flow
import { notifySlack } from '../services/notify.js';
import { saveLead } from '../services/leads.js';

export async function demoFlow(conversation, ctx) {
  await ctx.reply('👋 ¡Empecemos! ¿Cómo te llamas?');
  const name = (await conversation.waitFor('message:text'))
    .message.text;

  await ctx.reply(`Encantado, ${name}! ¿En qué empresa trabajas?`);
  const company = (await conversation.waitFor('message:text'))
    .message.text;

  await ctx.reply('📧 ¿Tu email de trabajo?');
  const email = (await conversation.waitFor('message:text'))
    .message.text;

  await ctx.reply('¿Qué plan te interesa?', {
    reply_markup: {
      inline_keyboard: [[
        { text: '🚀 Pro (49€)', callback_data: 'plan_pro' },
        { text: '🏢 Agency (199€)', callback_data: 'plan_agency' },
      ],[
        { text: '🆓 Primero pruebo Free', callback_data: 'plan_free' }
      ]]
    }
  });
  const { data: plan } = (await conversation
    .waitForCallbackQuery(['plan_pro', 'plan_agency', 'plan_free']))
    .callbackQuery;

  const lead = { name, company, email, plan,
    tgId: ctx.from.id, ts: new Date().toISOString() };

  await Promise.all([saveLead(lead), notifySlack(lead)]);

  await ctx.answerCallbackQuery();
  await ctx.editMessageText(
    `✅ *¡Listo, ${name}!*\n\nTu solicitud de demo está registrada. ` +
    `Nuestro equipo se pondrá en contacto en <24h.\n\n` +
    `📬 Confirmación enviada a: ${email}`,
    { parse_mode: 'HTML' }
  );
}
📋 Comandos registrados
Comando Descripción Tipo Handler
/start Bienvenida + menú principal inline público commands.js
/demo Inicia flujo de solicitud de demo (4 pasos) conversación conversations.js
/precios Muestra tabla de planes con botones de acción público commands.js
/faq Árbol de preguntas frecuentes navegable público keyboards/faq.js
/contacto Datos del equipo + enlace directo Calendly público commands.js
/admin Panel admin: ver leads, estadísticas admin only middleware.js
🏗 Arquitectura de producción
Telegram Cloud
Bot API Servers
👤 50.000+ usuarios
🔔 Webhook HTTPS
Updates JSON
200 OK
Railway (Node.js 20)
Express + grammY
💾 Session (Redis)
📊 Leads (Supabase)
📣 Notif. Slack WH
🚀 Opciones de despliegue
Railway
Webhook nativo, auto-deploy desde GitHub, SSL gratuito
✓ Recomendado para producción
Render.com
Free tier disponible, webhook, fácil de configurar
AWS Lambda
Serverless con webhook adapter de grammY, pay-per-use
VPS + systemd
Control total, polling o webhook, restart automático
📱 Preview del bot
🤖
LeadNest Bot
🟢 en línea
/start
09:41
👋 ¡Hola! Soy el bot de LeadNest, tu SaaS de captura de leads.

¿En qué puedo ayudarte hoy?
🎯 Solicitar demo 💰 Ver precios ❓ FAQ 📞 Contacto
09:41
🎯 Solicitar demo
09:42
👋 ¡Empecemos! ¿Cómo te llamas?
09:42
María García
09:42
Encantado, María! ¿En qué empresa trabajas?
09:42
AgenciaMax SL
09:43
¿Qué plan te interesa?
🚀 Pro (49€) 🏢 Agency (199€) 🆓 Free trial
09:43
¡Listo, María!

Tu solicitud de demo está registrada. Nuestro equipo contactará contigo en <24h.

📬 maria@agenciamax.es
09:43
🔀

Flujo de conversación /demo

Usuario envía /demo ctx.conversation.enter('demo')
Preguntar nombre waitFor('message:text')
Preguntar empresa waitFor('message:text')
Preguntar email waitFor('message:text')
Seleccionar plan waitForCallbackQuery(['pro','agency','free'])
Guardar lead + Notificar Slack Promise.all([saveLead, notifySlack])
Confirmación al usuario editMessageText() · fin conversación
LeadNest Bot · Constructor de Bots Telegram · CULTIVA IA grammY v1.x · Node.js 20 · Apache 2.0 · 2026