Israel Castro
Alejandro Yectivani Jimenez Rojas
Me ayudó perfectamente, muchísimas gracias por el aporte.
Oscar Barajas Tavares
Team PlatziGracias por esto.
Conectar un bot de WhatsApp con tu propio servidor empieza por un paso clave: configurar el webhook de WhatsApp API usando Express, dotenv y port forwarding. Aquí verás cómo armar ese flujo desde el código de ejemplo de Meta hasta recibir el primer mensaje replicado en tu chat, ideal si estás construyendo un bot conversacional como MedPet.
Qué hace el código base de Meta para el webhook
Meta entrega un proyecto de ejemplo en su documentación que sirve como punto de partida para levantar el servidor. Ese código trae todo lo necesario para validar la conexión y enviar un mensaje de eco.
El ejemplo usa tres piezas que conviene reconocer desde el inicio:
La lógica del eco es simple: cada mensaje que llega al bot se replica con el mismo texto. Eso te permite confirmar que la comunicación entre tu servidor y la API funciona antes de meter lógica más compleja [1:30].
¿Qué es un webhook en WhatsApp API? Es un endpoint público en tu servidor que Meta usa para enviarte los mensajes entrantes. Tú lo verificas con un token secreto y, una vez validado, recibes cada evento del bot en tiempo real.
Cómo conectar el webhook con variables de entorno
Después de copiar el código de ejemplo en un archivo server.js, el siguiente paso es sacar los valores sensibles del código y moverlos a un archivo .env. Esto evita exponer tokens en el repositorio y deja la configuración lista para escalar.
Qué variables de entorno necesita el proyecto
El archivo .env debe contener cinco variables que el servidor leerá con process.env:
WEBHOOK_VERIFY_TOKEN: una palabra secreta que tú defines, por ejemplo platzi.API_TOKEN: el access token que genera Meta en el panel de desarrolladores.BUSINESS_PHONE: el identificador del número de teléfono de tu app.API_VERSION: la versión de la API, por ejemplo v20.0.PORT: el puerto local, típicamente 3000.Agrega .env al .gitignore para no subirlo al repositorio. En su lugar, crea un .env.example con los nombres de las variables vacías para que cualquier persona del equipo sepa qué configurar [5:40].
Cómo ajustar el código de ejemplo
El ejemplo de Meta llega con la versión 18 hardcodeada y nombres como businessPhoneNumberId. Conviene reemplazar esos valores por las variables del .env para tener control desde un solo lugar. Lo mismo aplica al header Authorization, que debe leer API_TOKEN, y a la URL de Axios, que toma API_VERSION y BUSINESS_PHONE dinámicamente [7:20].
Cómo levantar el servidor con nodemon y exponerlo a internet
Para que el servidor reinicie en cada cambio durante desarrollo, nodemon es la herramienta indicada. Necesita un archivo nodemon.json con su configuración:
watch: apunta a src para escuchar cambios.ext: define las extensiones json y js.ignore: excluye node_modules y carpetas como public.exec: ejecuta node src/server.js.Al correr npm start por primera vez es común ver un error porque el código usa imports modernos de JavaScript. La solución es agregar "type": "module" en el package.json y volver a ejecutar el comando [11:50].
Por qué usar port forwarding de Visual Studio Code
Un servidor en localhost:3000 no es accesible desde fuera de tu máquina, y la API de Meta necesita una URL pública para enviarte los eventos. Aquí entra el port forwarding de Visual Studio Code, que toma tu puerto local y lo expone con una URL pública vía GitHub.
El flujo es directo: en la pestaña de puertos seleccionas Forward a Port, eliges el 3000, te autenticas con GitHub y cambias la visibilidad a pública. VS Code te entrega una URL que ya puedes pegar en el panel de Meta.
¿Por qué el webhook devuelve 403 al abrirlo en el navegador? Porque el endpoint
/webhookexige un token de verificación en la URL. Si entras sin token, la respuesta correcta es Forbidden: significa que la validación está activa y funcionando.
Recuerda que esta URL solo sirve en modo desarrollo. No es una solución para producción [14:30].
Cómo verificar el webhook en el panel de Meta
Con la URL pública lista, vas al panel de Meta en la sección de webhooks. Ahí pegas la URL completa terminada en /webhook y agregas el mismo verify token que pusiste en tu .env, en este caso platzi.
Al dar Verify and Save, Meta hace una petición GET a tu servidor y compara el token. Si coincide, la conexión queda establecida y aparece la pantalla para suscribirte a eventos.
Los tres eventos clave que debes activar son:
Qué hacer cuando el access token expira
Al enviar el primer Hola desde WhatsApp, es muy probable que aparezca un error 401 con el mensaje Session has expired. Eso pasa porque el token temporal del panel de pruebas tiene una vida corta.
La solución es regenerar el token desde API Setup, copiarlo de nuevo al .env, reiniciar el servidor con npm start y volver a enviar el mensaje. El bot debería responder con el mismo texto que enviaste, confirmando que el eco funciona [17:50].
¿Qué hago si el token de WhatsApp expira constantemente? Usa el token temporal solo para pruebas iniciales. Para un proyecto estable necesitas generar un token permanente desde la configuración de Meta Business, vinculado a un usuario de sistema.
Ahora que el flujo de eco está activo, el siguiente reto es modificar la lógica para que el mensaje no se replique como reply. ¿Cómo lo resolverías tú? Déjalo en los comentarios.
Israel Castro
Alejandro Yectivani Jimenez Rojas
Me ayudó perfectamente, muchísimas gracias por el aporte.
Oscar Barajas Tavares
Team PlatziGracias por esto.
vengo del 2025 y si no estoy mal la documentacion ha cambiado por lo tanto la url para lo de express es la siguiente
y el archivo viene asi
// Import Express.js
const express = require('express');
// Create an Express app
const app = express();
// Middleware to parse JSON bodies
app.use(express.json());
// Set port and verify_token
const port = process.env.PORT || 3000;
const verifyToken = process.env.VERIFY_TOKEN;
// Route for GET requests
app.get('/', (req, res) => {
const { 'hub.mode': mode, 'hub.challenge': challenge, 'hub.verify_token': token } = req.query;
if (mode === 'subscribe' && token === verifyToken) {
console.log('WEBHOOK VERIFIED');
res.status(200).send(challenge);
} else {
res.status(403).end();
}
});
// Route for POST requests
app.post('/', (req, res) => {
const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
console.log(`\n\nWebhook received ${timestamp}\n`);
console.log(JSON.stringify(req.body, null, 2));
res.status(200).end();
});
// Start the server
app.listen(port, () => {
console.log(`\nListening on port ${port}\n`);
});
Carolina Avila Coral
Ese modelo de código de glitch ¿es solo para node.js? ¿Está disponible para python?
Neicer Vásquez
David Correal Melo
Tuve un montón de errores, pero con ayuda de chatgpt saque la clase adelante, eso sí, me costó 2 horas.
Ricardo Dario Ferrer
Ante el Problema que a varios les a sucedido: data: {
error: {
message: '(#131030) Recipient phone number not in allowed list',
type: 'OAuthException',
code: 131030,
error_data: {
messaging_product: 'whatsapp',
details: 'El número de teléfono del destinatario no está en la lista de autorizados: Agrega el número de teléfono del destinatario a la lista de destinatarios y vuelve a intentarlo.'
},
fbtrace_id: 'AgKH_NCHXeT-gIiIBURTdjn'
}
}
},
status: 400
Lo que leí en la documentación es que en desarrollo mas allá que el numero haya sido registrado en la API debe estar autorizado y registrado como tester, esto lo pueden modificar en Roles de la App. Sin embargo simplemente probe modificando el To:message.from (esto indica; por lo que entiendo que responda a todos los números registrados que en producción serian todos) por el numero que registre entonces quedo To:"12356465784", y ya eso fue todo para que funcione.
Espero les sirva saludos.-
Matias Ezequiel Rivero
Excelente, gracias, con las soluciones anteriores no logre hacer que me tomara el número, de esta forma funcionó, verifiquen el token que también vence la sesión.
Milton Seitzinger
Muchas gracias, me funciono con esto.
Pablo Aquino
Jose Alberto Gomez Macias
POR SI LES SALE ERROR 400, AQUI ESTA LA SOLUCION
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */
import express from "express";import axios from "axios";import 'dotenv/config';
const app = express();app.use(express.json());
const { WEBHOOK_VERIFY_TOKEN, API_TOKEN, BUSINESS_PHONE, API_VERSION, PORT } = process.env;
app.post("/webhook", async (req, res) => { // Log incoming messages console.log("Incoming webhook message:", JSON.stringify(req.body, null, 2));
// Check if the webhook request contains a message const message = req.body.entry?.[0]?.changes[0]?.value?.messages?.[0];
// Check if the incoming message contains text if (message?.type === "text") { // Adjust the phone number to remove the "1" extra for Mexican numbers let toNumber = message.from;
// Detect and remove the "1" extra if it appears after the Mexico country code (52) if (toNumber.startsWith("521") && toNumber.length === 13) { toNumber = toNumber.replace(/^521/, "52"); // Replace "521" with "52" }
try { // Send the reply message await axios({ method: "POST", url: https://graph.facebook.com/${API\_VERSION}/${BUSINESS\_PHONE}/messages, headers: { Authorization: Bearer ${API\_TOKEN}, }, data: { messaging_product: "whatsapp", to: toNumber, // Use the adjusted number text: { body: "Echo: " + message.text.body }, context: { message_id: message.id, // Show the message as a reply to the original user message }, }, });
// Mark incoming message as read await axios({ method: "POST", url: https://graph.facebook.com/${API\_VERSION}/${BUSINESS\_PHONE}/messages, headers: { Authorization: Bearer ${API\_TOKEN}, }, data: { messaging_product: "whatsapp", status: "read", message_id: message.id, }, }); } catch (error) { console.error("Error sending or marking message:", error.response?.data || error.message); } }
res.sendStatus(200);});
// Accepts GET requests at the /webhook endpoint. You need this URL to set up the webhook initially.app.get("/webhook", (req, res) => { const mode = req.query["hub.mode"]; const token = req.query["hub.verify_token"]; const challenge = req.query["hub.challenge"];
// Check if the mode and token sent are correct if (mode === "subscribe" && token === WEBHOOK_VERIFY_TOKEN) { // Respond with 200 OK and challenge token from the request res.status(200).send(challenge); console.log("Webhook verified successfully!"); } else { // Respond with '403 Forbidden' if verify tokens do not match res.sendStatus(403); }});
app.get("/", (req, res) => { res.send(\<pre>Nothing to see here.Checkout README.md to start.\</pre>);});
app.listen(PORT, () => { console.log(Server is listening on port: ${PORT});});
Norberto Daniel Rojas
Crack, Idolo, Barrilete Cosmico
Magdalena Fernandez
Alguien sabe por que sale este error, es al momento de mandar el mensaje para que me responda el "echo": "AxiosError: Request failed with status code 400"
Juan Manuel Moreno
Esta es la nueva documentación oficial para el tutorial de test webhook. Sigan los pasos del siguiente enlace, el video del curso está desactualizado.
Otto Luis Amaya Campo
Aquí me quedé estancado, no entiendo muy bien qué hace o cómo seguir.
Otto Luis Amaya Campo
Logré correr la prueba
Juan David Cordoba Mosquera
estoy trabajando en una maquina virtual ubuntu, no me genera en consola una direccion, solo me muestra el localhost:3000. ¿alguien tiene el mismo error?
Mauricio Combariza
Yo tube el mismo problema, hay que poner un servidor publico aparte, se puede hacer con ngrok. ve hasta la pagina crea una cuenta
Sheyzi mg
error al verificar el webhook "No se ha podido validar la URL de devolución de llamada ni el identificador de verificación. Comprueba la información proporcionada o vuelve a intentarlo más tarde."
Carlos Ríos
Hola, ¿pudiste resolver el error al validar la url o el token?
Iveth Perez
Tengo el mismo problema :/
Gabriel Lagos
Matias Ezequiel Rivero
Hola, a la fecha 24-1-2026 ya va por la versión 24 en META y en webhook ha cambiado y ya no tiene integrado solicitudes HTTP con axios para replicar el mensaje. Solo permite validar la conexión con los servidores de META.
// Import Express.js
const express = require('express');
// Create an Express app
const app = express();
// Middleware to parse JSON bodies
app.use(express.json());
// Set port and verify_token
const port = process.env.PORT || 3000;
const verifyToken = process.env.VERIFY_TOKEN;
// Route for GET requests
app.get('/', (req, res) => {
const { 'hub.mode': mode, 'hub.challenge': challenge, 'hub.verify_token': token } = req.query;
if (mode === 'subscribe' && token === verifyToken) {
console.log('WEBHOOK VERIFIED');
res.status(200).send(challenge);
} else {
res.status(403).end();
}
});
// Route for POST requests
app.post('/', (req, res) => {
const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
console.log(`\n\nWebhook received ${timestamp}\n`);
console.log(JSON.stringify(req.body, null, 2));
res.status(200).end();
});
// Start the server
app.listen(port, () => {
console.log(`\nListening on port ${port}\n`);
});
Link:
Luego de conectar el webhook con META recuerden habilitar las opciones que quieren que disparen el webhook.
Juan Camilo Perdomo Duarte
Gracias por el aporte. Sábes si esto cambia por completo el resto de la configuración y si sea mejor hacerlo en Python desde cero?
Matias Ezequiel Rivero
Carlos Sebastian Gracia Yañez
Daniela Akerman
Gracias!
Miguel Enrique Sánchez
AxiosError: Request failed with status code 401
Gracias error resuelto.
Ricardo Dario Ferrer
Respecto al archivo nodemon.js tambien pueden simplemete guardarlo como nodemon.json y listo.
Jorge Armando Muñoz Ordoñez
Alguien tuvo este error al momento de configurar el webhook?
MARISOL ROSALDO JIMÉNEZ
Deisy Páez
No he logrado solucionar este error
Miguel Urcia Guevara
José Ángel Martinez Frias
Lo resolví de la siguiente manera:
El error se generó porque en el archivo . env no tenía puesta la variable de port y ni el puerto, ya que se lo puse funciono correctamente.
Ojalá y les sirva.
Cristian Acalo
Gustavo Troncoso
No me está funcionando el paso de exponer el puerto de desarrollo con el Port Forwarding de Visual Studio Code, no me muestra el aviso de la extensión que muestra el profesor ni tampoco me pide ingresar con mis credenciales a Github, no sé qué me falta instalar o configurar en mi VSCode.
Mauricio Gomez Rivera
Hola, me pasaba lo mismo, y me di cuenta de que era porque estaba utilizando WSL en Windows.
Aparentemente, se tiene problemas de reenvíos trabajando desde WSL, válida que no estés trabajando con esto. :)
Gustavo Troncoso
Gracias Mauricio Gomez Rivera efectivamente al cerrar la conexión con WSL y probar hacer el port forwarding en modo local si funciona.
💡 Solución al mensaje de error Número de teléfono del destinatario no incluido en la lista de autorizados…
Limpiamos el número (ya que facebook le agrega un "1" entre la clave del país y el número, pasando de 525512345678 -> 5215512345678) con una función:
const cleanPhoneNumber = (number) => {   return number.startsWith('521') ? number.replace("521", "52") : number;   }
Esta función se la pasamos al objeto data y de esta manera el número se enviará en el formato correcto.
data: {   messaging\_product: "whatsapp",   to: cleanPhoneNumber(message.from),   …
De esta manera funciona correctamente.
Según chatgpt este sería el código. No lo he implementado ya que no he usado antes flask.
import os from flask import Flask, request, jsonify import requests app = Flask(__name__) # Variables de entorno WEBHOOK_VERIFY_TOKEN = os.getenv("WEBHOOK_VERIFY_TOKEN") API_TOKEN = os.getenv("API_TOKEN") PORT = int(os.getenv("PORT", 5000)) BUSINESS_PHONE = os.getenv("BUSINESS_PHONE") API_VERSION = os.getenv("API_VERSION") @app.route("/webhook", methods=["POST"]) def webhook(): # Log de los mensajes entrantes incoming_data = request.json print("Incoming webhook message:", incoming_data) # Extraer mensaje de texto message = ( incoming_data.get("entry", [{}])[0] .get("changes", [{}])[0] .get("value", {}) .get("messages", [{}])[0] ) if message.get("type") == "text": user_id = message.get("from") message_id = message.get("id") message_text = message.get("text", {}).get("body") # Responder al mensaje response = requests.post( f"https://graph.facebook.com/{API_VERSION}/{BUSINESS_PHONE}/messages", headers={ "Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json", }, json={ "messaging_product": "whatsapp", "to": user_id, "text": {"body": "Bienvenido a Mundo Emperatriz"}, "context": {"message_id": message_id}, }, ) print("Message sent:", response.json()) # Marcar el mensaje como leído requests.post( f"https://graph.facebook.com/{API_VERSION}/{BUSINESS_PHONE}/messages", headers={ "Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json", }, json={ "messaging_product": "whatsapp", "status": "read", "message_id": message_id, }, ) return jsonify({"status": "success"}), 200 @app.route("/webhook", methods=["GET"]) def verify_webhook(): mode = request.args.get("hub.mode") token = request.args.get("hub.verify_token") challenge = request.args.get("hub.challenge") if mode == "subscribe" and token == WEBHOOK_VERIFY_TOKEN: print("Webhook verified successfully!") return challenge, 200 else: return "Forbidden", 403 @app.route("/", methods=["GET"]) def home(): return "<pre>Nothing to see here.\nCheckout README.md to start.</pre>", 200 if __name__ == "__main__": app.run(host="0.0.0.0", port=PORT)
Actualmente feb-2026 la configuración ha cambiado, ya no es necesario poner /webhook, y el código de ejemplo no incluye el envío de mensajes
Para que puedas enviar mensajes debes modificar el código de ejemplo, agrega una función para envío de mensajes
function to send a message using the WhatsApp Business API async function sendMessage(phoneNumber, message) { const url = `https://graph.facebook.com/${apiVersion}/${businessPhone}/messages`; const data = { messaging_product: 'whatsapp', to: phoneNumber, text: { body: message }, }; try { const response = await axios.post(url, data, { headers: { 'Authorization': `Bearer ${process.env.API_TOKEN}`, 'Content-Type': 'application/json', }, }); console.log('Message sent:', response.data); } catch (error) { console.error('Error sending message:', error.response?.data || error.message); } }
Modifica ligeramente la sección de post request
// Route for POST requests app.post('/', (req, res) => { const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19); console.log(`\n\nWebhook received ${timestamp}\n`); console.log(JSON.stringify(req.body, null, 2)); // check if the webhook request contains a message const message = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; //check if the incoming message is a text message if (message && message.type === 'text') { const phoneNumber = message.from; const text = message.text.body; console.log(`Received message from ${phoneNumber}: ${text}`); // send a response message back to the user const responseMessage = `You said: ${text}`; sendMessage(phoneNumber, responseMessage); } res.status(200).end(); });
Con eso tendrás un ejemplo similar al que se muestra en clase.
Con estos codigos me funciono tal como lo proponen en el curso:
server.js:
import express from "express"; import axios from "axios"; import dotenv from "dotenv"; dotenv.config(); const app = express(); app.use(express.json()); const { WEBHOOK_VERIFY_TOKEN, API_TOKEN, BUSINESS_PHONE, API_VERSION, PORT } = process.env; console.log("TOKEN cargado:", API_TOKEN ? "SI" : "NO"); /* |-------------------------------------------------------------------------- | RECIBE MENSAJES DE WHATSAPP |-------------------------------------------------------------------------- */ app.post("/webhook", async (req, res) => { console.log( "Incoming webhook message:", JSON.stringify(req.body, null, 2) ); const message = req.body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]; if (message?.type === "text") { try { await axios({ method: "POST", url: `https://graph.facebook.com/${API_VERSION}/${BUSINESS_PHONE}/messages`, headers: { Authorization: `Bearer ${API_TOKEN}`, "Content-Type": "application/json" }, data: { messaging_product: "whatsapp", to: message.from, text: { body: "Echo: " + message.text.body } } }); console.log("Mensaje enviado correctamente"); } catch (error) { console.log("ERROR META:"); if (error.response) { console.log(error.response.data); } else { console.log(error.message); } } } res.sendStatus(200); }); /* |-------------------------------------------------------------------------- | VERIFICACION DEL WEBHOOK |-------------------------------------------------------------------------- */ 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 === WEBHOOK_VERIFY_TOKEN) { console.log("Webhook verificado correctamente"); res.status(200).send(challenge); } else { res.sendStatus(403); } }); /* |-------------------------------------------------------------------------- | PAGINA PRINCIPAL |-------------------------------------------------------------------------- */ app.get("/", (req, res) => { res.send("WhatsApp Bot funcionando"); }); /* |-------------------------------------------------------------------------- | INICIAR SERVIDOR |-------------------------------------------------------------------------- */ app.listen(PORT, () => { console.log("Servidor corriendo en puerto:", PORT); });
y package.json:
{ "name": "whatsapp-chatbot", "version": "1.0.0", "type": "module", "main": "server.js", "scripts": { "start": "node server.js" }, "dependencies": { "axios": "^1.13.6", "dotenv": "^16.6.1", "express": "^4.22.1" } }
espero que sea útil para los que están en esta parte, al inicio a mi no me funcionaba la configuración, recibía los mensajes iniciales pero cuando yo enviaba un mensaje no recibía el echo(el mismo mensaje copiado) .
Cambia sobre todo la parte de replicar el mensaje que muestra la clase. Luego de conectar tu servidor con los de META, al enviarle un mensaje al bot en consola vas a ver un objeto completo con toda la info que te manda el servidor de META, con el cual luego de separar la lógica MVC (modelo vista controlador) puedes empezar a partir del OBJ recibido de META a tomar distintas acciones de respuesta y manipulación.
Sugiero apoyarte en la documentación actualizada de META y en los comentarios recientes del curso. En py he visto algunos compañeros que lo han realizado. Por mi lado estoy con JS y nodeJS. Saludos.
Para los que les de el error 400 o 401 de axios, aqui les dejo el codigo de server.js para ver que error hay en la petición del webhook:
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import express from "express"; import axios from "axios"; import 'dotenv/config'; const app = express(); app.use(express.json()); const { WEBHOOK_VERIFY_TOKEN, API_TOKEN, BUSINESS_PHONE, API_VERSION, PORT } = process.env; app.post("/webhook", async (req, res) => { // log incoming messages console.log("Incoming webhook message:", JSON.stringify(req.body, null, 2)); // check if the webhook request contains a message // details on WhatsApp text message payload: https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/payload-examples#text-messages const message = req.body.entry?.[0]?.changes[0]?.value?.messages?.[0]; // check if the incoming message contains text if (message?.type === "text") { try { // send a reply message as per the docs here https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages await axios({ method: "POST", url: `https://graph.facebook.com/${API_VERSION}/${BUSINESS_PHONE}/messages`, headers: { Authorization: `Bearer ${API_TOKEN}`, }, data: { messaging_product: "whatsapp", to: message.from, text: { body: "Echo: " + message.text.body }, context: { message_id: message.id, // shows the message as a reply to the original user message }, }, }); // mark incoming message as read await axios({ method: "POST", url: `https://graph.facebook.com/${API_VERSION}/${BUSINESS_PHONE}/messages`, headers: { Authorization: `Bearer ${API_TOKEN}`, }, data: { messaging_product: "whatsapp", status: "read", message_id: message.id, }, }); } catch (e) { // Aquí verás el status y el sub-código de WhatsApp (clave para depurar) console.error("WA-ERROR:", e.response?.status, e.response?.data); } } res.sendStatus(200); }); // accepts GET requests at the /webhook endpoint. You need this URL to setup webhook initially. // info on verification request payload: https://developers.facebook.com/docs/graph-api/webhooks/getting-started#verification-requests app.get("/webhook", (req, res) => { const mode = req.query["hub.mode"]; const token = req.query["hub.verify_token"]; const challenge = req.query["hub.challenge"]; // check the mode and token sent are correct if (mode === "subscribe" && token === WEBHOOK_VERIFY_TOKEN) { // respond with 200 OK and challenge token from the request res.status(200).send(challenge); console.log("Webhook verified successfully!"); } else { // respond with '403 Forbidden' if verify tokens do not match res.sendStatus(403); } }); app.get("/", (req, res) => { res.send(`<pre>Nothing to see here. Checkout README.md to start.</pre>`); }); app.listen(PORT, () => { console.log(`Server is listening on port: ${PORT}`); });
✨🦄 Realicé la interacción entre diferentes elementos de wpp:
Con este código, solo cambia la data que se envía en la respuesta:
app.post("/webhook", async (req, res) => { // log incoming messages console.log("Incoming webhook message:", JSON.stringify(req.body, null, 2)); // check if the webhook request contains a message const message = req.body.entry?.[0]?.changes[0]?.value?.messages?.[0]; let data = {}; if (message) { if (message.type === "interactive") { data = { messaging_product: "whatsapp", to: message.from, text: { body: "Has interactuado con un botón! :D" }, context: { message_id: message.id, // shows the message as a reply to the original user message }, } } else if (message.text.body === "button") { data = { messaging_product: "whatsapp", to: message.from, type: "interactive", interactive: { type: "button", body: { text: "Here is a button example", }, action: { buttons: [ { type: "reply", reply: { id: "button1", title: "Button 1", }, }, { type: "reply", reply: { id: "button2", title: "Button 2", }, }, ], }, }, } } else if (message.text.body === "image") { data = { messaging_product: "whatsapp", to: message.from, type: "image", image: { link: "https://img.freepik.com/fotos-premium/imagen-fondo_910766-187.jpg", }, } } else { data = { messaging_product: "whatsapp", to: message.from, text: { body: "Echo: " + message.text.body }, context: { message_id: message.id, // shows the message as a reply to the original user message }, } } await axios({ method: "POST", url: `https://graph.facebook.com/${API_VERSION}/${BUSINESS_PHONE}/messages`, headers: { Authorization: `Bearer ${API_TOKEN}`, }, data: data, }); // mark incoming message as read await axios({ method: "POST", url: `https://graph.facebook.com/${API_VERSION}/${BUSINESS_PHONE}/messages`, headers: { Authorization: `Bearer ${API_TOKEN}`, }, data: { messaging_product: "whatsapp", status: "read", message_id: message.id, }, }); } res.sendStatus(200); });