>_ Black Engine

Crear bot de WhatsApp con Python y la API oficial (código)

Por Black Engine · 6 de noviembre de 2026

Para crear un bot de WhatsApp con Python de forma oficial necesitas tres piezas: una app en Meta for Developers con el producto WhatsApp, un pequeño servidor en Python (aquí con Flask) que reciba los mensajes por webhook, y llamadas a la API de WhatsApp Cloud para responder. Abajo está el código completo, listo para adaptar.

Un webhook es una dirección de tu servidor a la que Meta le avisa, con una petición HTTP, cada vez que pasa algo (como un mensaje nuevo).

1. Prepara la app en Meta

  1. En developers.facebook.com crea una app de negocio y agrega WhatsApp.
  2. En WhatsApp → API Setup copia el Phone number ID y el token de acceso (el temporal sirve para probar).
  3. Registra tu celular como destinatario de prueba.

Guía oficial: Get started with the Cloud API.

2. Instala lo necesario

python3 -m venv .venv
source .venv/bin/activate
pip install flask requests python-dotenv

Crea un archivo .env (y agrégalo a .gitignore; aquí explicamos qué es un archivo .env):

WHATSAPP_TOKEN=tu_token
PHONE_NUMBER_ID=tu_phone_number_id
VERIFY_TOKEN=una_frase_secreta_que_tu_inventas
GRAPH_VERSION=v21.0

GRAPH_VERSION es la versión de la API de Meta. Usa la que aparezca en tu panel o en la documentación; Meta publica versiones nuevas varias veces al año.

3. El código del bot

# bot.py
import os
import requests
from flask import Flask, request
from dotenv import load_dotenv

load_dotenv()
app = Flask(__name__)

TOKEN = os.environ["WHATSAPP_TOKEN"]
PHONE_ID = os.environ["PHONE_NUMBER_ID"]
VERIFY = os.environ["VERIFY_TOKEN"]
API = f"https://graph.facebook.com/{os.environ['GRAPH_VERSION']}/{PHONE_ID}/messages"


def enviar_texto(numero, texto):
    r = requests.post(
        API,
        headers={"Authorization": f"Bearer {TOKEN}"},
        json={
            "messaging_product": "whatsapp",
            "to": numero,
            "type": "text",
            "text": {"body": texto},
        },
        timeout=15,
    )
    r.raise_for_status()


def responder(texto):
    t = texto.lower().strip()
    if "horario" in t:
        return "Abrimos de lunes a sábado de 9 a 18 h."
    if "ubicacion" in t or "ubicación" in t:
        return "Estamos en Av. Ejemplo 123, Monterrey."
    return "Hola, escribe *horario* o *ubicación*, o *asesor* para hablar con una persona."


@app.get("/webhook")
def verificar():
    # Meta llama aquí una vez para confirmar que el webhook es tuyo
    if request.args.get("hub.verify_token") == VERIFY:
        return request.args.get("hub.challenge", ""), 200
    return "Token inválido", 403


@app.post("/webhook")
def recibir():
    data = request.get_json(silent=True) or {}
    for entry in data.get("entry", []):
        for change in entry.get("changes", []):
            for msg in change.get("value", {}).get("messages", []):
                if msg.get("type") == "text":
                    enviar_texto(msg["from"], responder(msg["text"]["body"]))
    # Responde 200 rápido o Meta reintenta el envío
    return "ok", 200


if __name__ == "__main__":
    app.run(port=5000)

