Saltar al contenido
Chatbots de WhatsApp desde cero
Temario

Ejercicio: Recibir mensajes reales

  • ⏱ 50 minutos
  • 📶 Nivel: intermedio

Objetivo

Conectar tu webhook con Meta, ver llegar un mensaje real de tu celular y practicar la lógica del webhook con tres funciones de JavaScript puro: responder la verificación, resumir un evento y descartar duplicados.

Cómo se trabaja

La parte A es práctica real: túnel o despliegue, registro del webhook en Meta y una prueba desde tu celular. La parte B son tres funciones que se comprueban en esta página. Son versiones simplificadas de lo que ya hace src/worker.js y src/whatsapp.js (sin firma ni red), para que entiendas la lógica. No pegues tokens reales aquí ni en capturas.

💡 Reto extra

Añade a resumirEvento el nombre del contacto (value.contacts[].profile.name) cuando exista, con el formato mensaje de Cliente Ejemplo (51999000111): .... Compara tu versión con parsearMensaje de src/whatsapp.js.

▶ Prueba tu código aquí (opcional)
Consola

Pasos

Marca cada paso a medida que lo completes. Tu avance se guarda en este navegador.

💡 Pista 1: Verificación

Compara con === los tres datos y exige que verifyToken sea un texto no vacío. Recuerda que el reto se devuelve tal cual, sin modificarlo.

💡 Pista 2: Resumen del evento

Usa payload.entry ?? [], luego entrada.changes ?? [], y para cada value recorre value.messages ?? [] y value.statuses ?? []. Un arreglo vacío es un buen valor por defecto para todo lo que falte.

💡 Pista 3: Duplicados

Set tiene has y add. Primero pregunta si existe; si no, agrégalo antes de devolver false.

🔎 Comprueba tu trabajo

Pega tu código y pulsa Comprobar. La revisión ocurre en tu navegador; nada se envía a ningún sitio. Cada punto en rojo incluye una pista. Pega solo el JavaScript, sin las etiquetas <script>.

    ✅ Ver una solución posible

    Intenta resolverlo antes de mirar. Tu versión puede ser distinta y también correcta.

    funciones.js
    function responderVerificacion(query, verifyToken) {
      const modo = query["hub.mode"];
      const token = query["hub.verify_token"];
      const reto = query["hub.challenge"];
      if (modo === "subscribe" && verifyToken && token === verifyToken && reto) {
        return { status: 200, body: reto };
      }
      return { status: 403, body: "Prohibido" };
    }
    
    function resumirEvento(payload) {
      const lineas = [];
      if (!payload || payload.object !== "whatsapp_business_account" || !Array.isArray(payload.entry)) return lineas;
      for (const entrada of payload.entry) {
        for (const cambio of entrada?.changes ?? []) {
          const valor = cambio?.value ?? {};
          for (const msg of valor.messages ?? []) {
            if (msg.type === "text") lineas.push(`mensaje de ${msg.from}: ${msg.text?.body ?? ""}`);
            else lineas.push(`mensaje de ${msg.from}: no soportado (${msg.type})`);
          }
          for (const st of valor.statuses ?? []) {
            lineas.push(`estado ${st.status} de ${st.id}`);
          }
        }
      }
      return lineas;
    }
    
    function esDuplicado(vistos, id) {
      if (vistos.has(id)) return true;
      vistos.add(id);
      return false;
    }