Bots Conversacional · WhatsApp Business API

Bot WhatsApp NutriBox

Blueprint completo de implementacion con Meta Cloud API · Node.js · Railway

ClienteNutriBox
StackNode.js 20 + Express + Redis
Flujos automatizados4 / 4
DespliegueRailway (HTTPS)
APIMeta Cloud API v21.0
70%
Consultas automatizadas
84
Tickets/dia gestionados por bot
<3s
Tiempo de respuesta medio
-60%
Carga del equipo de soporte
Como fluye cada mensaje
Meta entrega los mensajes al webhook; el procesador consulta la API de NutriBox y responde
WhatsApp Cloud API
Meta Servers
Webhook Receiver
Express / Railway
Message Queue
Redis RPUSH
Bot Processor
Worker Node.js
NutriBox API
api.nutribox.es/v1
State Store
Redis (conversation state)
4 automatizaciones principales
Diseno de cada conversacion con pasos, mensajes y logica de bifurcacion
1
Estado del pedido
1
Usuario escribe "Hola", "Pedido" o pulsa boton menu
2
Bot envia menu interactivo con 4 botones
"Hola! Soy el asistente de NutriBox. ¿En que puedo ayudarte?"
3
Usuario elige "Estado de mi pedido"
4
Bot consulta GET /v1/orders?customer_wa_id={id}
"Tu caja NutriBox #NB-8821 sale manana viernes desde nuestro almacen de Valencia. Llegada estimada: 15-17h"
5
Boton de seguimiento + enlace tracking
2
Pausar suscripcion
1
Usuario elige "Pausar mi suscripcion"
2
Bot pide confirmacion con lista: 1 semana / 2 semanas / 1 mes
"¿Cuanto tiempo quieres pausar tu suscripcion?"
3
Llamada PATCH /v1/subscriptions/{id} con status=paused, resume_date
4
Envio template aprobado subscription_paused
"Tu suscripcion NutriBox ha sido pausada. Cuando quieras reactivarla, escribe REACTIVAR."
5
Cron job para reactivacion automatica en fecha indicada
3
Reportar producto
1
Usuario elige "Reportar un problema"
2
Bot solicita numero de pedido
"¿Cual es el numero de tu ultimo pedido? Lo encuentras en el email de confirmacion (ej. NB-8821)"
3
Bot solicita foto del producto afectado
"Adjunta una foto del producto para que podamos ver el problema"
4
Descarga imagen via graph.facebook.com/v21.0/{media_id} y la sube a S3
5
Crea ticket en CRM + notifica a equipo por Slack
"Incidencia registrada #INC-441. Te contactaremos en menos de 24h con la solucion."
4
Consulta nutricional
1
Usuario elige "Informacion nutricional"
2
Bot obtiene caja actual del cliente: GET /v1/boxes/{box_id}
3
Envia lista interactiva con los platos de la caja
"Esta semana tienes 5 platos en tu caja. ¿Sobre cual quieres informacion?"
4
Devuelve tabla de macros: calorias, proteinas, carbohidratos, grasas
"Pollo al curry con arroz basmati: 480 kcal · Prot. 38g · Carb. 52g · Grasas 12g"
5
Boton para volver al menu o enviar resumen PDF de la semana
Webhook handler principal
Node.js 20 · Express · Redis para estado de conversacion
index.js
messageHandler.js
nutriboxApi.js
.env.example
// NutriBox WhatsApp Bot — index.js
// Meta Cloud API v21.0 + Express + Redis state

const express = require('express');
const { createClient } = require('redis');
const { handleMessage } = require('./messageHandler');

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

const redis = createClient({ url: process.env.REDIS_URL });
redis.connect();

// Webhook verification (GET) — requerido por Meta
app.get('/webhook', (req, res) => {
  const mode      = req.query['hub.mode'];
  const token     = req.query['hub.verify_token'];
  const challenge = req.query['hub.challenge'];

  if (mode === 'subscribe' && token === process.env.WHATSAPP_VERIFY_TOKEN) {
    console.log('Webhook verificado correctamente');
    return res.status(200).send(challenge);
  }
  res.sendStatus(403);
});

// Recepcion de mensajes (POST) — responder 200 INMEDIATAMENTE
app.post('/webhook', async (req, res) => {
  res.sendStatus(200); // Responder antes de procesar (max 5s)

  const entry   = req.body.entry?.[0];
  const change  = entry?.changes?.[0];
  const message = change?.value?.messages?.[0];

  if (!message) return;

  // Deduplicacion: ignorar mensajes ya procesados
  const key = `msg:${message.id}`;
  const seen = await redis.setNX(key, 1);
  if (!seen) return;
  await redis.expire(key, 86400); // TTL 24h

  const phoneId = change.value.metadata.phone_number_id;
  await handleMessage(message, phoneId, redis);
});