4. Conecta el webhook

  1. Corre el bot: python bot.py.
  2. Para probar en tu computadora, expón el puerto con un túnel HTTPS (por ejemplo, ngrok http 5000 o cloudflared tunnel --url http://localhost:5000).
  3. En Meta, WhatsApp → Configuration → Webhook: pon https://TU-URL/webhook y tu VERIFY_TOKEN. Pulsa Verificar y guardar.
  4. Suscríbete al campo messages.
  5. Escríbele al número de prueba desde tu celular. Debe contestar.

5. Agregar IA (ChatGPT, Claude o Gemini)

Cambia la función responder por una llamada al modelo. Ejemplo con la librería oficial de Anthropic (pip install anthropic):

import anthropic

claude = anthropic.Anthropic()  # lee ANTHROPIC_API_KEY del entorno

INSTRUCCIONES = """Eres el asistente de un taller mecánico en Monterrey.
Solo hablas de servicios, horarios (lun-sáb 9-18 h) y citas.
Si no sabes un precio, di que un asesor lo confirma. No inventes datos."""

def responder(texto):
    r = claude.messages.create(
        model="claude-sonnet-5-5",  # revisa el nombre del modelo vigente en docs.anthropic.com
        max_tokens=400,
        system=INSTRUCCIONES,
        messages=[{"role": "user", "content": texto}],
    )
    return r.content[0].text

Para que recuerde la conversación, guarda los últimos mensajes de cada número (en una base de datos o Redis) y mándalos en messages. Con OpenAI o Gemini el patrón es el mismo con su SDK.

Botones, imágenes y audios

El ejemplo solo atiende mensajes de texto, pero los clientes mandan de todo. Cada mensaje trae un campo type que te dice qué es: text, image, audio, document, location, interactive (cuando tocan un botón) y otros. Lo mínimo es contestar algo útil cuando no lo entiendes, en vez de quedarte callado:

if msg.get("type") != "text":
    enviar_texto(msg["from"], "Por ahora solo leo texto. Escribe *asesor* y te atiende una persona.")

Para menús, los botones de respuesta son más claros que pedir que escriban una palabra exacta: mandas un mensaje de tipo interactive con hasta tres botones, y cuando el cliente toca uno te llega el id del botón, sin errores de ortografía de por medio:

def enviar_botones(numero):
    requests.post(API, headers={"Authorization": f"Bearer {TOKEN}"}, timeout=15, json={
        "messaging_product": "whatsapp", "to": numero, "type": "interactive",
        "interactive": {"type": "button", "body": {"text": "¿En qué te ayudamos?"},
            "action": {"buttons": [
                {"type": "reply", "reply": {"id": "horario", "title": "Horario"}},
                {"type": "reply", "reply": {"id": "cita", "title": "Agendar cita"}},
                {"type": "reply", "reply": {"id": "asesor", "title": "Hablar con asesor"}},
            ]}}})

La respuesta llega en msg["interactive"]["button_reply"]["id"]. Los límites de botones y de largo del texto están en la referencia de mensajes interactivos.

Para imágenes y audios, el mensaje trae un id de medio que descargas con otra llamada a la API. Así puedes, por ejemplo, transcribir notas de voz con un modelo de voz antes de pasarlas al bot.

Pasar la conversación a una persona

Ningún bot resuelve todo, y nada molesta más que un bot que no deja hablar con alguien. Define desde el principio:

  1. Cuándo se pasa: la palabra “asesor”, un botón, o cuando el bot no entiende dos veces seguidas.
  2. Cómo se marca: guarda en tu base de datos que ese número está “con humano” y, mientras lo esté, el bot no contesta.
  3. Dónde lo atiende la persona: la Cloud API no muestra los chats en el celular como la app de WhatsApp Business. Necesitas un panel propio, una herramienta de bandeja compartida o, como mínimo, que el bot te reenvíe el mensaje a otro canal (correo, Telegram, Slack).
  4. Cuándo vuelve el bot: tras cierto tiempo sin mensajes o cuando la persona lo cierra.

Antes de conectar tu número real, revisa en la documentación de Meta cómo afecta a la app de WhatsApp que ya usas en ese número: las opciones para usar la app y la API al mismo tiempo dependen del tipo de cuenta y han cambiado con el tiempo. Si no quieres arriesgar tu número principal, empieza con uno nuevo.

6. Llevarlo a producción

  • Servidor siempre encendido con HTTPS: un servidor virtual o una plataforma como Render, Railway o Fly.io. Usa gunicorn bot:app en lugar del servidor de desarrollo de Flask.
  • Token permanente con un usuario del sistema de Meta Business.
  • Valida la firma X-Hub-Signature-256 con tu App Secret para confirmar que la petición viene de Meta.
  • Procesa en segundo plano si la IA tarda: responde 200 a Meta de inmediato y manda la respuesta después; si no, Meta reintenta y tu bot contesta dos veces.
  • Ventana de 24 horas: fuera de ella solo puedes mandar plantillas aprobadas. Los precios por mensaje están en la página oficial de Meta.

Errores comunes

  • La verificación falla: el VERIFY_TOKEN no coincide o tu URL no es HTTPS pública.
  • Error 401: token caducado o mal copiado.
  • Error ”(#131030) Recipient phone number not in allowed list”: con el número de prueba solo puedes escribir a destinatarios registrados.
  • Mensajes duplicados: tardaste en responder 200 y Meta reintentó. Guarda el id de cada mensaje procesado.
  • Usar pywhatkit, Selenium o librerías que simulan WhatsApp Web en un número de negocio: riesgo de bloqueo.

Para cerrar

Con este código tienes la base de un bot oficial en Python. Si prefieres no programar, el mismo resultado se arma en n8n, y en crear bot de WhatsApp con la API explicamos plantillas, números y verificación del negocio. Si quieres automatizar más cosas con este lenguaje, mira automatizar procesos con Python. En Black Engine construimos y alojamos bots de WhatsApp en Python; escríbenos por WhatsApp.

Preguntas frecuentes

¿Qué librería de Python uso para un bot de WhatsApp?

No necesitas una librería especial: con Flask (o FastAPI) para recibir el webhook y requests para llamar a la API de WhatsApp Cloud basta. Es la vía oficial.

¿Puedo usar pywhatkit o Selenium para el bot?

Funcionan automatizando WhatsApp Web, pero no son oficiales, se rompen seguido y pueden hacer que bloqueen tu número. Para un negocio, usa la API oficial.

¿Dónde subo mi bot de Python?

En cualquier servidor con HTTPS público que esté siempre encendido: un servidor virtual, Render, Railway, Fly.io o similar. Meta debe poder llamar a tu webhook.

¿Cómo le agrego ChatGPT o Claude?

Antes de responder, mandas el texto del cliente a la API del modelo junto con instrucciones de tu negocio, y envías por WhatsApp lo que conteste.

Pide ayuda por WhatsApp