Pon un agente de OpenAI Agents SDK en WhatsApp
Configura el destino del webhook del número en una ruta de tu app Python. Por cada mensaje entrante, ejecuta el agente con Runner.run y una sesión identificada por el número del remitente, y envía result.final_output de vuelta por la Cloud API con el token del número y el phone number id. La app de WhatsApp Business sigue funcionando en el mismo número.
La sesión integrada del SDK, respaldada en archivo o en memoria, que recuerda los turnos anteriores bajo un id de sesión.
MCPServerStreamableHttp acepta aquí un httpx.Auth, o un encabezado Authorization, para autenticar el servidor.
La versión de la Graph API que usan los ejemplos actuales de Meta para enviar mensajes.
¿Cómo se convierte un mensaje de WhatsApp en una ejecución del agente?
A través de una ruta de tu propia aplicación a la que llama Meta. Configura el destino del webhook del número con ella, con un secreto largo y aleatorio en la ruta. La ruta responde a la verificación GET de Meta devolviendo hub.challenge como texto plano, acepta cada POST, responde 200 de inmediato y encola el trabajo, porque Meta reintenta las respuestas lentas y ejecutarías el agente dos veces.
Un worker lee entonces el remitente y el texto del payload y llama a Runner.run. Pasa una sesión cuyo id sea el número del remitente: el SDK guarda la conversación bajo ese id, así que el siguiente mensaje del mismo cliente continúa donde terminó el anterior, y dos clientes nunca comparten historial. SQLiteSession basta para empezar; el SDK también incluye sesiones de Redis y SQLAlchemy para varios workers.
El secreto en la URL es aquí la autenticación. Meta firma las entregas con el app secret del Tech Provider, así que el cliente no puede validar el encabezado de firma.
import os, httpx
from agents import Agent, Runner, SQLiteSession
agent = Agent(name="Front desk", instructions="Answer briefly and politely.")
URL = f"https://graph.facebook.com/v25.0/{os.environ['PHONE_NUMBER_ID']}/messages"
async def handle(sender: str, text: str) -> None:
session = SQLiteSession(sender, "whatsapp.db")
result = await Runner.run(agent, text, session=session)
async with httpx.AsyncClient() as http:
await http.post(
URL,
headers={"Authorization": f"Bearer {os.environ['WA_TOKEN']}"},
json={"messaging_product": "whatsapp", "to": sender,
"type": "text", "text": {"body": result.final_output}},
)¿Por qué debe enviar la respuesta tu código y no el agente?
Porque la única regla que nunca debe romperse es de tiempo, y el código la hace cumplir mejor que un prompt. Meta abre una ventana de atención al cliente de 24 horas cuando un cliente escribe. Dentro de ella, el texto libre se entrega. Fuera, solo pasa una plantilla aprobada, y el texto libre devuelve el error 131047.
Un worker que responde al mensaje que acaba de llegar siempre está dentro de la ventana, así que enviar result.final_output como texto es seguro por construcción. El trabajo que ocurre más tarde, un seguimiento a la mañana siguiente o un recordatorio, debe pasar por una ruta aparte que envíe una plantilla y nunca texto libre.
El agente aún puede tener herramientas. Dale herramientas de función para consultar datos, como un pedido o una reserva, y deja el envío por WhatsApp en el worker. Así el token de acceso queda fuera de cualquier cosa que el modelo pueda llamar con argumentos arbitrarios.
¿Puede el agente usar el servidor MCP de EasyCoexistence?
Puede, mediante MCPServerStreamableHttp, con más configuración que un encabezado. El SDK acepta un encabezado Authorization o un httpx.Auth en params["auth"]. El servidor MCP de EasyCoexistence emite sus propios tokens OAuth tras un inicio de sesión en el navegador, con registro dinámico de clientes y PKCE, así que no existe una clave estática. El SDK de Python de MCP incluye OAuthClientProvider, un manejador de autenticación HTTP que ejecuta ese flujo con PKCE y renovación de tokens, y eso es lo que va en params["auth"].
Vale la pena cuando el agente debe decidir por sí mismo: comprobar el estado de un número, leer el estado de una plantilla o elegir entre send_message y send_template con las reglas de las descripciones de las herramientas. Para una recepción que solo responde, el worker de arriba es más corto y tiene menos que pueda fallar.
De cualquier modo, el webhook se queda. MCP es petición y respuesta, y el mensaje de un cliente solo puede llegar al agente por la ruta a la que llama Meta.
Errores comunes
- Ejecutar el agente antes de devolver 200 a Meta. Una respuesta lenta se reintenta y el cliente recibe dos respuestas.
- Usar una sola sesión para todos los clientes. Identifícala por el número del remitente, o los historiales se mezclan.
- Dejar que un seguimiento retrasado envíe texto libre. Pasadas 24 horas falla con 131047; envía una plantilla.
Conecta el número en easycoexistence.com, configura el destino del webhook en tu ruta y lee el token y el phone number id en el panel. Desde US$ 9 por número conectado al mes, hasta US$ 1 según se añaden números, con los primeros 3 días gratis.
Preguntas frecuentes
¿Esto necesita la herramienta MCP alojada de la Responses API de OpenAI?
No. El worker ejecuta el agente en local con Runner.run, y el lado de WhatsApp es una llamada HTTPS simple que hace tu código.
¿Qué versión de la Graph API debo usar?
Los ejemplos actuales de Meta usan v25.0. Fija la versión en un solo lugar de tu código para que actualizarla sea un cambio de una línea.
¿Puede una persona tomar el control desde el teléfono?
Sí. Coexistencia mantiene funcionando la app de WhatsApp Business, y una respuesta desde el teléfono llega a tu ruta como un evento echo que el worker puede usar para pausar el agente.
¿EasyCoexistence guarda la conversación?
No. Meta entrega directamente a tu ruta. Lo que guarde la sesión vive en tu propia base de datos.
Sigue leyendo
¿Listo para empezar?
Configura WhatsApp Coexistence en minutos, no en meses. La app sigue funcionando en el teléfono.
Empezar prueba gratisVerificado el