Configuración inicial

1

Desarrolla tu Chatbot con la API de Whatsapp

2

¿Cómo funciona la API de WhatsApp?

3

¿Cómo crear una cuenta de desarrollador en Meta?

4

¿Cómo configurar una aplicación en Developers Facebook?

5

Creación y configuración de una aplicación en Whatsapp

Integración con la API de WhatsApp

6

¿Cómo configurar la API de WhatsApp para recibir y enviar mensajes?

7

¿Cómo configurar la API de WhatsaApp con Postman?

8

¿Cómo crear un servidor de Express?

Implementación de Servidor Express

9

¿Cómo implementar Webhooks en Express?

10

¿Cómo optimizar la arquitectura de un bot usando servicios y controladores?

Comunicación con la API de WhatsApp

11

¿Cómo enviar un mensaje de bienvenida con la API de WhatsApp?

12

¿Cómo configurar una respuesta personalizada desde la API de WhatsApp?

Flujos de Interacción con la API de WhatsApp

13

¿Cómo desarrollar un flujo inicial para guiar a los usuarios con WhatsApp API?

14

¿Cómo configurar un menú de opciones desde la API de WhatsApp?

Multimedia con WhatsApp API

15

¿Cómo integrar mensajes multimedia en el flujo de tu chatbot?

16

¿Cómo Integrar el Send-Media-Message al flujo de tu Chatbot?

17

¿Cómo crear el flujo para agendar una cita desde la API de WhatsApp?

18

¿Cómo crear una lógica que permita almacenar el flujo de tu Chatbot?

Avances y Personalización

19

¿Cómo conectar tu chatbot con Google Sheets para la gestión de datos?

20

¿Cómo configurar la API de Google Sheets para almacenar la información de tu usuario?

21

¿Cómo conectar la API de WhatsApp con ChatGPT?

22

¿Cómo integrar ChatGPT al flujo de la API de WhatsApp?

23

¿Cómo enviar contactos desde tu chatbot para soporte al usuario?

24

¿Cómo configurar la API de WhatsApp para enviar ubicaciones a tu usuario?

25

¿Cómo crear flujos escalables en la API de WhatsApp usando buenas prácticas de programación?

26

¿Cómo desplegar la API de WhatsApp en un ambiente de producción?

27

¿Cómo publicar tu Chatbot para interacciones reales?

28

Ahora tienes tu Chatbot que potencia las interacciones con tu usuario

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

¿Cómo implementar Webhooks en Express?

9/28
Recursos

Para implementar una integración básica entre WhatsApp API y una aplicación de Node.js, sigue una serie de pasos que van desde configurar el servidor hasta establecer una conexión con la API de Meta para WhatsApp y realizar pruebas locales y públicas. Este proceso permite realizar un eco de los mensajes recibidos y replicarlos en el chat de WhatsApp, utilizando herramientas como Axios, Express y variables de entorno.

¿Cómo configurar el servidor de Node.js para WhatsApp API?

  1. Preparar el entorno del servidor:

    • Dirígete a la documentación de WhatsApp API de Meta para consultar el código de ejemplo que puedes usar como base.
    • Usa Express para construir el servidor y Axios para interactuar con la API de WhatsApp.
    • Configura el archivo server.js y asegúrate de tener dotenv para manejar las variables de entorno necesarias.
  2. Establecer las variables de entorno:

    • Crea un archivo .env que incluya:

      • WEBHOOK_VERIFY_TOKEN: un token secreto compartido con Meta para validar el webhook.
      • API_TOKEN: el token de acceso a la API.
      • PORT: el puerto en el cual se ejecutará el servidor.
      • BUSINESS_PHONE: el ID del teléfono de negocios registrado en Meta.
      • API_VERSION: la versión de la API en uso.
    • Excluye el archivo .env del control de versiones con .gitignore y proporciona un .env-example con las claves esperadas para futuros desarrolladores.

¿Cómo implementar el código de conexión y manejo de solicitudes?

  1. Configurar el webhook:

    • Usa el webhook proporcionado por Meta para recibir y validar los mensajes entrantes.
    • Define la lógica para replicar los mensajes recibidos: cuando el bot reciba un mensaje, este debe responder con el mismo texto, emulando un “eco”.
  2. Realizar cambios en las peticiones de Axios:

    • Personaliza el código de ejemplo para que la versión de la API y el ID de teléfono provengan de las variables de entorno, facilitando el mantenimiento.
    • Ajusta la autenticación de Axios para que utilice API_TOKEN.
  3. Configurar NodeMon para un desarrollo continuo:

    • Crea un archivo nodemon.json para monitorear los cambios en el código en las carpetas y extensiones clave del proyecto.
    • Especifica los directorios y archivos que no deben observarse, como node_modules.