app.listen(process.env.PORT || 3000, () =>
  console.log('NutriBox WhatsApp Bot iniciado')
);
📩

Menu principal (botones)

4 reply buttons para redirigir al flujo correcto. Maximo 3 botones por mensaje — se divide en 2 mensajes.

📋

Selector de plato (lista)

Lista interactiva con los 5 platos de la caja semanal. Hasta 10 filas por seccion, descripciones con calorias.

📷

Recepcion de media

Extrae media_id de imagen, descarga via API con Bearer token y sube a S3 como evidencia del ticket.

Mensajes de inicio de conversacion
Solo los templates aprobados pueden iniciar una conversacion — los mensajes libres requieren la ventana de 24h abierta
weekly_delivery_reminder
Aprobada
Categoria: Utility · Idioma: es_ES
Hola Laura, tu caja NutriBox llega el lunes 17 de junio. Preparate para comer bien 🥗
9:00 AM ✓✓
{{1}} nombre
{{2}} fecha_entrega
subscription_paused
Aprobada
Categoria: Utility · Idioma: es_ES
Tu suscripcion NutriBox ha sido pausada hasta el 1 de julio. Cuando quieras reactivarla antes, escribe REACTIVAR.
10:32 AM ✓✓
{{1}} fecha_reactivacion
incident_resolved
Aprobada
Categoria: Utility · Idioma: es_ES
Buenas noticias! Hemos resuelto tu incidencia #INC-441. Te enviamos un credito de 15€ en tu proximo pedido. Disculpa las molestias.
14:15 PM ✓✓
{{1}} ticket_id
{{2}} credito_eur
welcome_new_subscriber
Pendiente
Categoria: Marketing · Idioma: es_ES
Bienvenida a NutriBox, Laura! Tu primera caja llega el 17 de junio. Guardamos tu numero para enviarte actualizaciones por aqui. Responde STOP si prefieres no recibirlas.
11:00 AM ✓
{{1}} nombre
{{2}} fecha_primera_caja
Variables de entorno
Railway · Settings → Variables
# Meta WhatsApp WHATSAPP_TOKEN=EAAxxxxxxxxxxxxxxx WHATSAPP_PHONE_ID=123456789012345 WHATSAPP_BUSINESS_ID=987654321098765 WHATSAPP_VERIFY_TOKEN=nutribox_wb_secret_2026 # NutriBox interna NUTRIBOX_API_URL=https://api.nutribox.es/v1 NUTRIBOX_JWT_SECRET=jwt_service_token_here # Infraestructura REDIS_URL=redis://red-xxxxx.railway.app:6379 S3_BUCKET=nutribox-wa-incidents SLACK_WEBHOOK=https://hooks.slack.com/T.../B.../xxx PORT=3000
Pricing Meta (ES)
Ventana de 24h: 1 cobro independientemente del numero de mensajes
Tipo Precio/conv. Primer 1.000/mes
Service (usuario inicia)
Soporte, consultas
Gratis
hasta 1.000/mes
0 €
Service (exceso)
>1.000/mes
0,0083 € ~25 €/1.000
Utility (reminders)
Confirmaciones, avisos
0,0110 € ~11 €/1.000
Marketing
Campanas salientes
0,0650 € ~65 €/1.000
Authentication
OTP, 2FA
0,0540 € ~54 €/1.000
Antes de ir a produccion
Todos los puntos necesarios para un despliegue seguro y escalable
HTTPS obligatorio — Railway provisiona SSL automaticamente en railway.app
Deduplicacion con Redis — clave msg:{id} con TTL 24h para ignorar reenvios
200 inmediato — el webhook responde antes de procesar para evitar timeouts de 5s de Meta
Estado en Redis, no en memoria — permite escalar a N workers sin perder contexto de conversacion
Escalada a humano — flujo de fallback con keyword "hablar con agente" notifica al equipo por Slack
!
Numero de produccion verificado — requiere documento oficial de empresa ante Meta (1-3 dias habiles)
!
Limite inicial 250 conv/24h — solicitar incremento a 1K tras 30 dias con calidad de mensajes >70%
Token de sistema permanente — System User token sin caducidad en Meta Business Manager, no el token de 24h
Suscripcion a message_status — trackear sent/delivered/read/failed para metricas de entregabilidad
!
Template welcome_new_subscriber — pendiente de aprobacion Meta (marketing, puede tardar hasta 48h)

80 msg/seg

Limite de la Cloud API. Para NutriBox (3.200 usuarios) mas que suficiente incluso en horario pico.

📋

250 conv/24h

Limite inicial de cuenta nueva. Sube automaticamente a 1K tras periodo de calidad positivo.

📈

1K → 100K

Escalado en fases segun quality rating de Meta. NutriBox puede llegar a ilimitado en 3-4 meses.

🛠

Cron reminders

El lunes a las 9:00 AM se disparan 3.200 templates weekly_delivery_reminder en batches de 50.