¿Cómo realizar pruebas locales y públicas?

  1. Prueba local en Visual Studio Code:

    • Corre el servidor en el puerto 3000 y verifica la respuesta en localhost:3000.
    • Para probar la conexión con Meta, expón el puerto de desarrollo con el Port Forwarding de Visual Studio Code, lo cual crea una URL pública accesible temporalmente.
  2. Configurar el webhook en Meta:

    • En el panel de desarrolladores de Meta, usa la URL pública y agrega WEBHOOK_VERIFY_TOKEN para validar la conexión.
    • Activa los permisos de “mensajes”, “templates” y “templates de quality update” para que el bot pueda enviar y recibir mensajes.

¿Cómo probar y depurar la integración?

  1. Envía un mensaje de prueba:

    • Envía un mensaje al bot en WhatsApp. Si todo está configurado correctamente, el bot debe replicar el mensaje.
    • Si ocurre un error, verifica la consola de Node.js; errores comunes incluyen un 401 Unauthorized cuando el API_TOKEN expira.
  2. Actualizar tokens:

    • Dado que los tokens tienen una caducidad, genera uno nuevo desde el panel de Meta, actualiza la variable API_TOKEN en .env y reinicia el servidor.
  3. Optimizar para producción:

    • Aunque el Port Forwarding permite exponer el servidor para pruebas, evita usar esta configuración en producción.
    • Considera implementar una solución de hosting adecuada para el despliegue en producción con tokens de larga duración.

Aportes 46

Preguntas 6

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

💡 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: ```js 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. ```js data: { messaging\_product: "whatsapp", to: cleanPhoneNumber(message.from), … ``` De esta manera funciona correctamente. ![](https://static.platzi.com/media/user_upload/image-529deafe-1c48-4f4b-a498-c0cd212b8ed5.jpg)
Creo que no lo especifica pero para quienes ocupen la pagina donde esta el "Set up and Configure Glitch" es la siguiente url: <https://developers.facebook.com/docs/whatsapp/sample-app-endpoints> Pequeño aporte ojala les sirva(:
Tuve un montón de errores, pero con ayuda de chatgpt saque la clase adelante, eso sí, me costó 2 horas.
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.-
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."
Alguien tuvo este error al momento de configurar el **webhook?** ![](https://static.platzi.com/media/user_upload/image-c7662fe3-931b-4022-9136-35ffdc61079d.jpg)
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(`\
Nothing to see here.Checkout README.md to start.\
`);}); app.listen(PORT, () => {  console.log(`Server is listening on port: ${PORT}`);});
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.
Importante para los que usan WSL, se puede usar **ngrok** a continuación dejo un paso a paso pero antes quiero explicar lo que yo entendí del problema. Desde WSL no podemos exponer directamente el puerto (para mi caso usé 4000), esto se hace desde Windows y la conexión entre WSL y Windows para exponer dicho puerto la facilitará **ngrok**: 1. Vayan a <https://ngrok.com/downloads/windows?tab=download> y descarguen el instalador de Windows, descompriman y corran el .exe. 2. Eso les abrirá la terminal en Windows. Deben configurar el authtoken de ngrok, para eso creense una cuenta en la página de ngrok y en el apartado "Your Authtoken" copien `ngrok config add-authtoken <AuthToken>` 3. Vayan a esa terminal ejecutenlo y luego ejecuten `ngrok http <puerto_WSL>` (que para mi caso fue 4000) de esa forma les entregará la url desde la que se puede acceder, antes de pegarla en meta recuerden agregar /webhook a la URL y listo!
Hola una buena opción para exponer nuestro local host es <https://ngrok.com/>. Me parece mejor debido a que conserva la misma url y no hay que estarla modificando.
## ✨🦄 Realicé la interacción entre diferentes elementos de wpp: ![](https://static.platzi.com/media/user_upload/image-2c16e7aa-951e-4bae-b60c-7f878d69caf3.jpg) Con este código, solo cambia la data que se envía en la respuesta: ```js 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); }); ```
Respecto al archivo nodemon.js tambien pueden simplemete guardarlo como nodemon.json y listo.
para poder entender la estructura de arquitectura que utilizas que curso debo estudiar primero ?? es que no se que estructura de proyecto utilizas .. muchas gracias
Para obtener un token permanente de la API de WhatsApp Business, debes seguir estos pasos: 1. **Generar un token de acceso** a través del panel de desarrolladores de Meta. Este token suele tener una duración limitada. 2. **Usar el flujo de OAuth** para implementar un sistema de autenticación que pueda refrescar el token automáticamente. Esto implica que deberías tener un sistema que mantenga el acceso usando refresh tokens. 3. **Revisar la documentación de la API de WhatsApp** para entender cómo manejar tokens y su expiración de manera adecuada. Asegúrate de implementar estas prácticas de seguridad para proteger tus credenciales.
Lo visto en esta clase proporciona los fundamentos para implementar un webhook en un servidor Express, que es crucial para integrar la API de WhatsApp Business. La clase destaca cómo configurar la comunicación entre tu aplicación y la API de WhatsApp, permitiendo enviar y recibir mensajes. El proceso de validar el webhook y sincronizar los tokens es esencial para asegurar que tu bot funcione correctamente. Estos conceptos son vitales para aprovechar al máximo la API de WhatsApp y mejorar la interacción con los clientes.
Buenas tardes. Estoy ejecutando touch server.js pero tengo un mensaje de error ![](https://static.platzi.com/media/user_upload/upload-283cfc87-c363-4267-9e70-3b704b07c15f.png) tengo el dotenv integrado. Necesito ayuda
Esta fue mi solución! /\*\* \* 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 helmet from "helmet";import 'dotenv/config'; const app = express();app.use(helmet()); // Seguridad básicaapp.use(express.json()); // Variables de entornoconst { WEBHOOK\_VERIFY\_TOKEN, API\_TOKEN, BUSINESS\_PHONE, API\_VERSION, PORT } = process.env; // Verificación de variables de entornoif (!WEBHOOK\_VERIFY\_TOKEN || !API\_TOKEN || !BUSINESS\_PHONE || !API\_VERSION || !PORT) {    console.error("Faltan variables de entorno. Verifica tu archivo .env");    process.exit(1);} // Limpieza de númeroconst cleanPhoneNumber = (*number*) => {    return *number*.startsWith('521') ? *number*.replace("521", "52") : *number*;}; // Endpoint POST del Webhookapp.post("/webhook", async (*req*, *res*) => {    console.log("Mensaje entrante:", JSON.stringify(*req*.body, null, 2));     const message = *req*.body.entry?.\[0]?.changes\[0]?.value?.messages?.\[0];     if (message?.type === "text") {        try {            // Enviar respuesta "Echo"            await axios({                method: "POST",                url: `https://graph.facebook.com/${API\_VERSION}/${BUSINESS\_PHONE}/messages`,                headers: {                    Authorization: `Bearer ${API\_TOKEN}`,                },                data: {                    messaging\_product: "whatsapp",                    to: cleanPhoneNumber(message.from),                    text: { body: "Echo: " + message.text.body },                    context: {                        message\_id: message.id,                    },                },            });             // Marcar como leído            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 al manejar el mensaje:", error.message);            return *res*.sendStatus(500);        }    }     *res*.sendStatus(200);}); // Verificación del Webhookapp.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);    }}); // Ruta raízapp.get("/", (*req*, *res*) => {    *res*.send(`\
Nothing to see here.Checkout README.md to start.\
`);}); // Iniciar servidorapp.listen(PORT, () => {    console.log(`Servidor escuchando en el puerto: ${PORT}`);});
para los que les sale el error ![](https://static.platzi.com/media/user_upload/error%20face-de75fc7d-f87b-4df5-95cb-7eb285ab92c2.jpg)lo que tienen que hacer es editar el código ![]()![]()![]()```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; 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") { // 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, }, }); } 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(`
Nothing to see here.
Checkout README.md to start.
`); }); const port = PORT || 3000; app.listen(port, () => { console.log(`Server is listening on port: ${port}`); }); ```son unas pequeñas configuraciones al codigo en el documento "server.js". Seguido de eso se van al documento ".env" y lo configuran con el codigo que esta en el curso pero sin espacios, ejemplo: ```js WEBHOOK_VERIFY_TOKEN=Aqui1 API_TOKEN=aquitutoken BUSINESS_PHONE=codigo API_VERSION=version PORT=3000o4000 ```y ejecutan en la terminal preferentemento con CMD y hacen CTRL + C para parar el servidor, seguido de eso colocan `node server.js` o `npm start` , les saldra lo siguiente: ![](https://static.platzi.com/media/user_upload/image-1210da4b-f133-4940-85fe-e5357331d8d3.jpg) ahora se van a su puerto y vuelven a habilitarlo y funcionara, recuerden que en facebook debe ir el link de la siguiente forma: <https://hola.brs.devtunnels.ms/webhook> Espero les sirva
Un servidor de webhook puede funcionar para múltiples aplicaciones de API de WhatsApp, siempre que cada aplicación tenga su propia configuración de webhook y token de verificación. Sin embargo, se deben manejar correctamente las rutas y la lógica de procesamiento de mensajes para que el servidor distinga entre las diferentes solicitudes de las aplicaciones conectadas. Esto es esencial para mantener una comunicación fluida y evitar conflictos entre los diferentes flujos de trabajo en el mismo servidor.
Para resolver el error "No se ha podido validar la URL de devolución de llamada o el token de verificación", verifica lo siguiente: 1. **URL de Webhook**: Asegúrate de que la URL de webhook esté correctamente configurada y sea accesible desde Internet. Utiliza herramientas como Ngrok para exponer tu servidor local si es necesario. 2. **Token de Verificación**: Revisa que el token que estás utilizando en tu configuración coincida exactamente con el que configuraste en tu aplicación de Meta. 3. **Puerto y Configuración**: Verifica que tu servidor esté escuchando en el puerto correcto (3000 en tu caso) y que tu archivo `.env` contenga las variables necesarias. Si todos estos puntos están correctos y el error persiste, intenta reiniciar tu servidor y verificar los logs para más detalles.
a veces el puerto 3000 esta ocupado sin que nos demos cuenta, al iniciar "npm run start" si no aparece, cambien a otro (como puerto 4000) y listo. (me pasó eso)
![](https://static.platzi.com/media/user_upload/image-c6ba5af5-e0be-4dcd-9e72-a0e960fe7aa9.jpg)Frente a este error sólamente deben colocar webhook al final del link. Ej: <https://...ms/> --> <https://...ms/webhook>
Les dejo un aporte para aquellos que estan usando python. 1\. el codigo de `server.py `es este ```js import os from flask import Flask, request, jsonify import requests from dotenv import load_dotenv load_dotenv() 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", 3000)) 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") print(WEBHOOK_VERIFY_TOKEN) 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 "
Nothing to see here.\nCheckout README.md to start.
", 200 if __name__ == "__main__": app.run(host="0.0.0.0", port=PORT) ```2. El archivo .env tiene esta estructura (respeten los "") ```js WEBHOOK_VERIFY_TOKEN=test API_TOKEN="EAAGD.......asdasdq12321" PORT=3000 BUSINESS_PHONE=434055.....116495 API_VERSION=v21.0 ```3. Cuando hacen lo de publicar el puerto verifiquen que sea HTTP (pueden hacerlo HTTPS para que sea mas seguro pero para practicar esta mas que bien) y que sea publico Si les sirvio avisenme
Sí, la configuración de un webhook similar a la que se realiza en Node.js con Express también se puede implementar en Python. En Python, puedes utilizar frameworks como Flask o Django para crear un servidor que maneje las solicitudes de webhook. La lógica para recibir y procesar mensajes de WhatsApp es similar; deberías definir una ruta en tu aplicación que escuche las solicitudes entrantes de la API de WhatsApp y luego manejar la respuesta. Aquí hay un ejemplo básico usando Flask: ```python from flask import Flask, request app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): data = request.json # Procesa el mensaje recibido return 'Webhook received', 200 if __name__ == '__main__': app.run(port=3000) ``` Recuerda ajustar las configuraciones de tu webhook en la plataforma de WhatsApp Business para que apunte a la URL de tu servidor Python.
![](https://static.platzi.com/media/user_upload/image-8d34938b-c21f-4339-aca6-3eb4f2a86a91.jpg)Excelente clase profe, gracias.
Alguien me puede ayudar porfavor... Estoy atorado, no puedo avanzar, The callback URL or verify token couldn't be validated. Please verify the provided information or try again later. Tengo el mismo codigo que en el curso.
Tengo una pregunta, si edito los comentarios por la costumbre de siempre poner algo personal en cada codigo, no pasa nada? o es que no se puede por terminos y condiciones
En el minuto 1.41 el equivalente a Touch en CMD es "echo. > nombre\_del\_archivo.txt" por ende "echo. > server.js
recuerden habilitar las opciones del webhook desde la configuración, estuve mucho tiempo bregando con eso y solo era suscribirse a los canales XD
Tenemos alguna forma de que el token dure mas tiempo?.. Me está expirando cada 3 hs!
Para solucionar el problema de no recibir mensajes en tu bot de WhatsApp, asegúrate de revisar lo siguiente: 1. **Token de acceso**: Verifica que el token de acceso no haya expirado y que sea el correcto. Puedes regenerarlo en el panel de Meta y actualizarlo en tus variables de entorno. 2. **Webhook**: Asegúrate de que la URL de tu webhook esté configurada correctamente en Meta y que el token de verificación coincida. 3. **Logs de errores**: Revisa la consola de tu servidor para detectar errores. Un error común puede ser un 401, indicando problemas de autenticación. 4. **Configuración del servidor**: Verifica que tu servidor esté corriendo en el puerto correcto (por defecto 3000) y que esté accesible públicamente. Toma en cuenta estos puntos y vuelve a probar el bot.
El error que mencionas generalmente ocurre cuando el número de teléfono no está autorizado para interactuar con tu bot. Asegúrate de que el número esté verificado y en la lista de usuarios autorizados en la configuración de tu aplicación en Meta. También verifica que el número esté registrado correctamente y que no haya errores tipográficos en el API Token o en los parámetros de la solicitud. Si el mensaje de prueba funciona, revisa si el número desde el cual envías el mensaje en WhatsApp está correctamente añadido en tus contactos y habilitado para recibir mensajes.
Para identificar tu archivo como JSON en lugar de JavaScript, asegúrate de que el archivo tenga la extensión `.json`. Además, al abrirlo en tu editor de código, selecciona el tipo de archivo como JSON si no se detecta automáticamente. En Visual Studio Code, puedes hacer esto desde la esquina inferior derecha, donde se muestra el tipo de archivo actual. Asegúrate también de que el contenido del archivo siga la sintaxis correcta de JSON, con claves y valores entre comillas.
Hola. ya probe a cambiar el business\_phone con Identificador de número de teléfono: x x x x x x x x x x x x x x x x, ​Identificador de la cuenta de WhatsApp Business: xxxxxxxxxxxxxxx y el número que ellos asignaron, intente quitar el 1 pero no se si eso lo hice bien o no. PEro principalmente que numero debo escoger. Todo el tiempo me sale el error 400. Unsupported post request. Object with ID '5551727369' does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api",
Yo sigo con el mismo problema. ME da status 400. Ya trate de poner la función para cambiar el numero pero aun no funciona.
Cuando dices "validamos que todo este funcional" ¿Eso como lo haces, lo de validar?
En mi caso hice la modificación del mensaje de respuesta ```js 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}. I will repeat all that you say, like a parrot 🦜` }, 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: { messaging\_product: "whatsapp", to: message.from, text: { body: `🤖 Echo: ${message.text.body}. I will repeat all that you say, like a parrot 🦜` }, context: { message\_id: message.id, // shows the message as a reply to the original user message }, }, }); Aqui dejo mi repositorio: <https://github.com/zearkiatos/medpet-chatbot-service>
Si alguien está usando WSL2 desde Windows, pueden usar ngrok, así pude crear mi webhook. Saludos
Hola, excelente clase. Desde el panel registré un número y pude enviar la petición de prueba. En el servidor me da este error: ```js data: { error: { message: '(#131030) Recipient phone number not in allowed list', type: 'OAuthException', code: 131030, error_data: { messaging_product: 'whatsapp', details: 'Número de teléfono del destinatario no incluido en la lista de autorizados: Añade el número de teléfono del destinatario a la lista de destinatarios y vuelve a intentarlo.' }, fbtrace_id: 'AFArHf4Wau8eTFCUr5Z3no_' } } }, status: 400 ```Me dice que el número no está registrado, pero el número ya está registrado e incluso recibo el mensaje de prueba. Ojalá me puedan ayudar con algún recurso donde se encuentre información al respecto. Gracias!!!!
Hola que tal. Tengo una pregunta: Qué cursos debería hacer antes que este? Hay alguna ruta que me puedan recomendar? no soy programador pero sé interpretar código y tengo conocimientos en lógica de programación. Muchas gracias!
Tengo este error al correr npm start: npm start \> [email protected] start \> node server.js Loaded environment variables: BUSINESS\_PHONE: undefined Server is listening on port: 3000 BUSINESS\_PHONE: undefined...siendo que en .env esta configurado obtenido tal cual lo indica el profesor. Que puede ser? A su vez no estoy pudiendo recibir respuesta del bot.
También pueden usar ngrok para generar una url que conecte con su localhost si no pueden (o no quieren) hacerlo con Vscode.
![](https://static.platzi.com/media/user_upload/image-bef34cc7-179b-4d59-8533-07087fdb9e24.jpg) ```js import express from "express"; import https from "https"; 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; // Función para realizar solicitudes HTTPS const sendHttpsRequest = (options, data) => new Promise((resolve, reject) => { const req = https.request(options, (res) => { let responseBody = ""; res.on("data", (chunk) => { responseBody += chunk; }); res.on("end", () => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve(JSON.parse(responseBody)); } else { reject(new Error(`HTTP Error: ${res.statusCode}, ${responseBody}`)); } }); }); req.on("error", (error) => { reject(error); }); if (data) { req.write(JSON.stringify(data)); } req.end(); }); const sendReply = async (to, type, content) => { const optionsReply = { hostname: "graph.facebook.com", path: `/${API_VERSION}/${BUSINESS_PHONE}/messages`, method: "POST", headers: { Authorization: `Bearer ${API_TOKEN}`, "Content-Type": "application/json", }, }; const data = { messaging_product: "whatsapp", to, type, ...content, }; await sendHttpsRequest(optionsReply, data); }; 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") { const messageValidate = message.text.body.toLowerCase(); const recipient = message.from; try { if (messageValidate.includes("img")) { await sendReply(recipient, "image", { image: { link: "https://generative-ai-ultisaer.s3.sa-east-1.amazonaws.com/images/breaking_free_from_chains_converted.jpg", caption: "Cosmic Void Darkness", }, }); } else if (messageValidate.includes("text")) { await sendReply(recipient, "text", { text: { body: "Hola, este es un mensaje de texto simple." }, }); } else if (messageValidate.includes("pdf")) { await sendReply(recipient, "document", { document: { link: "https://portfolio-ulternae.s3.sa-east-1.amazonaws.com/CV_Jhonatan_David_Castillo_Castillo_Frontend_Developer_es.pdf", caption: "Este es un documento PDF.", }, }); } else if (messageValidate.includes("audio")) { await sendReply(recipient, "audio", { audio: { link: "https://example.com/audio.mp3" }, }); } else if (messageValidate.includes("video")) { await sendReply(recipient, "video", { video: { link: "https://example.com/video.mp4", caption: "Este es un video de demostración.", }, }); } else if (messageValidate.includes("button")) { await sendReply(recipient, "interactive", { interactive: { type: "button", body: { text: "¿Te interesa continuar?", }, action: { buttons: [ { type: "reply", reply: { id: "yes", title: "Sí" } }, { type: "reply", reply: { id: "no", title: "No" } }, ], }, }, }); } else if (messageValidate.includes("template")) { await sendReply(recipient, "template", { template: { name: "order_confirmation", language: { code: "en_US" }, components: [ { type: "body", parameters: [ { type: "text", text: "Pedro" }, { type: "text", text: "Pedido #1234" }, ], }, ], }, }); } // Marcar el mensaje como leído await sendReply(recipient, "text", { status: "read", message_id: message.id, }); console.log("Response sent and message marked as read."); } catch (error) { console.error("Error processing message:", error.message); } } res.sendStatus(200); }); // Webhook verification 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) { res.status(200).send(challenge); console.log("Webhook verified successfully!"); } else { res.sendStatus(403); } }); app.get("/", (req, res) => { res.send("
Nothing to see here. Check README.md to start.
"); }); app.listen(PORT, () => { console.log(`Server is listening on port: ${PORT}`); }); ```Algunos metodos funcionan como img text pdf button, otros como audio o video solo debes cambiar la url por una compatible con whatsapp
aporte: si no les da y usan WSL haganlo por ngrok, fue sencillo y me funciono a la final
yo tuve que deployar porque la url no me toma ni ngrok igual no puedo leer el webhook